From ec2230198a1cce4e9bcfb528570c28c9ab66cc2d Mon Sep 17 00:00:00 2001 From: Bruno Muniz Azevedo Filho <bruno@elixxir.io> Date: Sat, 27 Aug 2022 04:39:26 -0300 Subject: [PATCH] Continued migration --- .../Resources/GoogleService-Info.plist | 64 +-- App/client-ios/Resources/Info.plist | 2 +- Package.swift | 1 + .../ViewModels/GroupChatViewModel.swift | 20 +- .../ViewModels/SingleChatViewModel.swift | 25 +- .../ChatInputFeature/ChatInputReducer.swift | 1 + .../ViewModel/ChatListViewModel.swift | 11 +- .../ViewModels/ContactViewModel.swift | 28 +- .../ViewModels/ContactListViewModel.swift | 7 +- .../ViewModels/CreateGroupViewModel.swift | 19 +- Sources/LaunchFeature/LaunchController.swift | 2 +- Sources/LaunchFeature/LaunchViewModel.swift | 512 +++++++++--------- ...OnboardingEmailConfirmationViewModel.swift | 5 +- .../ViewModels/OnboardingEmailViewModel.swift | 5 +- ...OnboardingPhoneConfirmationViewModel.swift | 5 +- .../ViewModels/OnboardingPhoneViewModel.swift | 8 +- .../OnboardingUsernameViewModel.swift | 274 +--------- .../ViewModels/ProfileCodeViewModel.swift | 8 +- .../ViewModels/ProfileEmailViewModel.swift | 8 +- .../ViewModels/ProfilePhoneViewModel.swift | 8 +- .../ViewModels/ProfileViewModel.swift | 7 +- .../ViewModels/RequestsFailedViewModel.swift | 10 +- .../RequestsReceivedViewModel.swift | 28 +- .../ViewModels/RequestsSentViewModel.swift | 10 +- .../ViewModels/RestoreViewModel.swift | 4 +- .../ViewModels/ScanDisplayViewModel.swift | 7 +- .../ViewModels/ScanViewModel.swift | 10 +- .../ViewModels/SearchLeftViewModel.swift | 82 +-- .../ViewModels/SearchRightViewModel.swift | 10 +- .../xcshareddata/swiftpm/Package.resolved | 14 +- 30 files changed, 491 insertions(+), 704 deletions(-) diff --git a/App/client-ios/Resources/GoogleService-Info.plist b/App/client-ios/Resources/GoogleService-Info.plist index 03e09469..676030ed 100644 --- a/App/client-ios/Resources/GoogleService-Info.plist +++ b/App/client-ios/Resources/GoogleService-Info.plist @@ -1,36 +1,36 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> -<dict> - <key>CLIENT_ID</key> - <string></string> - <key>REVERSED_CLIENT_ID</key> - <string></string> - <key>ANDROID_CLIENT_ID</key> - <string></string> - <key>API_KEY</key> - <string></string> - <key>GCM_SENDER_ID</key> - <string></string> - <key>PLIST_VERSION</key> - <string></string> - <key>BUNDLE_ID</key> - <string></string> - <key>PROJECT_ID</key> - <string></string> - <key>STORAGE_BUCKET</key> - <string></string> - <key>IS_ADS_ENABLED</key> - <false/> - <key>IS_ANALYTICS_ENABLED</key> - <false/> - <key>IS_APPINVITE_ENABLED</key> - <false/> - <key>IS_GCM_ENABLED</key> - <false/> - <key>IS_SIGNIN_ENABLED</key> - <false/> - <key>GOOGLE_APP_ID</key> - <string></string> -</dict> + <dict> + <key>CLIENT_ID</key> + <string>662236151640-herpu89qikpfs9m4kvbi9bs5fpdji5de.apps.googleusercontent.com</string> + <key>REVERSED_CLIENT_ID</key> + <string>com.googleusercontent.apps.662236151640-herpu89qikpfs9m4kvbi9bs5fpdji5de</string> + <key>ANDROID_CLIENT_ID</key> + <string>662236151640-2ughgo2dvc59dm4o39b45lbdungp2mct.apps.googleusercontent.com</string> + <key>API_KEY</key> + <string>AIzaSyCbI2yQ7pbuVSRvraqanjGcS9CDrjD7lNU</string> + <key>GCM_SENDER_ID</key> + <string>662236151640</string> + <key>PLIST_VERSION</key> + <string>1</string> + <key>BUNDLE_ID</key> + <string>io.xxlabs.messenger</string> + <key>PROJECT_ID</key> + <string>xx-messenger-6e03e</string> + <key>STORAGE_BUCKET</key> + <string>xx-messenger-6e03e.appspot.com</string> + <key>IS_ADS_ENABLED</key> + <false></false> + <key>IS_ANALYTICS_ENABLED</key> + <false></false> + <key>IS_APPINVITE_ENABLED</key> + <true></true> + <key>IS_GCM_ENABLED</key> + <true></true> + <key>IS_SIGNIN_ENABLED</key> + <true></true> + <key>GOOGLE_APP_ID</key> + <string>1:662236151640:ios:24badb58ab07515d8cef2d</string> + </dict> </plist> diff --git a/App/client-ios/Resources/Info.plist b/App/client-ios/Resources/Info.plist index d8cb845b..ee4d813d 100644 --- a/App/client-ios/Resources/Info.plist +++ b/App/client-ios/Resources/Info.plist @@ -105,6 +105,6 @@ <key>UIViewControllerBasedStatusBarAppearance</key> <true/> <key>isReportingOptional</key> - <false/> + <true/> </dict> </plist> diff --git a/Package.swift b/Package.swift index c4e214a9..dfcf799c 100644 --- a/Package.swift +++ b/Package.swift @@ -499,6 +499,7 @@ let package = Package( .target(name: "ReportingFeature"), .target(name: "DependencyInjection"), .product(name: "XXClient", package: "elixxir-dapps-sdk-swift"), + .product(name: "XXMessengerClient", package: "elixxir-dapps-sdk-swift"), .product(name: "CombineSchedulers", package: "combine-schedulers"), .product(name: "XXLegacyDatabaseMigrator", package: "client-ios-db"), ], diff --git a/Sources/ChatFeature/ViewModels/GroupChatViewModel.swift b/Sources/ChatFeature/ViewModels/GroupChatViewModel.swift index 4e27cad3..4412378c 100644 --- a/Sources/ChatFeature/ViewModels/GroupChatViewModel.swift +++ b/Sources/ChatFeature/ViewModels/GroupChatViewModel.swift @@ -10,6 +10,7 @@ import ToastFeature import DifferenceKit import ReportingFeature import DependencyInjection +import XXMessengerClient import struct XXModels.Message import XXClient @@ -20,25 +21,24 @@ enum GroupChatNavigationRoutes: Equatable { } final class GroupChatViewModel { - @Dependency var cMix: CMix @Dependency var database: Database @Dependency var sendReport: SendReport @Dependency var groupManager: GroupChat - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger @Dependency var reportingStatus: ReportingStatus @Dependency var toastController: ToastController @KeyObject(.username, defaultValue: nil) var username: String? var myId: Data { - try! GetIdFromContact.live(userDiscovery.getContact()) + try! messenger.ud.get()!.getContact().getId() } var hudPublisher: AnyPublisher<HUDStatus, Never> { hudSubject.eraseToAnyPublisher() } - var reportPopupPublisher: AnyPublisher<Contact, Never> { + var reportPopupPublisher: AnyPublisher<XXModels.Contact, Never> { reportPopupSubject.eraseToAnyPublisher() } @@ -54,7 +54,7 @@ final class GroupChatViewModel { private var stagedReply: Reply? private var cancellables = Set<AnyCancellable>() private let hudSubject = CurrentValueSubject<HUDStatus, Never>(.none) - private let reportPopupSubject = PassthroughSubject<Contact, Never>() + private let reportPopupSubject = PassthroughSubject<XXModels.Contact, Never>() private let replySubject = PassthroughSubject<(String, String), Never>() private let routesSubject = PassthroughSubject<GroupChatNavigationRoutes, Never>() @@ -121,7 +121,7 @@ final class GroupChatViewModel { ).asData() ) - try cMix.waitForRoundResult( + try messenger.cMix.get()!.waitForRoundResult( roundList: try report.encode(), timeoutMS: 5_000, callback: .init(handle: { @@ -174,7 +174,7 @@ final class GroupChatViewModel { ).asData() ) - try cMix.waitForRoundResult( + try messenger.cMix.get()!.waitForRoundResult( roundList: try report.encode(), timeoutMS: 5_000, callback: .init(handle: { @@ -246,7 +246,7 @@ final class GroupChatViewModel { replySubject.send(getReplyContent(for: networkId)) } - func report(contact: Contact, screenshot: UIImage, completion: @escaping () -> Void) { + func report(contact: XXModels.Contact, screenshot: UIImage, completion: @escaping () -> Void) { let report = Report( sender: .init( userId: contact.id.base64EncodedString(), @@ -285,13 +285,13 @@ final class GroupChatViewModel { } } - private func blockContact(_ contact: Contact) { + private func blockContact(_ contact: XXModels.Contact) { var contact = contact contact.isBlocked = true _ = try? database.saveContact(contact) } - private func presentReportConfirmation(contact: Contact) { + private func presentReportConfirmation(contact: XXModels.Contact) { let name = (contact.nickname ?? contact.username) ?? "the contact" toastController.enqueueToast(model: .init( title: "Your report has been sent and \(name) is now blocked.", diff --git a/Sources/ChatFeature/ViewModels/SingleChatViewModel.swift b/Sources/ChatFeature/ViewModels/SingleChatViewModel.swift index 5014a493..9b01d4d4 100644 --- a/Sources/ChatFeature/ViewModels/SingleChatViewModel.swift +++ b/Sources/ChatFeature/ViewModels/SingleChatViewModel.swift @@ -13,6 +13,7 @@ import ToastFeature import DifferenceKit import ReportingFeature import DependencyInjection +import XXMessengerClient import struct XXModels.Message import struct XXModels.FileTransfer @@ -29,22 +30,20 @@ enum SingleChatNavigationRoutes: Equatable { } final class SingleChatViewModel: NSObject { - @Dependency var e2e: E2E - @Dependency var cMix: CMix @Dependency var logger: XXLogger @Dependency var database: Database @Dependency var sendReport: SendReport - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger @Dependency var permissions: PermissionHandling @Dependency var toastController: ToastController @Dependency var transferManager: XXClient.FileTransfer @KeyObject(.username, defaultValue: nil) var username: String? - var contact: Contact { contactSubject.value } + var contact: XXModels.Contact { contactSubject.value } private var stagedReply: Reply? private var cancellables = Set<AnyCancellable>() - private let contactSubject: CurrentValueSubject<Contact, Never> + private let contactSubject: CurrentValueSubject<XXModels.Contact, Never> private let replySubject = PassthroughSubject<(String, String), Never>() private let navigationRoutes = PassthroughSubject<SingleChatNavigationRoutes, Never>() private let sectionsRelay = CurrentValueSubject<[ArraySection<ChatSection, Message>], Never>([]) @@ -59,10 +58,10 @@ final class SingleChatViewModel: NSObject { } var myId: Data { - try! GetIdFromContact.live(userDiscovery.getContact()) + try! messenger.ud.get()!.getContact().getId() } - var contactPublisher: AnyPublisher<Contact, Never> { contactSubject.eraseToAnyPublisher() } + var contactPublisher: AnyPublisher<XXModels.Contact, Never> { contactSubject.eraseToAnyPublisher() } var replyPublisher: AnyPublisher<(String, String), Never> { replySubject.eraseToAnyPublisher() } var navigation: AnyPublisher<SingleChatNavigationRoutes, Never> { navigationRoutes.eraseToAnyPublisher() } var shouldDisplayEmptyView: AnyPublisher<Bool, Never> { sectionsRelay.map { $0.isEmpty }.eraseToAnyPublisher() } @@ -79,7 +78,7 @@ final class SingleChatViewModel: NSObject { }.eraseToAnyPublisher() } - private func updateRecentState(_ contact: Contact) { + private func updateRecentState(_ contact: XXModels.Contact) { if contact.isRecent == true { var contact = contact contact.isRecent = false @@ -91,7 +90,7 @@ final class SingleChatViewModel: NSObject { updateRecentState(contact) } - init(_ contact: Contact) { + init(_ contact: XXModels.Contact) { self.contactSubject = .init(contact) super.init() @@ -215,7 +214,7 @@ final class SingleChatViewModel: NSObject { reply = Reply(messageId: replyId, senderId: myId) } - let report = try e2e.send( + let report = try messenger.e2e.get()!.send( messageType: 2, recipientId: contact.id, payload: Payload( @@ -225,7 +224,7 @@ final class SingleChatViewModel: NSObject { e2eParams: GetE2EParams.liveDefault() ) - try cMix.waitForRoundResult( + try messenger.cMix.get()!.waitForRoundResult( roundList: try report.encode(), timeoutMS: 5_000, callback: .init(handle: { @@ -320,14 +319,14 @@ final class SingleChatViewModel: NSObject { do { message = try database.saveMessage(message) - let report = try e2e.send( + let report = try messenger.e2e.get()!.send( messageType: 2, recipientId: contact.id, payload: Payload(text: message.text, reply: stagedReply).asData(), e2eParams: GetE2EParams.liveDefault() ) - try cMix.waitForRoundResult( + try messenger.cMix.get()!.waitForRoundResult( roundList: try report.encode(), timeoutMS: 5_000, callback: .init(handle: { diff --git a/Sources/ChatInputFeature/ChatInputReducer.swift b/Sources/ChatInputFeature/ChatInputReducer.swift index 23bb35ba..170647ee 100644 --- a/Sources/ChatInputFeature/ChatInputReducer.swift +++ b/Sources/ChatInputFeature/ChatInputReducer.swift @@ -1,3 +1,4 @@ +import Foundation import ComposableArchitecture public let chatInputReducer = Reducer<ChatInputState, ChatInputAction, ChatInputEnvironment> { state, action, env in diff --git a/Sources/ChatListFeature/ViewModel/ChatListViewModel.swift b/Sources/ChatListFeature/ViewModel/ChatListViewModel.swift index e578d5f7..557223c0 100644 --- a/Sources/ChatListFeature/ViewModel/ChatListViewModel.swift +++ b/Sources/ChatListFeature/ViewModel/ChatListViewModel.swift @@ -5,6 +5,7 @@ import Models import Combine import XXModels import Defaults +import XXMessengerClient import ReportingFeature import DependencyInjection @@ -18,16 +19,16 @@ enum SearchSection { enum SearchItem: Equatable, Hashable { case chat(ChatInfo) - case connection(Contact) + case connection(XXModels.Contact) } -typealias RecentsSnapshot = NSDiffableDataSourceSnapshot<SectionId, Contact> +typealias RecentsSnapshot = NSDiffableDataSourceSnapshot<SectionId, XXModels.Contact> typealias SearchSnapshot = NSDiffableDataSourceSnapshot<SearchSection, SearchItem> final class ChatListViewModel { @Dependency var database: Database + @Dependency var messenger: Messenger @Dependency var groupManager: GroupChat - @Dependency var userDiscovery: UserDiscovery @Dependency var reportingStatus: ReportingStatus // TO REFACTOR: @@ -36,7 +37,7 @@ final class ChatListViewModel { } var myId: Data { - try! GetIdFromContact.live(userDiscovery.getContact()) + try! messenger.ud.get()!.getContact().getId() } var chatsPublisher: AnyPublisher<[ChatInfo], Never> { @@ -189,7 +190,7 @@ final class ChatListViewModel { } } - func clear(_ contact: Contact) { + func clear(_ contact: XXModels.Contact) { _ = try? database.deleteMessages(.init(chat: .direct(myId, contact.id))) } diff --git a/Sources/ContactFeature/ViewModels/ContactViewModel.swift b/Sources/ContactFeature/ViewModels/ContactViewModel.swift index c5c5d085..7f915791 100644 --- a/Sources/ContactFeature/ViewModels/ContactViewModel.swift +++ b/Sources/ContactFeature/ViewModels/ContactViewModel.swift @@ -6,6 +6,7 @@ import XXModels import Defaults import CombineSchedulers import DependencyInjection +import XXMessengerClient import XXClient @@ -19,14 +20,13 @@ struct ContactViewState: Equatable { } final class ContactViewModel { - @Dependency var e2e: E2E @Dependency var database: Database - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger @Dependency var getFactsFromContact: GetFactsFromContact @KeyObject(.username, defaultValue: nil) var username: String? - var contact: Contact + var contact: XXModels.Contact var popToRootPublisher: AnyPublisher<Void, Never> { popToRootRelay.eraseToAnyPublisher() } var popPublisher: AnyPublisher<Void, Never> { popRelay.eraseToAnyPublisher() } @@ -41,15 +41,15 @@ final class ContactViewModel { private let stateRelay = CurrentValueSubject<ContactViewState, Never>(.init()) var myId: Data { - try! GetIdFromContact.live(userDiscovery.getContact()) + try! messenger.ud.get()!.getContact().getId() } var backgroundScheduler: AnySchedulerOf<DispatchQueue> = DispatchQueue.global().eraseToAnyScheduler() - init(_ contact: Contact) { + init(_ contact: XXModels.Contact) { self.contact = contact - let facts = try? getFactsFromContact(contact: contact.marshaled!) + let facts = try? getFactsFromContact(contact.marshaled!) let email = facts?.first(where: { $0.type == FactType.email.rawValue })?.fact let phone = facts?.first(where: { $0.type == FactType.phone.rawValue })?.fact @@ -73,7 +73,7 @@ final class ContactViewModel { hudRelay.send(.on) do { - try e2e.deleteRequest.partner(contact.id) + try messenger.e2e.get()!.deleteRequest.partnerId(contact.id) try database.deleteContact(contact) hudRelay.send(.none) @@ -111,11 +111,11 @@ final class ContactViewModel { do { try self.database.saveContact(self.contact) - var myFacts = try self.userDiscovery.getFacts() + var myFacts = try self.messenger.ud.get()!.getFacts() myFacts.append(Fact(fact: self.username!, type: FactType.username.rawValue)) - let _ = try self.e2e.requestAuthenticatedChannel( - partnerContact: self.contact.id, + let _ = try self.messenger.e2e.get()!.requestAuthenticatedChannel( + partner: XXClient.Contact.live(self.contact.marshaled!), myFacts: myFacts ) @@ -143,11 +143,11 @@ final class ContactViewModel { do { try self.database.saveContact(self.contact) - var myFacts = try self.userDiscovery.getFacts() + var myFacts = try self.messenger.ud.get()!.getFacts() myFacts.append(Fact(fact: self.username!, type: FactType.username.rawValue)) - let _ = try self.e2e.requestAuthenticatedChannel( - partnerContact: self.contact.marshaled!, + let _ = try self.messenger.e2e.get()!.requestAuthenticatedChannel( + partner: XXClient.Contact.live(self.contact.marshaled!), myFacts: myFacts ) @@ -175,7 +175,7 @@ final class ContactViewModel { do { try self.database.saveContact(self.contact) - let _ = try self.e2e.confirmReceivedRequest(partnerContact: self.contact.marshaled!) + let _ = try self.messenger.e2e.get()!.confirmReceivedRequest(partner: XXClient.Contact.live(self.contact.marshaled!)) self.contact.authStatus = .friend try self.database.saveContact(self.contact) diff --git a/Sources/ContactListFeature/ViewModels/ContactListViewModel.swift b/Sources/ContactListFeature/ViewModels/ContactListViewModel.swift index f37561ac..ad365d34 100644 --- a/Sources/ContactListFeature/ViewModels/ContactListViewModel.swift +++ b/Sources/ContactListFeature/ViewModels/ContactListViewModel.swift @@ -4,20 +4,21 @@ import XXModels import Defaults import ReportingFeature import DependencyInjection +import XXMessengerClient import Foundation import XXClient final class ContactListViewModel { @Dependency var database: Database - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger @Dependency private var reportingStatus: ReportingStatus var myId: Data { - try! GetIdFromContact.live(userDiscovery.getContact()) + try! messenger.ud.get()!.getContact().getId() } - var contacts: AnyPublisher<[Contact], Never> { + var contacts: AnyPublisher<[XXModels.Contact], Never> { let query = Contact.Query( authStatus: [.friend], isBlocked: reportingStatus.isEnabled() ? false : nil, diff --git a/Sources/ContactListFeature/ViewModels/CreateGroupViewModel.swift b/Sources/ContactListFeature/ViewModels/CreateGroupViewModel.swift index 06dabcb0..019e1333 100644 --- a/Sources/ContactListFeature/ViewModels/CreateGroupViewModel.swift +++ b/Sources/ContactListFeature/ViewModels/CreateGroupViewModel.swift @@ -8,6 +8,7 @@ import XXClient import ReportingFeature import CombineSchedulers import DependencyInjection +import XXMessengerClient final class CreateGroupViewModel { @KeyObject(.username, defaultValue: "") var username: String @@ -16,20 +17,20 @@ final class CreateGroupViewModel { @Dependency var database: Database @Dependency var groupManager: GroupChat - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger @Dependency var reportingStatus: ReportingStatus // MARK: Properties var myId: Data { - try! GetIdFromContact.live(userDiscovery.getContact()) + try! messenger.ud.get()!.getContact().getId() } - var selected: AnyPublisher<[Contact], Never> { + var selected: AnyPublisher<[XXModels.Contact], Never> { selectedContactsRelay.eraseToAnyPublisher() } - var contacts: AnyPublisher<[Contact], Never> { + var contacts: AnyPublisher<[XXModels.Contact], Never> { contactsRelay.eraseToAnyPublisher() } @@ -44,12 +45,12 @@ final class CreateGroupViewModel { var backgroundScheduler: AnySchedulerOf<DispatchQueue> = DispatchQueue.global().eraseToAnyScheduler() - private var allContacts = [Contact]() + private var allContacts = [XXModels.Contact]() private var cancellables = Set<AnyCancellable>() private let infoRelay = PassthroughSubject<GroupInfo, Never>() private let hudRelay = CurrentValueSubject<HUDStatus, Never>(.none) - private let contactsRelay = CurrentValueSubject<[Contact], Never>([]) - private let selectedContactsRelay = CurrentValueSubject<[Contact], Never>([]) + private let contactsRelay = CurrentValueSubject<[XXModels.Contact], Never>([]) + private let selectedContactsRelay = CurrentValueSubject<[XXModels.Contact], Never>([]) // MARK: Lifecycle @@ -72,7 +73,7 @@ final class CreateGroupViewModel { // MARK: Public - func didSelect(contact: Contact) { + func didSelect(contact: XXModels.Contact) { if selectedContactsRelay.value.contains(contact) { selectedContactsRelay.value.removeAll { $0.username == contact.username } } else { @@ -93,7 +94,7 @@ final class CreateGroupViewModel { ) } - func create(name: String, welcome: String?, members: [Contact]) { + func create(name: String, welcome: String?, members: [XXModels.Contact]) { hudRelay.send(.on) backgroundScheduler.schedule { [weak self] in diff --git a/Sources/LaunchFeature/LaunchController.swift b/Sources/LaunchFeature/LaunchController.swift index a17c9fc3..651da26c 100644 --- a/Sources/LaunchFeature/LaunchController.swift +++ b/Sources/LaunchFeature/LaunchController.swift @@ -144,7 +144,7 @@ public final class LaunchController: UIViewController { negativeButton.publisher(for: .touchUpInside) .sink { [unowned self] in blocker.hideWindow() - viewModel.versionApproved() + viewModel.continueWithInitialization() }.store(in: &cancellables) vStack.addArrangedSubview(negativeButton) diff --git a/Sources/LaunchFeature/LaunchViewModel.swift b/Sources/LaunchFeature/LaunchViewModel.swift index a520214e..5178c2e2 100644 --- a/Sources/LaunchFeature/LaunchViewModel.swift +++ b/Sources/LaunchFeature/LaunchViewModel.swift @@ -16,9 +16,11 @@ import DependencyInjection import XXClient import struct XXClient.FileTransfer +import class XXClient.Cancellable import XXDatabase import XXLegacyDatabaseMigrator +import XXMessengerClient struct Update { let content: String @@ -36,17 +38,14 @@ enum LaunchRoute { final class LaunchViewModel { @Dependency var database: Database - @Dependency var cMixManager: CMixManager @Dependency var versionChecker: VersionChecker @Dependency var dropboxService: DropboxInterface @Dependency var fetchBannedList: FetchBannedList @Dependency var reportingStatus: ReportingStatus @Dependency var toastController: ToastController @Dependency var keychainHandler: KeychainHandling - @Dependency var getIdFromContact: GetIdFromContact @Dependency var processBannedList: ProcessBannedList @Dependency var permissionHandler: PermissionHandling - @Dependency var getFactsFromContact: GetFactsFromContact @KeyObject(.username, defaultValue: nil) var username: String? @KeyObject(.biometrics, defaultValue: false) var isBiometricsOn: Bool @@ -55,6 +54,8 @@ final class LaunchViewModel { hudSubject.eraseToAnyPublisher() } + var authCallbacksCancellable: Cancellable? + var routePublisher: AnyPublisher<LaunchRoute, Never> { routeSubject.eraseToAnyPublisher() } @@ -80,7 +81,7 @@ final class LaunchViewModel { self.versionChecker().sink { [unowned self] in switch $0 { case .upToDate: - self.versionApproved() + self.updateBannedList { self.continueWithInitialization() } case .failure(let error): self.versionFailed(error: error) case .updateRequired(let info): @@ -92,58 +93,110 @@ final class LaunchViewModel { } } - func versionApproved() { - updateBannedList { [weak self] in - guard let self = self else { return } + func continueWithInitialization() { + do { + try self.setupDatabase() - _ = try? SetLogLevel.live(.trace) + try SetLogLevel.live(.trace) - try! self.setupDatabase() + guard let certPath = Bundle.module.path(forResource: "cmix.rip", ofType: "crt"), + let contactFilePath = Bundle.module.path(forResource: "udContact", ofType: "bin") else { + fatalError("Couldn't retrieve alternative UD credentials") + } - if self.cMixManager.hasStorage(), self.username != nil { - self.checkBiometrics { [weak self] in - guard let self = self else { return } + let address = "46.101.98.49:18001" + let cert = try Data(contentsOf: URL(fileURLWithPath: certPath)) + let contactFile = try Data(contentsOf: URL(fileURLWithPath: contactFilePath)) + + var environment: MessengerEnvironment = .live() + environment.udCert = cert + environment.udAddress = address + environment.udContact = contactFile + environment.ndfEnvironment = .mainnet + + let messenger = Messenger.live(environment) + + DependencyInjection.Container.shared.register(messenger) + + if messenger.isLoaded() == false { + if messenger.isCreated() == false { + try messenger.create() + } + + try messenger.load() + } + + try messenger.start() + authCallbacksCancellable = messenger.registerAuthCallbacks( + AuthCallbacks(handle: { switch $0 { - case .success(false): - break - case .success(true): - do { - //UpdateCommonErrors.live(jsonFile: ) DOWNLOAD THE JSON FROM THE REPO - - let cMix = try self.initCMix() - try cMix.startNetworkFollower(timeoutMS: 10_000) - guard cMix.waitForNetwork(timeoutMS: 30_000) else { - fatalError("^^^ cMix.waitForNetwork returned FALSE") - } + case .confirm(contact: let contact, receptionId: _, ephemeralId: _, roundId: _): + self.handleConfirm(from: contact) + case .request(contact: let contact, receptionId: _, ephemeralId: _, roundId: _): + self.handleDirectRequest(from: contact) + case .reset(contact: let contact, receptionId: _, ephemeralId: _, roundId: _): + self.handleReset(from: contact) + } + }) + ) + + if messenger.isConnected() == false { + try messenger.connect() + } + + try generateGroupManager(messenger: messenger) - let e2e = try self.initE2E(cMix) - _ = try self.initUD(alternative: true, e2e: e2e, cMix: cMix) - _ = try self.initGroupManager(e2e) - _ = try self.initTransferManager(e2e) - _ = try self.initDummyTrafficManager(e2e) + try generateTrafficManager(messenger: messenger) - self.hudSubject.send(.none) - self.routeSubject.send(.chats) - } catch { - self.hudSubject.send(.error(.init(with: error))) + try generateTransferManager(messenger: messenger) + + if messenger.isLoggedIn() == false { + if try messenger.isRegistered() == false { + hudSubject.send(.none) + routeSubject.send(.onboarding) + } else { + hudSubject.send(.none) + checkBiometrics { [weak self] bioResult in + + switch bioResult { + case .success(let granted): + if granted { + try! messenger.logIn() + self?.routeSubject.send(.chats) + } else { + // WHAT SHOULD HAPPEN HERE? + } + case .failure(let error): + print(">>> Bio auth failed: \(error.localizedDescription)") } - case .failure(let error): - self.hudSubject.send(.error(.init(with: error))) } } } else { - self.cleanUp() - self.presentOnboardingFlow() + hudSubject.send(.none) + checkBiometrics { [weak self] bioResult in + switch bioResult { + case .success(let granted): + if granted { + self?.routeSubject.send(.chats) + } else { + // WHAT SHOULD HAPPEN HERE? + } + case .failure(let error): + print(">>> Bio auth failed: \(error.localizedDescription)") + } + } } + } catch { + print(">>> Initialization couldn't be completed: \(error.localizedDescription)") } } private func cleanUp() { - try? cMixManager.remove() - try? keychainHandler.clear() - - dropboxService.unlink() +// try? cMixManager.remove() +// try? keychainHandler.clear() +// +// dropboxService.unlink() } private func presentOnboardingFlow() { @@ -189,7 +242,7 @@ final class LaunchViewModel { DependencyInjection.Container.shared.register(database) } - func getContactWith(userId: Data) -> Contact? { + func getContactWith(userId: Data) -> XXModels.Contact? { let query = Contact.Query( id: [userId], isBlocked: reportingStatus.isEnabled() ? false : nil, @@ -267,102 +320,80 @@ final class LaunchViewModel { } } - private func initCMix() throws -> CMix { - if let cMix = try? DependencyInjection.Container.shared.resolve() as CMix { - return cMix + private func updateBannedList(completion: @escaping () -> Void) { + fetchBannedList { result in + switch result { + case .failure(_): + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + self.updateBannedList(completion: completion) + } + case .success(let data): + self.processBannedList(data, completion: completion) + } } - - let cMix = try cMixManager.load() - DependencyInjection.Container.shared.register(cMix) - return cMix } - private func initE2E(_ cMix: CMix) throws -> E2E { - if let e2e = try? DependencyInjection.Container.shared.resolve() as E2E { - return e2e - } - - let e2e = try Login.live( - cMixId: cMix.getId(), - authCallbacks: .init( - handle: { - switch $0 { - case .reset(contact: let contact, receptionId: _, ephemeralId: _, roundId: _): - self.handleReset(from: contact) - case .confirm(contact: let contact, receptionId: _, ephemeralId: _, roundId: _): - self.handleConfirm(from: contact) - case .request(contact: let contact, receptionId: _, ephemeralId: _, roundId: _): - self.handleRequest(from: contact) + private func processBannedList(_ data: Data, completion: @escaping () -> Void) { + processBannedList( + data: data, + forEach: { result in + switch result { + case .success(let userId): + let query = Contact.Query(id: [userId]) + if var contact = try! database.fetchContacts(query).first { + if contact.isBanned == false { + contact.isBanned = true + try! database.saveContact(contact) + self.enqueueBanWarning(contact: contact) + } + } else { + try! database.saveContact(.init(id: userId, isBanned: true)) } + + case .failure(_): + break } - ), - identity: cMix.makeLegacyReceptionIdentity() - ) + }, + completion: { result in + switch result { + case .failure(_): + DispatchQueue.main.asyncAfter(deadline: .now() + 2) { + self.updateBannedList(completion: completion) + } - try e2e.registerListener( - senderId: nil, - messageType: 2, - callback: .init(handle: { message in - print(message.timestamp) - }) + case .success(_): + completion() + } + } ) - - DependencyInjection.Container.shared.register(e2e) - return e2e } - private func initUD(alternative: Bool, e2e: E2E, cMix: CMix) throws -> UserDiscovery { - if let userDiscovery = try? DependencyInjection.Container.shared.resolve() as UserDiscovery { - return userDiscovery - } - - guard let certPath = Bundle.module.path(forResource: "cmix.rip", ofType: "crt"), - let contactFilePath = Bundle.module.path(forResource: "udContact", ofType: "bin") else { - fatalError("Couldn't retrieve alternative UD credentials") - } - - let address = alternative ? "46.101.98.49:18001" : e2e.getUdAddressFromNdf() - let cert = alternative ? try Data(contentsOf: URL(fileURLWithPath: certPath)) : e2e.getUdCertFromNdf() - let contactFile = alternative ? try Data(contentsOf: URL(fileURLWithPath: contactFilePath)) : try e2e.getUdContactFromNdf() - - let userDiscovery = try NewOrLoadUd.live( - params: .init( - e2eId: e2e.getId(), - username: username!, - registrationValidationSignature: cMix.getReceptionRegistrationValidationSignature(), - cert: cert, - contactFile: contactFile, - address: address - ), - follower: .init(handle: { cMix.networkFollowerStatus() }) - ) - - DependencyInjection.Container.shared.register(userDiscovery) - return userDiscovery + private func enqueueBanWarning(contact: XXModels.Contact) { + let name = (contact.nickname ?? contact.username) ?? "One of your contacts" + toastController.enqueueToast(model: .init( + title: "\(name) has been banned for offensive content.", + leftImage: Asset.requestSentToaster.image + )) } +} - private func initGroupManager(_ e2e: E2E) throws -> GroupChat { - if let groupManager = try? DependencyInjection.Container.shared.resolve() as GroupChat { - return groupManager - } - - let groupManager = try NewGroupChat.live( - e2eId: e2e.getId(), - groupRequest: .init(handle: { print($0) }), - groupChatProcessor: .init(handle: { print($0) }) +extension LaunchViewModel { + private func generateGroupManager(messenger: Messenger) throws { + let manager = try NewGroupChat.live( + e2eId: messenger.e2e()!.getId(), + groupRequest: .init(handle: { [weak self] group in + guard let self = self else { return } + self.handleGroupRequest(from: group) + }), + groupChatProcessor: .init(handle: { print($0) }) // What is this? ) - DependencyInjection.Container.shared.register(groupManager) - return groupManager + DependencyInjection.Container.shared.register(manager) } - private func initTransferManager(_ e2e: E2E) throws -> XXClient.FileTransfer { - if let transferManager = try? DependencyInjection.Container.shared.resolve() as FileTransfer { - return transferManager - } - - let transferManager = try InitFileTransfer.live( - e2eId: e2e.getId(), + private func generateTransferManager(messenger: Messenger) throws { + let manager = try InitFileTransfer.live( + e2eId: messenger.e2e()!.getId(), callback: .init(handle: { switch $0 { case .success(let receivedFile): @@ -373,186 +404,141 @@ final class LaunchViewModel { }) ) - DependencyInjection.Container.shared.register(transferManager) - return transferManager + DependencyInjection.Container.shared.register(manager) } - private func initDummyTrafficManager(_ e2e: E2E) throws -> DummyTraffic { - if let dummyTrafficManager = try? DependencyInjection.Container.shared.resolve() as DummyTraffic { - return dummyTrafficManager - } - - let dummyTrafficManager = try NewDummyTrafficManager.live( - cMixId: e2e.getId(), + private func generateTrafficManager(messenger: Messenger) throws { + let manager = try NewDummyTrafficManager.live( + cMixId: messenger.e2e()!.getId(), maxNumMessages: 1, avgSendDeltaMS: 1, randomRangeMS: 1 ) - DependencyInjection.Container.shared.register(dummyTrafficManager) - return dummyTrafficManager - } - - private func handleRequest(from contact: Data) { - guard isRepeatedRequest(from: contact) == false else { return } - - do { - let facts = try? getFactsFromContact(contact: contact) - - let model = try self.database.saveContact(.init( - id: try getIdFromContact(contact), - marshaled: contact, - username: facts?.first(where: { $0.type == FactType.username.rawValue })?.fact, - email: facts?.first(where: { $0.type == FactType.email.rawValue })?.fact, - phone: facts?.first(where: { $0.type == FactType.phone.rawValue })?.fact, - nickname: nil, - photo: nil, - authStatus: .verificationInProgress, - isRecent: true, - createdAt: Date() - )) - - if model.email == nil, model.phone == nil { - performLookup(on: model) - } else { - //performSearch() - } - } catch { - print("^^^ Request processing failed: \(error.localizedDescription)") - } + DependencyInjection.Container.shared.register(manager) } +} - private func isRepeatedRequest(from contact: Data) -> Bool { - if let id = try? getIdFromContact(contact), - let _ = try? self.database.fetchContacts(Contact.Query(id: [id])).first { - return true +extension LaunchViewModel { + private func handleDirectRequest(from contact: XXClient.Contact) { + guard let id = try? contact.getId() else { + fatalError("Couldn't extract ID from contact request arrived.") } - return false - } - - private func performLookup(on contact: Contact) { - guard let e2e = try? DependencyInjection.Container.shared.resolve() as E2E, - let userDiscovery = try? DependencyInjection.Container.shared.resolve() as UserDiscovery else { - print("^^^ couldn't resolve UD/E2E to process lookup") + if let _ = try? database.fetchContacts(.init(id: [id])).first { + print(">>> Tried to handle request from pre-existing contact.") return } - do { - let _ = try LookupUD.live( - e2eId: e2e.getId(), - udContact: try userDiscovery.getContact(), - lookupId: contact.id, - callback: .init(handle: { [weak self] in + let facts = try? contact.getFacts() + let email = facts?.first(where: { $0.type == FactType.email.rawValue })?.fact + let phone = facts?.first(where: { $0.type == FactType.phone.rawValue })?.fact + let username = facts?.first(where: { $0.type == FactType.username.rawValue })?.fact + + var model = try! database.saveContact(.init( + id: id, + marshaled: contact.data, + username: username, + email: email, + phone: phone, + nickname: nil, + photo: nil, + authStatus: .verificationInProgress, + isRecent: false, + createdAt: Date() + )) + + if email == nil, phone == nil { + do { + try performLookup(on: contact) { [weak self] in guard let self = self else { return } switch $0 { - case .success(let id): - self.performOwnershipVerification(contact: contact, idLookedUp: id) + case .success(let lookedUpContact): + if try! self.verifyOwnership(contact, lookedUpContact) { // How could this ever throw? + model.authStatus = .verified + try! self.database.saveContact(model) + } else { + try! self.database.deleteContact(model) + } case .failure(let error): - print("^^^ Lookup failed: \(error.localizedDescription)") + model.authStatus = .verificationFailed + print(">>> Error \(#file):\(#line): \(error.localizedDescription)") + try! self.database.saveContact(model) } - }) - ) - } catch { - print("^^^ Error when trying to run lookup: \(error.localizedDescription)") + } + } catch { + print(">>> Error \(#file):\(#line): \(error.localizedDescription)") + } + } else { + performSearch(on: contact) } } - private func performOwnershipVerification(contact: Contact, idLookedUp: Data) { - guard let e2e = try? DependencyInjection.Container.shared.resolve() as E2E else { - print("^^^ couldn't resolve E2E to process verification") - return - } - - do { - let result = try e2e.verifyOwnership( - receivedContact: contact.marshaled!, - verifiedContact: idLookedUp, - e2eId: e2e.getId() - ) - - if result == true { - var contact = contact - contact.authStatus = .verified - try database.saveContact(contact) - } else { - try database.deleteContact(contact) - } - } catch { - print("^^^ Exception thrown at verify ownership") + private func handleConfirm(from contact: XXClient.Contact) { + guard let id = try? contact.getId() else { + fatalError("Couldn't extract ID from contact confirmation arrived.") } - } - private func handleConfirm(from contact: Data) { - guard let id = try? getIdFromContact(contact) else { - print("^^^ Couldn't get id from contact. Confirmation failed") + guard var existentContact = try? database.fetchContacts(.init(id: [id])).first else { + print(">>> Tried to handle a confirmation from someone that is not a contact yet") return } - if var model = try? database.fetchContacts(.init(id: [id])).first { - model.authStatus = .friend - _ = try? database.saveContact(model) - } + existentContact.authStatus = .friend + try! database.saveContact(existentContact) } - private func handleReset(from contact: Data) { + private func handleReset(from contact: XXClient.Contact) { // TODO } - private func updateBannedList(completion: @escaping () -> Void) { - fetchBannedList { result in - switch result { - case .failure(_): - DispatchQueue.main.asyncAfter(deadline: .now() + 2) { - self.updateBannedList(completion: completion) - } - case .success(let data): - self.processBannedList(data, completion: completion) - } - } + private func handleGroupRequest(from group: XXClient.Group) { + // TODO } - private func processBannedList(_ data: Data, completion: @escaping () -> Void) { - processBannedList( - data: data, - forEach: { result in - switch result { - case .success(let userId): - let query = Contact.Query(id: [userId]) - if var contact = try! database.fetchContacts(query).first { - if contact.isBanned == false { - contact.isBanned = true - try! database.saveContact(contact) - self.enqueueBanWarning(contact: contact) - } - } else { - try! database.saveContact(.init(id: userId, isBanned: true)) - } + private func performLookup( + on contact: XXClient.Contact, + completion: @escaping (Result<XXClient.Contact, Error>) -> Void + ) throws { + guard let messenger = try? DependencyInjection.Container.shared.resolve() as Messenger else { + fatalError(">>> Tried to lookup, but there's no messenger instance on DI container") + } - case .failure(_): - break - } - }, - completion: { result in - switch result { - case .failure(_): - DispatchQueue.main.asyncAfter(deadline: .now() + 2) { - self.updateBannedList(completion: completion) - } + print(">>> Performing Lookup") - case .success(_): - completion() + let _ = try LookupUD.live( + e2eId: messenger.e2e.get()!.getId(), + udContact: try messenger.ud.get()!.getContact(), + lookupId: contact.getId(), + callback: .init(handle: { + switch $0 { + case .success(let otherContact): + print(">>> Lookup succeeded") + + completion(.success(otherContact)) + case .failure(let error): + print(">>> Lookup failed: \(error.localizedDescription)") + + completion(.failure(error)) } - } + }) ) } - private func enqueueBanWarning(contact: Contact) { - let name = (contact.nickname ?? contact.username) ?? "One of your contacts" - toastController.enqueueToast(model: .init( - title: "\(name) has been banned for offensive content.", - leftImage: Asset.requestSentToaster.image - )) + private func performSearch(on contact: XXClient.Contact) { + fatalError(">>> UD Search is not implemented yet") + } + + private func verifyOwnership( + _ lhs: XXClient.Contact, + _ rhs: XXClient.Contact + ) throws -> Bool { + guard let messenger = try? DependencyInjection.Container.shared.resolve() as Messenger else { + fatalError(">>> Tried to verify ownership, but there's no messenger instance on DI container") + } + + let e2e = messenger.e2e.get()! + return try e2e.verifyOwnership(received: lhs, verified: rhs, e2eId: e2e.getId()) } } diff --git a/Sources/OnboardingFeature/ViewModels/OnboardingEmailConfirmationViewModel.swift b/Sources/OnboardingFeature/ViewModels/OnboardingEmailConfirmationViewModel.swift index b22252cb..d379b9cc 100644 --- a/Sources/OnboardingFeature/ViewModels/OnboardingEmailConfirmationViewModel.swift +++ b/Sources/OnboardingFeature/ViewModels/OnboardingEmailConfirmationViewModel.swift @@ -8,6 +8,7 @@ import InputField import XXClient import CombineSchedulers import DependencyInjection +import XXMessengerClient struct OnboardingEmailConfirmationViewState: Equatable { var input: String = "" @@ -16,7 +17,7 @@ struct OnboardingEmailConfirmationViewState: Equatable { } final class OnboardingEmailConfirmationViewModel { - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger @KeyObject(.email, defaultValue: nil) var email: String? @@ -66,7 +67,7 @@ final class OnboardingEmailConfirmationViewModel { guard let self = self else { return } do { - try self.userDiscovery.confirmFact( + try self.messenger.ud.get()!.confirmFact( confirmationId: self.confirmation.confirmationId!, code: self.stateRelay.value.input ) diff --git a/Sources/OnboardingFeature/ViewModels/OnboardingEmailViewModel.swift b/Sources/OnboardingFeature/ViewModels/OnboardingEmailViewModel.swift index 85776bd9..98262328 100644 --- a/Sources/OnboardingFeature/ViewModels/OnboardingEmailViewModel.swift +++ b/Sources/OnboardingFeature/ViewModels/OnboardingEmailViewModel.swift @@ -8,6 +8,7 @@ import InputField import XXClient import CombineSchedulers import DependencyInjection +import XXMessengerClient struct OnboardingEmailViewState: Equatable { var input: String = "" @@ -16,7 +17,7 @@ struct OnboardingEmailViewState: Equatable { } final class OnboardingEmailViewModel { - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger @KeyObject(.pushNotifications, defaultValue: false) private var pushNotifications @@ -44,7 +45,7 @@ final class OnboardingEmailViewModel { guard let self = self else { return } do { - let confirmationId = try self.userDiscovery.sendRegisterFact( + let confirmationId = try self.messenger.ud.get()!.sendRegisterFact( .init(fact: self.stateRelay.value.input, type: FactType.email.rawValue) ) diff --git a/Sources/OnboardingFeature/ViewModels/OnboardingPhoneConfirmationViewModel.swift b/Sources/OnboardingFeature/ViewModels/OnboardingPhoneConfirmationViewModel.swift index b05a6b21..49e15708 100644 --- a/Sources/OnboardingFeature/ViewModels/OnboardingPhoneConfirmationViewModel.swift +++ b/Sources/OnboardingFeature/ViewModels/OnboardingPhoneConfirmationViewModel.swift @@ -8,6 +8,7 @@ import InputField import XXClient import CombineSchedulers import DependencyInjection +import XXMessengerClient struct OnboardingPhoneConfirmationViewState: Equatable { var input: String = "" @@ -16,7 +17,7 @@ struct OnboardingPhoneConfirmationViewState: Equatable { } final class OnboardingPhoneConfirmationViewModel { - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger @KeyObject(.phone, defaultValue: nil) var phone: String? @@ -66,7 +67,7 @@ final class OnboardingPhoneConfirmationViewModel { guard let self = self else { return } do { - try self.userDiscovery.confirmFact( + try self.messenger.ud.get()!.confirmFact( confirmationId: self.confirmation.confirmationId!, code: self.stateRelay.value.input ) diff --git a/Sources/OnboardingFeature/ViewModels/OnboardingPhoneViewModel.swift b/Sources/OnboardingFeature/ViewModels/OnboardingPhoneViewModel.swift index 3469c45c..a3141d2c 100644 --- a/Sources/OnboardingFeature/ViewModels/OnboardingPhoneViewModel.swift +++ b/Sources/OnboardingFeature/ViewModels/OnboardingPhoneViewModel.swift @@ -2,11 +2,13 @@ import HUD import Shared import Models import Combine +import XXClient import Countries import InputField -import XXClient +import Foundation import CombineSchedulers import DependencyInjection +import XXMessengerClient struct OnboardingPhoneViewState: Equatable { var input: String = "" @@ -16,7 +18,7 @@ struct OnboardingPhoneViewState: Equatable { } final class OnboardingPhoneViewModel { - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger var hud: AnyPublisher<HUDStatus, Never> { hudRelay.eraseToAnyPublisher() } private let hudRelay = CurrentValueSubject<HUDStatus, Never>(.none) @@ -55,7 +57,7 @@ final class OnboardingPhoneViewModel { let content = "\(self.stateRelay.value.input)\(self.stateRelay.value.country.code)" do { - let confirmationId = try self.userDiscovery.sendRegisterFact( + let confirmationId = try self.messenger.ud.get()!.sendRegisterFact( .init(fact: content, type: FactType.phone.rawValue) ) diff --git a/Sources/OnboardingFeature/ViewModels/OnboardingUsernameViewModel.swift b/Sources/OnboardingFeature/ViewModels/OnboardingUsernameViewModel.swift index ff426498..d6d9b690 100644 --- a/Sources/OnboardingFeature/ViewModels/OnboardingUsernameViewModel.swift +++ b/Sources/OnboardingFeature/ViewModels/OnboardingUsernameViewModel.swift @@ -5,12 +5,11 @@ import Combine import Defaults import XXModels import InputField -import XXClient +import Foundation +import XXMessengerClient import CombineSchedulers import DependencyInjection -import struct XXClient.FileTransfer - struct OnboardingUsernameViewState: Equatable { var input: String = "" var status: InputField.ValidationStatus = .unknown(nil) @@ -18,9 +17,7 @@ struct OnboardingUsernameViewState: Equatable { final class OnboardingUsernameViewModel { @Dependency var database: Database - @Dependency var cMixManager: CMixManager - @Dependency var getIdFromContact: GetIdFromContact - @Dependency var getFactsFromContact: GetFactsFromContact + @Dependency var messenger: Messenger @KeyObject(.username, defaultValue: "") var username: String @@ -54,17 +51,26 @@ final class OnboardingUsernameViewModel { guard let self = self else { return } do { - let cMix = try self.initCMix() - try cMix.startNetworkFollower(timeoutMS: 10_000) - guard cMix.waitForNetwork(timeoutMS: 10_000) else { - fatalError("^^^ cMix.waitForNetwork returned FALSE") - } - let e2e = try self.initE2E(cMix) - let ud = try self.initUD(alternative: true, e2e: e2e, cMix: cMix) - _ = try self.initGroupManager(e2e) - _ = try self.initTransferManager(e2e) - _ = try self.initDummyTrafficManager(e2e) - + try self.messenger.register( + username: self.stateRelay.value.input + ) + + try self.database.saveContact(.init( + id: self.messenger.ud.get()!.getContact().getId(), + marshaled: self.messenger.ud.get()!.getContact().data, + username: self.stateRelay.value.input, + email: nil, + phone: nil, + nickname: nil, + photo: nil, + authStatus: .friend, + isRecent: false, + isBlocked: false, + isBanned: false, + createdAt: Date() + )) + + self.username = self.stateRelay.value.input self.hudRelay.send(.none) self.greenRelay.send() } catch { @@ -73,238 +79,4 @@ final class OnboardingUsernameViewModel { } } } - - private func initCMix() throws -> CMix { - if let cMix = try? DependencyInjection.Container.shared.resolve() as CMix { - return cMix - } - - let cMix = try cMixManager.create() - DependencyInjection.Container.shared.register(cMix) - return cMix - } - - private func initE2E(_ cMix: CMix) throws -> E2E { - if let e2e = try? DependencyInjection.Container.shared.resolve() as E2E { - return e2e - } - - let e2e = try Login.live( - cMixId: cMix.getId(), - authCallbacks: .init( - handle: { - switch $0 { - case .reset(contact: let contact, receptionId: _, ephemeralId: _, roundId: _): - self.handleReset(from: contact) - case .confirm(contact: let contact, receptionId: _, ephemeralId: _, roundId: _): - self.handleConfirm(from: contact) - case .request(contact: let contact, receptionId: _, ephemeralId: _, roundId: _): - self.handleRequest(from: contact) - } - } - ), - identity: cMix.makeLegacyReceptionIdentity() - ) - - try e2e.registerListener( - senderId: nil, - messageType: 2, - callback: .init(handle: { message in - print(message.timestamp) - }) - ) - - DependencyInjection.Container.shared.register(e2e) - return e2e - } - - private func initUD(alternative: Bool, e2e: E2E, cMix: CMix) throws -> UserDiscovery { - if let userDiscovery = try? DependencyInjection.Container.shared.resolve() as UserDiscovery { - return userDiscovery - } - - guard let certPath = Bundle.module.path(forResource: "cmix.rip", ofType: "crt"), - let contactFilePath = Bundle.module.path(forResource: "udContact", ofType: "bin") else { - fatalError("Couldn't retrieve alternative UD credentials") - } - - let address = alternative ? "46.101.98.49:18001" : e2e.getUdAddressFromNdf() - let cert = alternative ? try Data(contentsOf: URL(fileURLWithPath: certPath)) : e2e.getUdCertFromNdf() - let contactFile = alternative ? try Data(contentsOf: URL(fileURLWithPath: contactFilePath)) : try e2e.getUdContactFromNdf() - - let userDiscovery = try NewOrLoadUd.live( - params: .init( - e2eId: e2e.getId(), - username: self.stateRelay.value.input, - registrationValidationSignature: cMix.getReceptionRegistrationValidationSignature(), - cert: cert, - contactFile: contactFile, - address: address - ), - follower: .init(handle: { cMix.networkFollowerStatus() }) - ) - - username = self.stateRelay.value.input - DependencyInjection.Container.shared.register(userDiscovery) - return userDiscovery - } - - private func initGroupManager(_ e2e: E2E) throws -> GroupChat { - if let groupManager = try? DependencyInjection.Container.shared.resolve() as GroupChat { - return groupManager - } - - let groupManager = try NewGroupChat.live( - e2eId: e2e.getId(), - groupRequest: .init(handle: { print($0) }), - groupChatProcessor: .init(handle: { print($0) }) - ) - - DependencyInjection.Container.shared.register(groupManager) - return groupManager - } - - private func initTransferManager(_ e2e: E2E) throws -> XXClient.FileTransfer { - if let transferManager = try? DependencyInjection.Container.shared.resolve() as FileTransfer { - return transferManager - } - - let transferManager = try InitFileTransfer.live( - e2eId: e2e.getId(), - callback: .init(handle: { - switch $0 { - case .success(let receivedFile): - print(receivedFile.name) - case .failure(let error): - print(error.localizedDescription) - } - }) - ) - - DependencyInjection.Container.shared.register(transferManager) - return transferManager - } - - private func initDummyTrafficManager(_ e2e: E2E) throws -> DummyTraffic { - if let dummyTrafficManager = try? DependencyInjection.Container.shared.resolve() as DummyTraffic { - return dummyTrafficManager - } - - let dummyTrafficManager = try NewDummyTrafficManager.live( - cMixId: e2e.getId(), - maxNumMessages: 1, - avgSendDeltaMS: 1, - randomRangeMS: 1 - ) - - DependencyInjection.Container.shared.register(dummyTrafficManager) - return dummyTrafficManager - } - - private func handleRequest(from contact: Data) { - guard isRepeatedRequest(from: contact) == false else { return } - - do { - let facts = try? getFactsFromContact(contact: contact) - - let model = try self.database.saveContact(.init( - id: try getIdFromContact(contact), - marshaled: contact, - username: facts?.first(where: { $0.type == FactType.username.rawValue })?.fact, - email: facts?.first(where: { $0.type == FactType.email.rawValue })?.fact, - phone: facts?.first(where: { $0.type == FactType.phone.rawValue })?.fact, - nickname: nil, - photo: nil, - authStatus: .verificationInProgress, - isRecent: true, - createdAt: Date() - )) - - if model.email == nil, model.phone == nil { - performLookup(on: model) - } else { - //performSearch() - } - } catch { - print("^^^ Request processing failed: \(error.localizedDescription)") - } - } - - private func isRepeatedRequest(from contact: Data) -> Bool { - if let id = try? getIdFromContact(contact), - let _ = try? self.database.fetchContacts(Contact.Query(id: [id])).first { - return true - } - - return false - } - - private func performLookup(on contact: Contact) { - guard let e2e = try? DependencyInjection.Container.shared.resolve() as E2E, - let userDiscovery = try? DependencyInjection.Container.shared.resolve() as UserDiscovery else { - print("^^^ couldn't resolve UD/E2E to process lookup") - return - } - - do { - let _ = try LookupUD.live( - e2eId: e2e.getId(), - udContact: try userDiscovery.getContact(), - lookupId: contact.id, - callback: .init(handle: { [weak self] in - guard let self = self else { return } - - switch $0 { - case .success(let id): - self.performOwnershipVerification(contact: contact, idLookedUp: id) - case .failure(let error): - print("^^^ Lookup failed: \(error.localizedDescription)") - } - }) - ) - } catch { - print("^^^ Error when trying to run lookup: \(error.localizedDescription)") - } - } - - private func performOwnershipVerification(contact: Contact, idLookedUp: Data) { - guard let e2e = try? DependencyInjection.Container.shared.resolve() as E2E else { - print("^^^ couldn't resolve E2E to process verification") - return - } - - do { - let result = try e2e.verifyOwnership( - receivedContact: contact.marshaled!, - verifiedContact: idLookedUp, - e2eId: e2e.getId() - ) - - if result == true { - var contact = contact - contact.authStatus = .verified - try database.saveContact(contact) - } else { - try database.deleteContact(contact) - } - } catch { - print("^^^ Exception thrown at verify ownership") - } - } - - private func handleConfirm(from contact: Data) { - guard let id = try? getIdFromContact(contact) else { - print("^^^ Couldn't get id from contact. Confirmation failed") - return - } - - if var model = try? database.fetchContacts(.init(id: [id])).first { - model.authStatus = .friend - _ = try? database.saveContact(model) - } - } - - private func handleReset(from contact: Data) { - // TODO - } } diff --git a/Sources/ProfileFeature/ViewModels/ProfileCodeViewModel.swift b/Sources/ProfileFeature/ViewModels/ProfileCodeViewModel.swift index 49be0077..f2c0d8a5 100644 --- a/Sources/ProfileFeature/ViewModels/ProfileCodeViewModel.swift +++ b/Sources/ProfileFeature/ViewModels/ProfileCodeViewModel.swift @@ -3,10 +3,12 @@ import Shared import Models import Combine import Defaults -import InputField import XXClient +import Foundation +import InputField import CombineSchedulers import DependencyInjection +import XXMessengerClient struct ProfileCodeViewState: Equatable { var input: String = "" @@ -15,7 +17,7 @@ struct ProfileCodeViewState: Equatable { } final class ProfileCodeViewModel { - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger @KeyObject(.email, defaultValue: nil) var email: String? @KeyObject(.phone, defaultValue: nil) var phone: String? @@ -67,7 +69,7 @@ final class ProfileCodeViewModel { guard let self = self else { return } do { - try self.userDiscovery.confirmFact( + try self.messenger.ud.get()!.confirmFact( confirmationId: self.confirmation.confirmationId!, code: self.stateRelay.value.input ) diff --git a/Sources/ProfileFeature/ViewModels/ProfileEmailViewModel.swift b/Sources/ProfileFeature/ViewModels/ProfileEmailViewModel.swift index 21ec9fa8..8edf40aa 100644 --- a/Sources/ProfileFeature/ViewModels/ProfileEmailViewModel.swift +++ b/Sources/ProfileFeature/ViewModels/ProfileEmailViewModel.swift @@ -2,10 +2,12 @@ import HUD import Models import Shared import Combine -import InputField import XXClient +import Foundation +import InputField import CombineSchedulers import DependencyInjection +import XXMessengerClient struct ProfileEmailViewState: Equatable { var input: String = "" @@ -16,7 +18,7 @@ struct ProfileEmailViewState: Equatable { final class ProfileEmailViewModel { // MARK: Injected - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger // MARK: Properties @@ -46,7 +48,7 @@ final class ProfileEmailViewModel { guard let self = self else { return } do { - let confirmationId = try self.userDiscovery.sendRegisterFact( + let confirmationId = try self.messenger.ud.get()!.sendRegisterFact( .init(fact: self.stateRelay.value.input, type: FactType.email.rawValue) ) diff --git a/Sources/ProfileFeature/ViewModels/ProfilePhoneViewModel.swift b/Sources/ProfileFeature/ViewModels/ProfilePhoneViewModel.swift index 37db504e..e5504140 100644 --- a/Sources/ProfileFeature/ViewModels/ProfilePhoneViewModel.swift +++ b/Sources/ProfileFeature/ViewModels/ProfilePhoneViewModel.swift @@ -2,11 +2,13 @@ import HUD import Shared import Models import Combine +import XXClient import Countries import InputField -import XXClient +import Foundation import CombineSchedulers import DependencyInjection +import XXMessengerClient struct ProfilePhoneViewState: Equatable { var input: String = "" @@ -18,7 +20,7 @@ struct ProfilePhoneViewState: Equatable { final class ProfilePhoneViewModel { // MARK: Injected - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger // MARK: Properties @@ -55,7 +57,7 @@ final class ProfilePhoneViewModel { let content = "\(self.stateRelay.value.input)\(self.stateRelay.value.country.code)" do { - let confirmationId = try self.userDiscovery.sendRegisterFact( + let confirmationId = try self.messenger.ud.get()!.sendRegisterFact( .init(fact: content, type: FactType.phone.rawValue) ) diff --git a/Sources/ProfileFeature/ViewModels/ProfileViewModel.swift b/Sources/ProfileFeature/ViewModels/ProfileViewModel.swift index d6bc8bb3..57334dcf 100644 --- a/Sources/ProfileFeature/ViewModels/ProfileViewModel.swift +++ b/Sources/ProfileFeature/ViewModels/ProfileViewModel.swift @@ -10,6 +10,7 @@ import Permissions import XXClient import CombineSchedulers import DependencyInjection +import XXMessengerClient enum ProfileNavigationRoutes { case none @@ -31,7 +32,7 @@ final class ProfileViewModel { @KeyObject(.sharingEmail, defaultValue: false) var isEmailSharing: Bool @KeyObject(.sharingPhone, defaultValue: false) var isPhoneSharing: Bool - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger @Dependency private var permissions: PermissionHandling var name: String { username! } @@ -90,9 +91,9 @@ final class ProfileViewModel { guard let self = self else { return } do { - try self.userDiscovery.removeFact( + try self.messenger.ud.get()!.removeFact( .init( - fact: isEmail ? "E\(self.emailStored!)" : "P\(self.phoneStored!)", + fact: isEmail ? self.emailStored! : self.phoneStored!, type: isEmail ? FactType.email.rawValue : FactType.phone.rawValue ) ) diff --git a/Sources/RequestsFeature/ViewModels/RequestsFailedViewModel.swift b/Sources/RequestsFeature/ViewModels/RequestsFailedViewModel.swift index 6b3cf746..29636883 100644 --- a/Sources/RequestsFeature/ViewModels/RequestsFailedViewModel.swift +++ b/Sources/RequestsFeature/ViewModels/RequestsFailedViewModel.swift @@ -7,11 +7,11 @@ import Defaults import XXClient import CombineSchedulers import DependencyInjection +import XXMessengerClient final class RequestsFailedViewModel { - @Dependency var e2e: E2E @Dependency var database: Database - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger @KeyObject(.username, defaultValue: nil) var username: String? @@ -49,11 +49,11 @@ final class RequestsFailedViewModel { guard let self = self else { return } do { - var myFacts = try self.userDiscovery.getFacts() + var myFacts = try self.messenger.ud.get()!.getFacts() myFacts.append(Fact(fact: self.username!, type: FactType.username.rawValue)) - let _ = try self.e2e.requestAuthenticatedChannel( - partnerContact: contact.id, + let _ = try self.messenger.e2e.get()!.requestAuthenticatedChannel( + partner: XXClient.Contact.live(contact.marshaled!), myFacts: myFacts ) diff --git a/Sources/RequestsFeature/ViewModels/RequestsReceivedViewModel.swift b/Sources/RequestsFeature/ViewModels/RequestsReceivedViewModel.swift index 9ae5fc8e..326b72a9 100644 --- a/Sources/RequestsFeature/ViewModels/RequestsReceivedViewModel.swift +++ b/Sources/RequestsFeature/ViewModels/RequestsReceivedViewModel.swift @@ -10,6 +10,7 @@ import DrawerFeature import ReportingFeature import CombineSchedulers import DependencyInjection +import XXMessengerClient import struct XXModels.Group @@ -20,10 +21,9 @@ struct RequestReceived: Hashable, Equatable { } final class RequestsReceivedViewModel { - @Dependency var e2e: E2E @Dependency var database: Database @Dependency var groupManager: GroupChat - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger @Dependency var reportingStatus: ReportingStatus @KeyObject(.isShowingHiddenRequests, defaultValue: false) var isShowingHiddenRequests: Bool @@ -44,7 +44,7 @@ final class RequestsReceivedViewModel { groupConfirmationSubject.eraseToAnyPublisher() } - var contactConfirmationPublisher: AnyPublisher<Contact, Never> { + var contactConfirmationPublisher: AnyPublisher<XXModels.Contact, Never> { contactConfirmationSubject.eraseToAnyPublisher() } @@ -53,7 +53,7 @@ final class RequestsReceivedViewModel { private let verifyingSubject = PassthroughSubject<Void, Never>() private let hudSubject = CurrentValueSubject<HUDStatus, Never>(.none) private let groupConfirmationSubject = PassthroughSubject<Group, Never>() - private let contactConfirmationSubject = PassthroughSubject<Contact, Never>() + private let contactConfirmationSubject = PassthroughSubject<XXModels.Contact, Never>() private let itemsSubject = CurrentValueSubject<NSDiffableDataSourceSnapshot<Section, RequestReceived>, Never>(.init()) var backgroundScheduler: AnySchedulerOf<DispatchQueue> = DispatchQueue.global().eraseToAnyScheduler() @@ -156,16 +156,16 @@ final class RequestsReceivedViewModel { if contact.email == nil && contact.phone == nil { let _ = try LookupUD.live( - e2eId: self.e2e.getId(), - udContact: self.userDiscovery.getContact(), + e2eId: self.messenger.e2e.get()!.getId(), + udContact: self.messenger.ud.get()!.getContact(), lookupId: contact.id, callback: .init(handle: { switch $0 { - case .success(let data): - let ownershipResult = try! self.e2e.verifyOwnership( - receivedContact: contact.marshaled!, - verifiedContact: data, - e2eId: self.e2e.getId() + case .success(let secondContact): + let ownershipResult = try! self.messenger.e2e.get()!.verifyOwnership( + received: XXClient.Contact.live(contact.marshaled!), + verified: secondContact, + e2eId: self.messenger.e2e.get()!.getId() ) if ownershipResult == true { @@ -262,14 +262,14 @@ final class RequestsReceivedViewModel { } } - func didRequestHide(contact: Contact) { + func didRequestHide(contact: XXModels.Contact) { if var contact = try? database.fetchContacts(.init(id: [contact.id])).first { contact.authStatus = .hidden _ = try? database.saveContact(contact) } } - func didRequestAccept(contact: Contact, nickname: String? = nil) { + func didRequestAccept(contact: XXModels.Contact, nickname: String? = nil) { hudSubject.send(.on) var contact = contact @@ -282,7 +282,7 @@ final class RequestsReceivedViewModel { do { try self.database.saveContact(contact) - let _ = try self.e2e.confirmReceivedRequest(partnerContact: contact.id) + let _ = try self.messenger.e2e.get()!.confirmReceivedRequest(partner: XXClient.Contact.live(contact.marshaled!)) contact.authStatus = .friend try self.database.saveContact(contact) diff --git a/Sources/RequestsFeature/ViewModels/RequestsSentViewModel.swift b/Sources/RequestsFeature/ViewModels/RequestsSentViewModel.swift index 2463f011..1522b9ec 100644 --- a/Sources/RequestsFeature/ViewModels/RequestsSentViewModel.swift +++ b/Sources/RequestsFeature/ViewModels/RequestsSentViewModel.swift @@ -11,6 +11,7 @@ import ToastFeature import ReportingFeature import CombineSchedulers import DependencyInjection +import XXMessengerClient struct RequestSent: Hashable, Equatable { var request: Request @@ -18,9 +19,8 @@ struct RequestSent: Hashable, Equatable { } final class RequestsSentViewModel { - @Dependency var e2e: E2E @Dependency var database: Database - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger @Dependency var reportingStatus: ReportingStatus @Dependency var toastController: ToastController @@ -70,11 +70,11 @@ final class RequestsSentViewModel { guard let self = self else { return } do { - var myFacts = try self.userDiscovery.getFacts() + var myFacts = try self.messenger.ud.get()!.getFacts() myFacts.append(Fact(fact: self.username!, type: FactType.username.rawValue)) - let _ = try self.e2e.requestAuthenticatedChannel( - partnerContact: contact.id, + let _ = try self.messenger.e2e.get()!.requestAuthenticatedChannel( + partner: XXClient.Contact.live(contact.marshaled!), myFacts: myFacts ) diff --git a/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift b/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift index 4560f3cd..002ba409 100644 --- a/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift +++ b/Sources/RestoreFeature/ViewModels/RestoreViewModel.swift @@ -225,7 +225,7 @@ final class RestoreViewModel { } } ), - identity: try cMix.makeLegacyReceptionIdentity() + identity: try cMix.makeReceptionIdentity() ) guard let certPath = Bundle.module.path(forResource: "cmix.rip", ofType: "crt"), @@ -240,7 +240,7 @@ final class RestoreViewModel { email: emailFact, phone: phoneFact, cert: Data(contentsOf: URL(fileURLWithPath: certPath)), - contactFile: Data(contentsOf: URL(fileURLWithPath: contactFilePath)), + contact: Data(contentsOf: URL(fileURLWithPath: contactFilePath)), address: "46.101.98.49:18001" ), follower: .init(handle: { cMix.networkFollowerStatus() }) diff --git a/Sources/ScanFeature/ViewModels/ScanDisplayViewModel.swift b/Sources/ScanFeature/ViewModels/ScanDisplayViewModel.swift index 1b7ed9b2..d18e7ab8 100644 --- a/Sources/ScanFeature/ViewModels/ScanDisplayViewModel.swift +++ b/Sources/ScanFeature/ViewModels/ScanDisplayViewModel.swift @@ -5,6 +5,7 @@ import Defaults import Countries import XXClient import DependencyInjection +import XXMessengerClient struct ScanDisplayViewState: Equatable { var image: CIImage? @@ -15,7 +16,7 @@ struct ScanDisplayViewState: Equatable { } final class ScanDisplayViewModel { - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger @KeyObject(.email, defaultValue: nil) private var email: String? @KeyObject(.phone, defaultValue: nil) private var phone: String? @@ -60,7 +61,7 @@ final class ScanDisplayViewModel { guard let filter = CIFilter(name: "CIQRCodeGenerator") else { return } var facts: [Fact] = [] - let myContact = try! userDiscovery.getContact() + let myContact = try! messenger.ud.get()!.getContact() if sharingPhone { facts.append(Fact(fact: phone!, type: FactType.phone.rawValue)) @@ -71,7 +72,7 @@ final class ScanDisplayViewModel { } let myContactWithFacts = try! SetFactsOnContact.live( - contact: myContact, + contactData: myContact.data, facts: facts ) diff --git a/Sources/ScanFeature/ViewModels/ScanViewModel.swift b/Sources/ScanFeature/ViewModels/ScanViewModel.swift index c7c9b11a..365533cd 100644 --- a/Sources/ScanFeature/ViewModels/ScanViewModel.swift +++ b/Sources/ScanFeature/ViewModels/ScanViewModel.swift @@ -32,8 +32,8 @@ final class ScanViewModel { var backgroundScheduler: AnySchedulerOf<DispatchQueue> = DispatchQueue.global().eraseToAnyScheduler() - var contactPublisher: AnyPublisher<Contact, Never> { contactRelay.eraseToAnyPublisher() } - private let contactRelay = PassthroughSubject<Contact, Never>() + var contactPublisher: AnyPublisher<XXModels.Contact, Never> { contactRelay.eraseToAnyPublisher() } + private let contactRelay = PassthroughSubject<XXModels.Contact, Never>() var state: AnyPublisher<ScanViewState, Never> { stateRelay.eraseToAnyPublisher() } private let stateRelay = CurrentValueSubject<ScanViewState, Never>(.init()) @@ -73,7 +73,7 @@ final class ScanViewModel { return } - let facts = try? self.getFactsFromContact(contact: data) + let facts = try? self.getFactsFromContact(data) let contactEmail = facts?.first(where: { $0.type == FactType.email.rawValue })?.fact let contactPhone = facts?.first(where: { $0.type == FactType.phone.rawValue })?.fact @@ -99,14 +99,14 @@ final class ScanViewModel { private func verifyScanned(_ data: Data) throws -> (String, Data)? { let id = try? GetIdFromContact.live(data) - let facts = try? getFactsFromContact(contact: data) + let facts = try? getFactsFromContact(data) let username = facts?.first(where: { $0.type == FactType.username.rawValue })?.fact guard let id = id, let username = username else { return nil } return (username, id) } - private func succeed(with contact: Contact) { + private func succeed(with contact: XXModels.Contact) { stateRelay.value.status = .success contactRelay.send(contact) } diff --git a/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift b/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift index f24715e9..c6158e73 100644 --- a/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift +++ b/Sources/SearchFeature/ViewModels/SearchLeftViewModel.swift @@ -13,6 +13,7 @@ import NetworkMonitor import ReportingFeature import CombineSchedulers import DependencyInjection +import XXMessengerClient typealias SearchSnapshot = NSDiffableDataSourceSnapshot<SearchSection, SearchItem> @@ -24,24 +25,22 @@ struct SearchLeftViewState { } final class SearchLeftViewModel { - @Dependency var e2e: E2E - @Dependency var cMix: CMix @Dependency var database: Database - @Dependency var userDiscovery: UserDiscovery + @Dependency var messenger: Messenger @Dependency var reportingStatus: ReportingStatus @Dependency var networkMonitor: NetworkMonitoring @KeyObject(.username, defaultValue: nil) var username: String? var myId: Data { - try! GetIdFromContact.live(userDiscovery.getContact()) + try! messenger.ud.get()!.getContact().getId() } var hudPublisher: AnyPublisher<HUDStatus, Never> { hudSubject.eraseToAnyPublisher() } - var successPublisher: AnyPublisher<Contact, Never> { + var successPublisher: AnyPublisher<XXModels.Contact, Never> { successSubject.eraseToAnyPublisher() } @@ -53,7 +52,7 @@ final class SearchLeftViewModel { private var invitation: String? private var searchCancellables = Set<AnyCancellable>() - private let successSubject = PassthroughSubject<Contact, Never>() + private let successSubject = PassthroughSubject<XXModels.Contact, Never>() private let hudSubject = CurrentValueSubject<HUDStatus, Never>(.none) private let stateSubject = CurrentValueSubject<SearchLeftViewState, Never>(.init()) private var networkCancellable = Set<AnyCancellable>() @@ -70,17 +69,17 @@ final class SearchLeftViewModel { networkCancellable.removeAll() - networkMonitor.statusPublisher - .first { $0 == .available } - .eraseToAnyPublisher() - .flatMap { _ in self.session.waitForNodes(timeout: 5) } - .sink { - if case .failure(let error) = $0 { - self.hudSubject.send(.error(.init(with: error))) - } - } receiveValue: { - self.didStartSearching() - }.store(in: &networkCancellable) +// networkMonitor.statusPublisher +// .first { $0 == .available } +// .eraseToAnyPublisher() +// .flatMap { _ in self.session.waitForNodes(timeout: 5) } +// .sink { +// if case .failure(let error) = $0 { +// self.hudSubject.send(.error(.init(with: error))) +// } +// } receiveValue: { +// self.didStartSearching() +// }.store(in: &networkCancellable) } } @@ -113,7 +112,7 @@ final class SearchLeftViewModel { content += stateSubject.value.country.code } - let nrr = try! cMix.getNodeRegistrationStatus() + let nrr = try! messenger.cMix.get()!.getNodeRegistrationStatus() print("^^^ NRR: \(nrr.ratio)") backgroundScheduler.schedule { [weak self] in @@ -121,16 +120,29 @@ final class SearchLeftViewModel { do { let report = try SearchUD.live( - e2eId: self.e2e.getId(), - udContact: self.userDiscovery.getContact(), + e2eId: self.messenger.e2e.get()!.getId(), + udContact: self.messenger.ud.get()!.getContact(), facts: [Fact(fact: content, type: self.stateSubject.value.item.rawValue)], callback: .init(handle: { switch $0 { - case .success(let dataArray): - print("^^^ searchUD success: \(dataArray.map { $0.base64EncodedString() })") - + case .success(let results): self.hudSubject.send(.none) -// self.appendToLocalSearch(contact) + self.appendToLocalSearch( + XXModels.Contact( + id: try! results.first!.getId(), + marshaled: results.first!.data, + username: try! results.first?.getFacts().first(where: { $0.type == FactType.username.rawValue })?.fact, + email: try? results.first?.getFacts().first(where: { $0.type == FactType.email.rawValue })?.fact, + phone: try? results.first?.getFacts().first(where: { $0.type == FactType.phone.rawValue })?.fact, + nickname: nil, + photo: nil, + authStatus: .stranger, + isRecent: false, + isBlocked: false, + isBanned: false, + createdAt: Date() + ) + ) case .failure(let error): print("^^^ searchUD error: \(error.localizedDescription)") @@ -147,7 +159,7 @@ final class SearchLeftViewModel { } } - func didTapResend(contact: Contact) { + func didTapResend(contact: XXModels.Contact) { hudSubject.send(.on) var contact = contact @@ -159,11 +171,11 @@ final class SearchLeftViewModel { do { try self.database.saveContact(contact) - var myFacts = try self.userDiscovery.getFacts() + var myFacts = try self.messenger.ud.get()!.getFacts() myFacts.append(Fact(fact: self.username!, type: FactType.username.rawValue)) - let _ = try self.e2e.requestAuthenticatedChannel( - partnerContact: contact.id, + let _ = try self.messenger.e2e.get()!.requestAuthenticatedChannel( + partner: XXClient.Contact.live(contact.marshaled!), myFacts: myFacts ) @@ -179,7 +191,7 @@ final class SearchLeftViewModel { } } - func didTapRequest(contact: Contact) { + func didTapRequest(contact: XXModels.Contact) { hudSubject.send(.on) var contact = contact @@ -192,11 +204,11 @@ final class SearchLeftViewModel { do { try self.database.saveContact(contact) - var myFacts = try self.userDiscovery.getFacts() + var myFacts = try self.messenger.ud.get()!.getFacts() myFacts.append(Fact(fact: self.username!, type: FactType.username.rawValue)) - let _ = try self.e2e.requestAuthenticatedChannel( - partnerContact: contact.marshaled!, + let _ = try self.messenger.e2e.get()!.requestAuthenticatedChannel( + partner: XXClient.Contact.live(contact.marshaled!), myFacts: myFacts ) @@ -213,14 +225,14 @@ final class SearchLeftViewModel { } } - func didSet(nickname: String, for contact: Contact) { + func didSet(nickname: String, for contact: XXModels.Contact) { if var contact = try? database.fetchContacts(.init(id: [contact.id])).first { contact.nickname = nickname _ = try? database.saveContact(contact) } } - private func appendToLocalSearch(_ user: Contact?) { + private func appendToLocalSearch(_ user: XXModels.Contact?) { var snapshot = SearchSnapshot() if var user = user { @@ -259,7 +271,7 @@ final class SearchLeftViewModel { stateSubject.value.snapshot = snapshot } - private func removeMyself(from collection: [Contact]) -> [Contact]? { + private func removeMyself(from collection: [XXModels.Contact]) -> [XXModels.Contact]? { collection.filter { $0.id != myId } } } diff --git a/Sources/SearchFeature/ViewModels/SearchRightViewModel.swift b/Sources/SearchFeature/ViewModels/SearchRightViewModel.swift index 671e340d..8d41282f 100644 --- a/Sources/SearchFeature/ViewModels/SearchRightViewModel.swift +++ b/Sources/SearchFeature/ViewModels/SearchRightViewModel.swift @@ -29,7 +29,7 @@ final class SearchRightViewModel { @Dependency var reportingStatus: ReportingStatus @Dependency var getFactsFromContact: GetFactsFromContact - var foundPublisher: AnyPublisher<Contact, Never> { + var foundPublisher: AnyPublisher<XXModels.Contact, Never> { foundSubject.eraseToAnyPublisher() } @@ -41,7 +41,7 @@ final class SearchRightViewModel { statusSubject.eraseToAnyPublisher() } - private let foundSubject = PassthroughSubject<Contact, Never>() + private let foundSubject = PassthroughSubject<XXModels.Contact, Never>() private let cameraSemaphoreSubject = PassthroughSubject<Bool, Never>() private(set) var statusSubject = CurrentValueSubject<ScanningStatus, Never>(.reading) @@ -73,7 +73,7 @@ final class SearchRightViewModel { /// otherwise is just noise or an unknown qr code /// let userId = try? GetIdFromContact.live(data) - let facts = try? getFactsFromContact(contact: data) + let facts = try? getFactsFromContact(data) let username = facts?.first(where: { $0.type == FactType.username.rawValue })?.fact guard let userId = userId, let username = username else { @@ -113,11 +113,11 @@ final class SearchRightViewModel { statusSubject.send(.success) cameraSemaphoreSubject.send(false) - let email = try? GetFactsFromContact.live(contact: data) + let email = try? GetFactsFromContact.live(data) .first(where: { $0.type == FactType.email.rawValue }) .map(\.fact) - let phone = try? GetFactsFromContact.live(contact: data) + let phone = try? GetFactsFromContact.live(data) .first(where: { $0.type == FactType.phone.rawValue }) .map(\.fact) diff --git a/client-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved b/client-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved index 00c840d9..4fd5a955 100644 --- a/client-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/client-ios.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -68,8 +68,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/combine-schedulers", "state" : { - "revision" : "8fee20f993e64bbbf22bc3e3f444758ac2d05692", - "version" : "0.7.2" + "revision" : "9e42b4b0453da417a44daa17174103e7d1c5be07", + "version" : "0.7.3" } }, { @@ -105,7 +105,7 @@ "location" : "https://git.xx.network/elixxir/elixxir-dapps-sdk-swift", "state" : { "branch" : "development", - "revision" : "e5088ee5e3a3aeb6d6887d2402df829acdb4f8c2" + "revision" : "32ac1c46d6015069efa20dfe772f20adee6e3ecb" } }, { @@ -328,8 +328,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/pointfreeco/swift-composable-architecture.git", "state" : { - "revision" : "108e3a536fcebb16c4f247ef92c2d7326baf9fe3", - "version" : "0.39.0" + "revision" : "a518935116b2bada7234f47073159b433d432af1", + "version" : "0.39.1" } }, { @@ -355,8 +355,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-protobuf", "state" : { - "revision" : "fa0fcd43f272a260e7f734f23e6dc55e16fcae0a", - "version" : "1.19.1" + "revision" : "b8230909dedc640294d7324d37f4c91ad3dcf177", + "version" : "1.20.1" } }, { -- GitLab