Newer
Older
import Shared
import Combine
import XXModels
import Foundation
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 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)
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))
}
}
}
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
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()
))
}
}