Newer
Older
import Shared
import Combine
import XXModels
import Defaults
import Permissions
import DependencyInjection
case reading
case processing
case success
case requestOpened
case unknown(String)
case cameraPermission
case alreadyFriends(String)
}
final class SearchRightViewModel {
@Dependency var permissions: PermissionHandling
@Dependency var reportingStatus: ReportingStatus
var foundPublisher: AnyPublisher<XXModels.Contact, Never> {
foundSubject.eraseToAnyPublisher()
}
var cameraSemaphorePublisher: AnyPublisher<Bool, Never> {
cameraSemaphoreSubject.eraseToAnyPublisher()
}
var statusPublisher: AnyPublisher<ScanningStatus, Never> {
statusSubject.eraseToAnyPublisher()
}
private let foundSubject = PassthroughSubject<XXModels.Contact, Never>()
private let cameraSemaphoreSubject = PassthroughSubject<Bool, Never>()
private(set) var statusSubject = CurrentValueSubject<ScanningStatus, Never>(.reading)
permissions.requestCamera { [weak self] granted in
guard let self = self else { return }
if granted {
self.statusSubject.value = .reading
self.cameraSemaphoreSubject.send(true)
} else {
self.statusSubject.send(.failed(.cameraPermission))
}
}
}
func viewWillDisappear() {
cameraSemaphoreSubject.send(false)
}
func didScan(data: Data) {
/// We need to be accepting new readings in order
/// to process what just got scanned.
///
guard statusSubject.value == .reading else { return }
statusSubject.send(.processing)
/// Whatever got scanned, needs to have id and username
/// otherwise is just noise or an unknown qr code
///
guard
let uid = try? user.getId(),
let facts = try? user.getFacts(),
let username = facts.first(where: { $0.type == .username })?.value
let errorTitle = Localized.Scan.Error.invalid
statusSubject.send(.failed(.unknown(errorTitle)))
return
}
let email = facts.first { $0.type == .email }?.value
let phone = facts.first { $0.type == .phone }?.value
/// Make sure we are not processing a contact
/// that we already have
///
if let alreadyContact = try? database.fetchContacts(.init(id: [uid])).first {
if alreadyContact.isBlocked, reportingStatus.isEnabled() {

Bruno Muniz
committed
statusSubject.send(.failed(.unknown("You previously blocked this user.")))
return
}
if alreadyContact.isBanned, reportingStatus.isEnabled() {

Bruno Muniz
committed
statusSubject.send(.failed(.unknown("This user was banned.")))
return
}
/// Show error accordingly to the auth status
///
if alreadyContact.authStatus == .friend {
statusSubject.send(.failed(.alreadyFriends(username)))
} else if [.requested, .verified].contains(alreadyContact.authStatus) {
statusSubject.send(.failed(.requestOpened))
} else {
let generalErrorTitle = Localized.Scan.Error.general
statusSubject.send(.failed(.unknown(generalErrorTitle)))
}
return
}
statusSubject.send(.success)
cameraSemaphoreSubject.send(false)
foundSubject.send(.init(
nickname: nil,
photo: nil,
authStatus: .stranger,
isRecent: false,
createdAt: Date()
))
}
}