Something went wrong on our end
-
Bruno Muniz authoredBruno Muniz authored
SearchRightViewModel.swift 3.40 KiB
import Shared
import Combine
import XXModels
import Foundation
import Permissions
import Integration
import DependencyInjection
enum ScanningStatus: Equatable {
case reading
case processing
case success
case failed(ScanningError)
}
enum ScanningError: Equatable {
case requestOpened
case unknown(String)
case cameraPermission
case alreadyFriends(String)
}
final class SearchRightViewModel {
@Dependency var session: SessionType
@Dependency var permissions: PermissionHandling
var foundPublisher: AnyPublisher<Contact, Never> {
foundSubject.eraseToAnyPublisher()
}
var cameraSemaphorePublisher: AnyPublisher<Bool, Never> {
cameraSemaphoreSubject.eraseToAnyPublisher()
}
var statusPublisher: AnyPublisher<ScanningStatus, Never> {
statusSubject.eraseToAnyPublisher()
}
private let foundSubject = PassthroughSubject<Contact, Never>()
private let cameraSemaphoreSubject = PassthroughSubject<Bool, Never>()
private(set) var statusSubject = CurrentValueSubject<ScanningStatus, Never>(.reading)
func viewWillAppear() {
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 userId = session.getId(from: data),
let username = try? session.extract(fact: .username, from: data) else {
let errorTitle = Localized.Scan.Error.invalid
statusSubject.send(.failed(.unknown(errorTitle)))
return
}
/// Make sure we are not processing a contact
/// that we already have
///
if let alreadyContact = try? session.dbManager.fetchContacts(.init(id: [userId])).first {
/// 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(
id: userId,
marshaled: data,
username: username,
email: try? session.extract(fact: .email, from: data),
phone: try? session.extract(fact: .phone, from: data),
nickname: nil,
photo: nil,
authStatus: .stranger,
isRecent: false,
createdAt: Date()
))
}
}