diff --git a/Monal/Monal.xcodeproj/project.pbxproj b/Monal/Monal.xcodeproj/project.pbxproj index 4b2546f..9e5a22f 100644 --- a/Monal/Monal.xcodeproj/project.pbxproj +++ b/Monal/Monal.xcodeproj/project.pbxproj @@ -131,6 +131,7 @@ 54E594BE2523C34B00E4172B /* MLPubSub.m in Sources */ = {isa = PBXBuildFile; fileRef = 54E594BC2523C34A00E4172B /* MLPubSub.m */; }; 54F0B81928231691003664BD /* WelcomeLogIn.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54F0B81828231690003664BD /* WelcomeLogIn.swift */; }; 54F0B81C282316F5003664BD /* RegisterAccount.swift in Sources */ = {isa = PBXBuildFile; fileRef = 54F0B81B282316F5003664BD /* RegisterAccount.swift */; }; + 598A717356906687AD101542 /* MonalWrapperModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 282FE922A600668B10016B4C /* MonalWrapperModels.swift */; }; 6E9488F6997650B805476F25 /* Pods_another_im.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = F29121F912380F72CCE51747 /* Pods_another_im.framework */; }; 7D40218FEAB3BA882811A682 /* Pods_Monal.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8C40963CED187B2F1B4B88F7 /* Pods_Monal.framework */; }; 7E1C0AC72CEF68C000B8FEC0 /* MainTabScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E1C0AC62CEF68C000B8FEC0 /* MainTabScreen.swift */; }; @@ -559,6 +560,7 @@ 26FC619524EB6C270094C302 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = external/en.lproj/iosShare.strings; sourceTree = ""; }; 26FE3BC91C61A6C3003CC230 /* MLResizingTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MLResizingTextView.h; sourceTree = ""; }; 26FE3BCA1C61A6C3003CC230 /* MLResizingTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MLResizingTextView.m; sourceTree = ""; }; + 282FE922A600668B10016B4C /* MonalWrapperModels.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MonalWrapperModels.swift; sourceTree = ""; }; 29250DA62DD2322383585B2B /* Pods_MonalUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_MonalUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 2B7A5555D807EE78C95217FD /* Pods_NotificationService.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_NotificationService.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1409,7 +1411,7 @@ name = tools; sourceTree = ""; }; - 29B97314FDCFA39411CA2CEA /* CustomTemplate */ = { + 29B97314FDCFA39411CA2CEA = { isa = PBXGroup; children = ( 8414ADF92A7ABAC900EFFCCC /* Packages */, @@ -1499,6 +1501,7 @@ children = ( 7E6AF38E2CEB9110004328B5 /* MonalXmppWrapper.swift */, 404FB187FD6CB3DD41DAC820 /* AimErrors.swift */, + 282FE922A600668B10016B4C /* MonalWrapperModels.swift */, ); path = XMPP; sourceTree = ""; @@ -2061,7 +2064,7 @@ eu, "es-AR", ); - mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */; + mainGroup = 29B97314FDCFA39411CA2CEA; packageReferences = ( C1F5C7AD2777638B0001F295 /* XCRemoteSwiftPackageReference "swift-collections" */, 841898A82957712000FEC77D /* XCRemoteSwiftPackageReference "ViewExtractor" */, @@ -2656,6 +2659,7 @@ C11E557980B75AA90738EC9C /* LoginScreen.swift in Sources */, 1C8760F8FB99C27D0C3A6ED1 /* RegistrationScreen.swift in Sources */, 1767C5109B06AA6FDCD990E6 /* AimErrors.swift in Sources */, + 598A717356906687AD101542 /* MonalWrapperModels.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Monal/another.im/Views/Enter/LoginScreen.swift b/Monal/another.im/Views/Enter/LoginScreen.swift index 315207b..01604ac 100644 --- a/Monal/another.im/Views/Enter/LoginScreen.swift +++ b/Monal/another.im/Views/Enter/LoginScreen.swift @@ -99,7 +99,6 @@ struct LoginScreen: View { private func tryLogin() async { do { try await wrapper.tryLogin(jidStr, pass) - wrapper.accountsAvailability = .someEnabled } catch { router.showAlert( .alert, diff --git a/Monal/another.im/Views/Main/Contacts/ContactsScreen.swift b/Monal/another.im/Views/Main/Contacts/ContactsScreen.swift index 8ad28e2..8908fae 100644 --- a/Monal/another.im/Views/Main/Contacts/ContactsScreen.swift +++ b/Monal/another.im/Views/Main/Contacts/ContactsScreen.swift @@ -147,8 +147,8 @@ private struct ContactsScreenRow: View { router.dismissModal() } - //var roster = roster - //try? await roster.setLocallyDeleted(true) + // var roster = roster + // try? await roster.setLocallyDeleted(true) } private func deleteCompletely() async { diff --git a/Monal/another.im/Views/Main/MainTabScreen.swift b/Monal/another.im/Views/Main/MainTabScreen.swift index 0a21cd5..1e968ea 100644 --- a/Monal/another.im/Views/Main/MainTabScreen.swift +++ b/Monal/another.im/Views/Main/MainTabScreen.swift @@ -40,9 +40,6 @@ struct MainTabScreen: View { TabBar(selectedTab: $selectedTab) } } - .onLoad { - wrapper.reconnectAll() - } } } diff --git a/Monal/another.im/XMPP/MonalWrapperModels.swift b/Monal/another.im/XMPP/MonalWrapperModels.swift new file mode 100644 index 0000000..5198c21 --- /dev/null +++ b/Monal/another.im/XMPP/MonalWrapperModels.swift @@ -0,0 +1,39 @@ +import Foundation + +enum AccountsAvailability { + case noAccounts + case allDisabled + case someEnabled +} + +struct Account: Identifiable { + let id: Int + let local: String + let domain: String + let resource: String + let isEnabled: Bool + + var jid: String { + "\(local)@\(domain)" + } + + init?(_ dict: NSDictionary) { + guard let id = dict.value(forKey: "account_id") as? Int else { return nil } + guard let local = dict.value(forKey: "username") as? String else { return nil } + guard let domain = dict.value(forKey: "domain") as? String else { return nil } + guard let resource = dict.value(forKey: "resource") as? String else { return nil } + guard let isEnabled = dict.value(forKey: "enabled") as? Bool else { return nil } + + self.id = id + self.local = local + self.domain = domain + self.resource = resource + self.isEnabled = isEnabled + } +} + +struct Contact: Identifiable { + let jid: String + + var id: String { jid } +} diff --git a/Monal/another.im/XMPP/MonalXmppWrapper.swift b/Monal/another.im/XMPP/MonalXmppWrapper.swift index 27ee148..14d72bd 100644 --- a/Monal/another.im/XMPP/MonalXmppWrapper.swift +++ b/Monal/another.im/XMPP/MonalXmppWrapper.swift @@ -1,18 +1,17 @@ import Foundation import monalxmpp -enum AccountsAvailability { - case noAccounts - case allDisabled - case someEnabled -} - final class MonalXmppWrapper: ObservableObject { - @Published var accountsAvailability: AccountsAvailability = .noAccounts + @Published private(set) var accountsAvailability: AccountsAvailability = .noAccounts + @Published private(set) var accounts: [Account] = [] + @Published private(set) var contacts: [Contact] = [] private let xmpp: MLXMPPManager private let db: DataLayer + private var notificationObservers: [AnyObject] = [] + private var isInitialized: Bool = false + init() { // here is some inits (just for now) MLProcessLock.initialize(forProcess: "MainApp") @@ -21,7 +20,13 @@ final class MonalXmppWrapper: ObservableObject { xmpp = MLXMPPManager.sharedInstance() db = DataLayer.sharedInstance() - checkAccountsOnLoad() + // subscribe to monalxmpp notifications and fire notification for update + subscribeToUpdates() + NotificationCenter.default.post(name: Notification.Name(kMonalRefresh), object: nil) + } + + deinit { + notificationObservers.forEach { NotificationCenter.default.removeObserver($0) } } // try login @@ -30,27 +35,8 @@ final class MonalXmppWrapper: ObservableObject { let result = await loginObject.tryLogin(login, password) if !result { throw AimErrors.loginError - } - } - - func reconnectAll() { - xmpp.reconnectAll() - } -} - -// MARK: - Accounts -private extension MonalXmppWrapper { - // Check accounts state on launch - func checkAccountsOnLoad() { - let enabledAcocunts = db.enabledAccountList() - let allAccounts = db.accountList() - - if allAccounts.isEmpty { - accountsAvailability = .noAccounts - } else if !enabledAcocunts.isEmpty { - accountsAvailability = .someEnabled } else { - accountsAvailability = .allDisabled + NotificationCenter.default.post(name: Notification.Name(kMonalRefresh), object: nil) } } } @@ -98,3 +84,37 @@ private final class LoginTry { return result } } + +// MARK: - Handle notifications +private extension MonalXmppWrapper { + func subscribeToUpdates() { + let generalRefresh = NotificationCenter.default.addObserver(forName: Notification.Name(kMonalRefresh), object: nil, queue: .main) { [weak self] _ in + // get accounts + let accounts = self?.db.accountList() + .compactMap { dict -> Account? in + guard let dict = dict as? NSDictionary else { return nil } + return Account(dict) + } ?? [] + self?.accounts = accounts + + // start connect if it initialization process + if !(self?.isInitialized ?? true) { + self?.xmpp.reconnectAll() + self?.isInitialized = true + } + + // mark accounts availability + if accounts.isEmpty { + self?.accountsAvailability = .noAccounts + } else if !accounts.filter({ $0.isEnabled }).isEmpty { + self?.accountsAvailability = .allDisabled + } else { + self?.accountsAvailability = .someEnabled + } + + // get contacts for active accounts + // + } + notificationObservers.append(generalRefresh) + } +}