diff --git a/Nynja-Share/Resources/Info.plist b/Nynja-Share/Resources/Info.plist index 30f12f746f2c2e806e56839f3039f857c5a10b28..d2339858328ceb466669ed8633cd6161010fadbd 100644 --- a/Nynja-Share/Resources/Info.plist +++ b/Nynja-Share/Resources/Info.plist @@ -19,9 +19,9 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 1.0 + 0.8.0 CFBundleVersion - 0.5.5 + 0.8.3 Config $(Config) ModelsVersion diff --git a/Nynja-Share/Services/Handlers/ProfileHandler.swift b/Nynja-Share/Services/Handlers/ProfileHandler.swift index 2000956368165f8817ba5d530754e0585f79cdbf..faceba4a8ff24979b1aa15ce1ad34473eec87fe5 100644 --- a/Nynja-Share/Services/Handlers/ProfileHandler.swift +++ b/Nynja-Share/Services/Handlers/ProfileHandler.swift @@ -10,33 +10,26 @@ import Foundation protocol ProfileHandlerDelegate: class { func getProfileSuccess(model: Profile) - func removeProfileSuccess() } extension ProfileHandlerDelegate { func getProfileSuccess(model: Profile) {} - func removeProfileSuccess() {} } class ProfileHandler:BaseHandler { static weak var delegate :ProfileHandlerDelegate? static func executeHandle(data: BertTuple) { - if let profile = get_Profile().parse(bert: data) as? Profile { - if let status = profile.status?.string { - switch status { - case "get", "init": - self.delegate?.getProfileSuccess(model: profile) - case "set": - break - case "remove": - self.delegate?.removeProfileSuccess() - MQTTService.sharedInstance.reconnect() - default: - break - } - } + guard let profile = get_Profile().parse(bert: data) as? Profile, + let status = profile.status?.string else { + return + } + + switch status { + case "get", "init": + self.delegate?.getProfileSuccess(model: profile) + default: + break } } - } diff --git a/Nynja-Share/UI/ForwardSelector/Interactor/ForwardSelectorInteractor.swift b/Nynja-Share/UI/ForwardSelector/Interactor/ForwardSelectorInteractor.swift index 7acf73a6eab73649e44176aec01d0832447bfd16..cc538af190cdc8206bbb4a717b39875721704842 100644 --- a/Nynja-Share/UI/ForwardSelector/Interactor/ForwardSelectorInteractor.swift +++ b/Nynja-Share/UI/ForwardSelector/Interactor/ForwardSelectorInteractor.swift @@ -93,7 +93,7 @@ final class ForwardSelectorInteractor: ForwardSelectorInteractorInputProtocol, P func connectToServer() { if let token = StorageService.sharedInstance.token { LogService.log(topic: .MQTT) { return "token: \(token)" } - _ = MQTTService.sharedInstance.reconnect() + MQTTService.sharedInstance.connect() } else { handlerServerSignals?(.noToken) } @@ -353,7 +353,10 @@ final class ForwardSelectorInteractor: ForwardSelectorInteractorInputProtocol, P guard message.from == StorageService.sharedInstance.phoneId else { return } - handlerSuccess?() + dispatchAsyncMain { [weak self] in + self?.handlerSuccess?() + } + } @@ -365,7 +368,9 @@ final class ForwardSelectorInteractor: ForwardSelectorInteractorInputProtocol, P return } roster = myRoster - presenter.updateByState() + dispatchAsyncMain { [weak self] in + self?.presenter.updateByState() + } } @@ -374,13 +379,17 @@ final class ForwardSelectorInteractor: ForwardSelectorInteractorInputProtocol, P func didReceiveUpdatedContact(contact: Contact) { if [.ban, .banned].contains(contact.originalStatus) { contacts = contacts?.filter{ $0.content.contact?.phoneId != contact.phoneId } - presenter.updateContactsIfNeeded() + dispatchAsyncMain { [weak self] in + self?.presenter.updateContactsIfNeeded() + } } else if contact.originalStatus == .friend { if !(contacts?.contains(where: { $0.content.contact?.phoneId == contact.phoneId }) ?? false) { let target = makeForwardTarget(with: contact) contacts?.append(target) contacts = contacts?.sorted(by: sortComparator) - presenter.updateContactsIfNeeded() + dispatchAsyncMain { [weak self] in + self?.presenter.updateContactsIfNeeded() + } } } } @@ -389,11 +398,15 @@ final class ForwardSelectorInteractor: ForwardSelectorInteractorInputProtocol, P // MARK: IoHandlerDelegate func sessionNotFound() { - handlerServerSignals?(.sessionNotFound) + dispatchAsyncMain { [weak self] in + self?.handlerServerSignals?(.sessionNotFound) + } } func mismatchUserData() { - handlerServerSignals?(.mismatchUserData) + dispatchAsyncMain { [weak self] in + self?.handlerServerSignals?(.mismatchUserData) + } } diff --git a/Nynja.xcodeproj/project.pbxproj b/Nynja.xcodeproj/project.pbxproj index a572cf8e3c38e1a0b1ef134030e2afb0b160bd62..49a45dfbfb16b2263a7069cc611bede959a69e11 100644 --- a/Nynja.xcodeproj/project.pbxproj +++ b/Nynja.xcodeproj/project.pbxproj @@ -57,7 +57,7 @@ 00E86469204D519600844FF1 /* LanguageSettingsItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00E86468204D519600844FF1 /* LanguageSettingsItemsFactory.swift */; }; 00E8646D204D788100844FF1 /* LanguageSettingsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00E8646C204D788100844FF1 /* LanguageSettingsCell.swift */; }; 00E864702052B1BE00844FF1 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 00E864722052B1BE00844FF1 /* InfoPlist.strings */; }; - 00E9824C205C1E19008BF03D /* SecurityItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00E9824B205C1E19008BF03D /* SecurityItemsFactory.swift */; }; + 00E9824C205C1E19008BF03D /* ActiveSessionsItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00E9824B205C1E19008BF03D /* ActiveSessionsItemsFactory.swift */; }; 00E9824E205C2604008BF03D /* SessionItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00E9824D205C2604008BF03D /* SessionItemView.swift */; }; 00E98250205C2668008BF03D /* SessionHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00E9824F205C2668008BF03D /* SessionHeaderView.swift */; }; 00E98252205C26F7008BF03D /* SessionLineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00E98251205C26F7008BF03D /* SessionLineView.swift */; }; @@ -440,10 +440,10 @@ 2B924FFB43474DF387A06D67 /* VideoPreviewPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F0193413D570F0548B2E55F /* VideoPreviewPresenter.swift */; }; 2BE42DBEDF331A9C7E6FCBE1 /* TopUpAccountViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F1F219FC7966064C555AC2A4 /* TopUpAccountViewController.swift */; }; 2C95C06FF47CF32C3B35FF4F /* TutorialInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0557EB8B6354410A900A9A7A /* TutorialInteractor.swift */; }; - 2CB54DD94DA23D7160F36472 /* SecurityWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48276F2EE408C27334B2894C /* SecurityWireframe.swift */; }; + 2CB54DD94DA23D7160F36472 /* ActiveSessionsWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48276F2EE408C27334B2894C /* ActiveSessionsWireframe.swift */; }; 2F2A5C12A7202E7834F923DC /* GroupRulesWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 520422E90094C6C267AECE7E /* GroupRulesWireframe.swift */; }; 2F7C7F7837BDE6F5767A3A8C /* GroupStorageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D1D5302025583482829BBF2E /* GroupStorageViewController.swift */; }; - 3219C8F242591BA17953FF33 /* SecurityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F509C0C8B9C738DBC7ABE07 /* SecurityViewController.swift */; }; + 3219C8F242591BA17953FF33 /* ActiveSessionsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F509C0C8B9C738DBC7ABE07 /* ActiveSessionsViewController.swift */; }; 32868DD51F31CADF0028B260 /* ChatsListProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32868DD41F31CADF0028B260 /* ChatsListProtocols.swift */; }; 32868DDB1F31CB500028B260 /* ChatsListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32868DDA1F31CB500028B260 /* ChatsListViewController.swift */; }; 32868DDD1F31CB5D0028B260 /* ChatsListPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 32868DDC1F31CB5D0028B260 /* ChatsListPresenter.swift */; }; @@ -572,9 +572,13 @@ 4B0CC1FE2195B52000E0BA61 /* IoHandlerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0CC1FC2195B52000E0BA61 /* IoHandlerDelegate.swift */; }; 4B0CC1FF2195B58000E0BA61 /* StaticDelegating.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B87717C2195AFF50014AD09 /* StaticDelegating.swift */; }; 4B0CC2022195B69900E0BA61 /* LinkHandlerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B0CC2012195B69900E0BA61 /* LinkHandlerDelegate.swift */; }; + 4B1162FA21BFC1FB003859ED /* AppLifecycleConnectionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B483AAD21BEB0D900FCF879 /* AppLifecycleConnectionHandler.swift */; }; + 4B1162FC21BFC1FB003859ED /* AutoReconnectConnectionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B483AB121BEB42600FCF879 /* AutoReconnectConnectionHandler.swift */; }; + 4B1162FD21BFC1FB003859ED /* ReachabilityConnectionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B483AB321BEB8B100FCF879 /* ReachabilityConnectionHandler.swift */; }; + 4B1162FE21BFC1FB003859ED /* TokenConnectionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B483AB721BEC1C600FCF879 /* TokenConnectionHandler.swift */; }; + 4B1162FF21BFC213003859ED /* AppNotificationsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B71AC4121622A6A00E4583B /* AppNotificationsProvider.swift */; }; + 4B11630121BFC277003859ED /* AppNotificationsProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B71AC4421622AA700E4583B /* AppNotificationsProviding.swift */; }; 4B1D7DFA2029BF3400703228 /* HistoryItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1D7DF92029BF3400703228 /* HistoryItemsFactory.swift */; }; - 4B1D7DFC2029C37900703228 /* FavoritesItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1D7DFB2029C37900703228 /* FavoritesItemsFactory.swift */; }; - 4B1D7DFE2029C41C00703228 /* AboutItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1D7DFD2029C41C00703228 /* AboutItemsFactory.swift */; }; 4B1D7E012029C4BE00703228 /* OptionsItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1D7E002029C4BE00703228 /* OptionsItemsFactory.swift */; }; 4B1D7E032029C80800703228 /* ByContactsItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1D7E022029C80800703228 /* ByContactsItemsFactory.swift */; }; 4B1D7E052029CF2900703228 /* ShareContactsItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B1D7E042029CF2900703228 /* ShareContactsItemsFactory.swift */; }; @@ -618,6 +622,15 @@ 4B4266BF204D916000194BC1 /* ActionsView+Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4266BE204D916000194BC1 /* ActionsView+Action.swift */; }; 4B4266C1204D917800194BC1 /* ActionsView+Layout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4266C0204D917800194BC1 /* ActionsView+Layout.swift */; }; 4B4266C3204D923400194BC1 /* Array+UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B4266C2204D923400194BC1 /* Array+UIView.swift */; }; + 4B483AAC21BEB0A900FCF879 /* MQTTConnectionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B483AAB21BEB0A900FCF879 /* MQTTConnectionHandler.swift */; }; + 4B483AAE21BEB0D900FCF879 /* AppLifecycleConnectionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B483AAD21BEB0D900FCF879 /* AppLifecycleConnectionHandler.swift */; }; + 4B483AB021BEB1D000FCF879 /* AppGroupConnectionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B483AAF21BEB1D000FCF879 /* AppGroupConnectionHandler.swift */; }; + 4B483AB221BEB42600FCF879 /* AutoReconnectConnectionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B483AB121BEB42600FCF879 /* AutoReconnectConnectionHandler.swift */; }; + 4B483AB421BEB8B100FCF879 /* ReachabilityConnectionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B483AB321BEB8B100FCF879 /* ReachabilityConnectionHandler.swift */; }; + 4B483AB621BEC0C100FCF879 /* UserIdentifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B483AB521BEC0C100FCF879 /* UserIdentifiers.swift */; }; + 4B483AB821BEC1C600FCF879 /* TokenConnectionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B483AB721BEC1C600FCF879 /* TokenConnectionHandler.swift */; }; + 4B483AB921BEC84200FCF879 /* UserIdentifiers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B483AB521BEC0C100FCF879 /* UserIdentifiers.swift */; }; + 4B483ABA21BED06A00FCF879 /* MQTTConnectionHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B483AAB21BEB0A900FCF879 /* MQTTConnectionHandler.swift */; }; 4B5A0B73216E3BDD002C4160 /* ActionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5A0B6F216E3BDD002C4160 /* ActionsView.swift */; }; 4B5A0B74216E3BDD002C4160 /* ForwardAvatarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5A0B70216E3BDD002C4160 /* ForwardAvatarViewModel.swift */; }; 4B5A0B75216E3BDD002C4160 /* ProgressHUD.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B5A0B71216E3BDD002C4160 /* ProgressHUD.swift */; }; @@ -655,6 +668,7 @@ 4B752B5E2163A4F900E852B9 /* GApiResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 00E8513A2021E96E007DC792 /* GApiResponse.swift */; }; 4B752B612163A5C900E852B9 /* DescExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B752B602163A5C900E852B9 /* DescExtension.swift */; }; 4B752B652163A64300E852B9 /* Desc+Place.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B752B642163A64300E852B9 /* Desc+Place.swift */; }; + 4B78E30421C3F7BB001B2F0E /* CallsItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B78E30321C3F7BB001B2F0E /* CallsItemsFactory.swift */; }; 4B7B81C62044790700C2EFCF /* TimeZoneLocal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B7B81C52044790700C2EFCF /* TimeZoneLocal.swift */; }; 4B7C73F0215A5509007924DB /* SMSCodeProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B7C73E9215A5508007924DB /* SMSCodeProvider.swift */; }; 4B7C73F1215A5509007924DB /* SMSCodeProviding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B7C73EA215A5508007924DB /* SMSCodeProviding.swift */; }; @@ -726,6 +740,12 @@ 4BBAEBCE21AE9F790089B703 /* ValidatorFactoryImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBAEBCD21AE9F790089B703 /* ValidatorFactoryImpl.swift */; }; 4BBAEBD021AE9F9D0089B703 /* ValidatorFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BBAEBCF21AE9F9D0089B703 /* ValidatorFactory.swift */; }; 4BC8B38D2191AC360086DC6C /* ContactsProvidingFetchingArgs.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC8B38C2191AC360086DC6C /* ContactsProvidingFetchingArgs.swift */; }; + 4BC95A7721C0077100B462AC /* LocalizableConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC95A7621C0077000B462AC /* LocalizableConstants.swift */; }; + 4BC95A7821C0077100B462AC /* LocalizableConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC95A7621C0077000B462AC /* LocalizableConstants.swift */; }; + 4BC95A7921C0077100B462AC /* LocalizableConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC95A7621C0077000B462AC /* LocalizableConstants.swift */; }; + 4BC95A7A21C0077100B462AC /* LocalizableConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC95A7621C0077000B462AC /* LocalizableConstants.swift */; }; + 4BC95A8021C1224100B462AC /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC95A7F21C1224100B462AC /* FeatureFlags.swift */; }; + 4BC95A8121C1246800B462AC /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BC95A7F21C1224100B462AC /* FeatureFlags.swift */; }; 4BD53BF4202C8BCA00569C1A /* AVURLAsset+Duration.swift in Sources */ = {isa = PBXBuildFile; fileRef = E77FBDDC1FFE828400BDB255 /* AVURLAsset+Duration.swift */; }; 4BDC7E61203492CA00BCD381 /* TopSwipable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC7E60203492CA00BCD381 /* TopSwipable.swift */; }; 4BDC7E63203494C000BCD381 /* ScheduleButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BDC7E62203494C000BCD381 /* ScheduleButton.swift */; }; @@ -742,6 +762,11 @@ 4BE2C5E72142EB5A00A73DD9 /* NynjaCommunicatorService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE2C5E52142EB5A00A73DD9 /* NynjaCommunicatorService.swift */; }; 4BE2C5E82142EB5A00A73DD9 /* NynjaRingingService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BE2C5E62142EB5A00A73DD9 /* NynjaRingingService.swift */; }; 4BEE89D69CACB85ABEE9046F /* QRCodeGeneratorPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = DFAB7D8D9024C26FA51BF783 /* QRCodeGeneratorPresenter.swift */; }; + 4BEF0F6521C265F40012B6E1 /* CommingSoonWheelItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF0F6421C265F40012B6E1 /* CommingSoonWheelItemModel.swift */; }; + 4BEF0F6821C28FC70012B6E1 /* FavoritesMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF0F6721C28FC70012B6E1 /* FavoritesMode.swift */; }; + 4BEF0F6C21C290A10012B6E1 /* FavoritesP2pItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF0F6B21C290A10012B6E1 /* FavoritesP2pItemsFactory.swift */; }; + 4BEF0F6E21C290B10012B6E1 /* FavoritesGroupItemsFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF0F6D21C290B10012B6E1 /* FavoritesGroupItemsFactory.swift */; }; + 4BEF0F6F21C294A40012B6E1 /* FavoritesMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BEF0F6721C28FC70012B6E1 /* FavoritesMode.swift */; }; 4BF090B921635B4700DCCA5C /* LogServiceProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF090B821635B4700DCCA5C /* LogServiceProtocol.swift */; }; 4BF090BB21635B6600DCCA5C /* LogServiceTopic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF090BA21635B6600DCCA5C /* LogServiceTopic.swift */; }; 4BF090BC21635B8000DCCA5C /* LogServiceTopic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF090BA21635B6600DCCA5C /* LogServiceTopic.swift */; }; @@ -768,6 +793,7 @@ 4BF2C3FD218AFF6300E59F6C /* FullNameRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BF2C3FB218AFE9D00E59F6C /* FullNameRepresentable.swift */; }; 4BFED75A21A6BE49003CF1B3 /* CLLocation+GPSMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BFED75921A6BE49003CF1B3 /* CLLocation+GPSMetadata.swift */; }; 4BFED75D21A6CE38003CF1B3 /* ExtendedImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BFED75C21A6CE38003CF1B3 /* ExtendedImage.swift */; }; + 4BFF6C8221C84B6A00BB9432 /* DBUnreadInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4BFF6C8121C84B6A00BB9432 /* DBUnreadInfo.swift */; }; 4C5EEA13EBC6A8398F08DCD1 /* MainWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 65AAB8F770774CE3AE3FD6E1 /* MainWireframe.swift */; }; 4D53FE7454959323B1CCFD96 /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D270F638DBB2D8FC1BDEB633 /* ProfileViewController.swift */; }; 4DAEBCF361B86B0AD3C98749 /* EditUsernameInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBE3BAC9B7EA418FB463EF04 /* EditUsernameInteractor.swift */; }; @@ -1188,7 +1214,7 @@ 8E23E086200614AB00A59B8C /* GroupVideosCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E23E085200614AB00A59B8C /* GroupVideosCell.swift */; }; 8E23E0882006853000A59B8C /* GroupVideosListVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E23E0872006852F00A59B8C /* GroupVideosListVC.swift */; }; 8E47DBEB200EB05900E612B0 /* MapViewControllerLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E47DBEA200EB05900E612B0 /* MapViewControllerLayout.swift */; }; - 8E54E93EA25B11D417A6100E /* SecurityInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45739CD40D10B2FD5E35E0C0 /* SecurityInteractor.swift */; }; + 8E54E93EA25B11D417A6100E /* ActiveSessionsInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45739CD40D10B2FD5E35E0C0 /* ActiveSessionsInteractor.swift */; }; 8E55172E200D095B00C12B5D /* UserGroupRulesVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E55172D200D095B00C12B5D /* UserGroupRulesVC.swift */; }; 8E551730200D202B00C12B5D /* AdminGroupRulesVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E55172F200D202B00C12B5D /* AdminGroupRulesVC.swift */; }; 8E6C4BDE1FF40B97009C8374 /* GroupFilesCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8E6C4BDD1FF40B97009C8374 /* GroupFilesCell.swift */; }; @@ -1887,7 +1913,7 @@ C493782D4488E45CB1D67DE4 /* CreateGroupViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7C2CBB5F32D209160D00F744 /* CreateGroupViewController.swift */; }; C4AE8B6EFD76A8C6ADF51422 /* TutorialProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95853EBE3A525E3069F4637 /* TutorialProtocols.swift */; }; C52453F5FF7E703BE0E7561C /* AddContactByUsernameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 549BC324D11F1DDF87DAAEB7 /* AddContactByUsernameViewController.swift */; }; - C6B308C6734EFB77892832A0 /* SecurityPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 762BA232B5D027BD943DFA18 /* SecurityPresenter.swift */; }; + C6B308C6734EFB77892832A0 /* ActiveSessionsPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 762BA232B5D027BD943DFA18 /* ActiveSessionsPresenter.swift */; }; C8C6310F83825D7385C3A6E4 /* MapProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = EE2260535ED2762F80FA7A38 /* MapProtocols.swift */; }; C90E6A9B20558C0300D733E0 /* FileSizeFormatter.swift in Sources */ = {isa = PBXBuildFile; fileRef = C90E6A9A20558C0300D733E0 /* FileSizeFormatter.swift */; }; C90EE13E20246E2700FDB873 /* SelctCountryDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C90EE13D20246E2700FDB873 /* SelctCountryDelegate.swift */; }; @@ -2071,7 +2097,7 @@ E7F2CFE21F5EEF1E00806E43 /* PermissionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7F2CFE11F5EEF1E00806E43 /* PermissionManager.swift */; }; E7F68D271FA22C45009C98D1 /* EditProfileVCStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7F68D261FA22C45009C98D1 /* EditProfileVCStrings.swift */; }; E7F8F55C1F7BCA090016FDF9 /* DefaultWheelConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = E7F8F55B1F7BCA090016FDF9 /* DefaultWheelConfiguration.swift */; }; - E8AFC57E49EED25C3F5001B7 /* SecurityProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2144825E69D46CE96C0B7D8 /* SecurityProtocols.swift */; }; + E8AFC57E49EED25C3F5001B7 /* ActiveSessionsProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = C2144825E69D46CE96C0B7D8 /* ActiveSessionsProtocols.swift */; }; EA7ABD1C9C761A1F58D89F8A /* AddParticipantsWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = AD5E1768DC8E5A8BB9BBDD96 /* AddParticipantsWireframe.swift */; }; EA9F305BF0215CAC3602D0D9 /* EditGroupPhotoPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D5A57913B84E0665E3ABC0E /* EditGroupPhotoPresenter.swift */; }; F0839BACB1A52FCF846584D4 /* EditProfileWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = AE19B8A785E7FA17723F4D85 /* EditProfileWireframe.swift */; }; @@ -2086,7 +2112,6 @@ F105C6BC20A1347E0091786A /* PhotoPreviewWireframeProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F105C6B520A1347E0091786A /* PhotoPreviewWireframeProtocol.swift */; }; F105C6BD20A1347E0091786A /* PhotoPreviewViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = F105C6B720A1347E0091786A /* PhotoPreviewViewController.swift */; }; F105C6BE20A1347E0091786A /* PhotoPreviewInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = F105C6B920A1347E0091786A /* PhotoPreviewInteractor.swift */; }; - F10AFE9B20EF8B9B00C7CE83 /* DevAutoTests.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = F10AFE9A20EF8B9A00C7CE83 /* DevAutoTests.xcconfig */; }; F10AFEB420F7B1B000C7CE83 /* WheelPreviewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = F10AFEAE20F7B1AF00C7CE83 /* WheelPreviewProtocol.swift */; }; F10AFEB520F7B1B000C7CE83 /* WheelDefaultItemPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = F10AFEAF20F7B1AF00C7CE83 /* WheelDefaultItemPreview.swift */; }; F10AFEB620F7B1B000C7CE83 /* WheelImageFullItemPreview.swift in Sources */ = {isa = PBXBuildFile; fileRef = F10AFEB020F7B1AF00C7CE83 /* WheelImageFullItemPreview.swift */; }; @@ -2198,9 +2223,6 @@ FB61D64D214FEC7D00CB2A1F /* FontsConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD885752147F9640099B8C3 /* FontsConstants.swift */; }; FB61D64E214FEC7D00CB2A1F /* FontsConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD885752147F9640099B8C3 /* FontsConstants.swift */; }; FB61D64F214FEC7E00CB2A1F /* FontsConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD885752147F9640099B8C3 /* FontsConstants.swift */; }; - FB61D650214FEC8200CB2A1F /* LocalizableConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD885762147F9640099B8C3 /* LocalizableConstants.swift */; }; - FB61D651214FEC8200CB2A1F /* LocalizableConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD885762147F9640099B8C3 /* LocalizableConstants.swift */; }; - FB61D652214FEC8300CB2A1F /* LocalizableConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD885762147F9640099B8C3 /* LocalizableConstants.swift */; }; FB61D653214FEC8500CB2A1F /* AssetsConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD885772147F9640099B8C3 /* AssetsConstants.swift */; }; FB61D654214FEC8600CB2A1F /* AssetsConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD885772147F9640099B8C3 /* AssetsConstants.swift */; }; FB61D655214FEC8600CB2A1F /* AssetsConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD885772147F9640099B8C3 /* AssetsConstants.swift */; }; @@ -2234,7 +2256,6 @@ FBCE841420E525A6003B7558 /* NetworkService.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBCE840420E525A5003B7558 /* NetworkService.swift */; }; FBCE841520E525A6003B7558 /* URLRequestConvertible.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBCE840520E525A5003B7558 /* URLRequestConvertible.swift */; }; FBD885782147F9640099B8C3 /* FontsConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD885752147F9640099B8C3 /* FontsConstants.swift */; }; - FBD885792147F9640099B8C3 /* LocalizableConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD885762147F9640099B8C3 /* LocalizableConstants.swift */; }; FBD8857A2147F9640099B8C3 /* AssetsConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBD885772147F9640099B8C3 /* AssetsConstants.swift */; }; FBDA34E920921079009F4FB6 /* KeyboardLayoutGuide.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBDA34E820921079009F4FB6 /* KeyboardLayoutGuide.swift */; }; FBE3885D2118849000149721 /* AlertActionWrapper.swift in Sources */ = {isa = PBXBuildFile; fileRef = FBE3885C2118849000149721 /* AlertActionWrapper.swift */; }; @@ -2466,7 +2487,7 @@ 00E86468204D519600844FF1 /* LanguageSettingsItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageSettingsItemsFactory.swift; sourceTree = ""; }; 00E8646C204D788100844FF1 /* LanguageSettingsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguageSettingsCell.swift; sourceTree = ""; }; 00E864712052B1BE00844FF1 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; - 00E9824B205C1E19008BF03D /* SecurityItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SecurityItemsFactory.swift; sourceTree = ""; }; + 00E9824B205C1E19008BF03D /* ActiveSessionsItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActiveSessionsItemsFactory.swift; sourceTree = ""; }; 00E9824D205C2604008BF03D /* SessionItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionItemView.swift; sourceTree = ""; }; 00E9824F205C2668008BF03D /* SessionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionHeaderView.swift; sourceTree = ""; }; 00E98251205C26F7008BF03D /* SessionLineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionLineView.swift; sourceTree = ""; }; @@ -2846,9 +2867,9 @@ 40444524B52370D471DC9141 /* EditGroupPhotoViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = EditGroupPhotoViewController.swift; sourceTree = ""; }; 4177485419FF2E8F7CF8FF98 /* EditPhotoPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = EditPhotoPresenter.swift; sourceTree = ""; }; 4489153750EAC34408B967C0 /* MapViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MapViewController.swift; sourceTree = ""; }; - 45739CD40D10B2FD5E35E0C0 /* SecurityInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SecurityInteractor.swift; sourceTree = ""; }; + 45739CD40D10B2FD5E35E0C0 /* ActiveSessionsInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ActiveSessionsInteractor.swift; sourceTree = ""; }; 462440AD41D807CE8957FDD9 /* FavoritesProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = FavoritesProtocols.swift; sourceTree = ""; }; - 48276F2EE408C27334B2894C /* SecurityWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SecurityWireframe.swift; sourceTree = ""; }; + 48276F2EE408C27334B2894C /* ActiveSessionsWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ActiveSessionsWireframe.swift; sourceTree = ""; }; 4948B03AEE34116DB6A7A06D /* ScheduleMessageProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ScheduleMessageProtocols.swift; sourceTree = ""; }; 498AA2E3A69072FEC336C1ED /* TopUpAccountInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TopUpAccountInteractor.swift; sourceTree = ""; }; 499373C9A81A05B77308A5F0 /* AddContactByUsernameProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AddContactByUsernameProtocols.swift; sourceTree = ""; }; @@ -2888,8 +2909,6 @@ 4B0CC2012195B69900E0BA61 /* LinkHandlerDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinkHandlerDelegate.swift; sourceTree = ""; }; 4B15A544CC681BABD1A631AF /* QRCodeGeneratorInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = QRCodeGeneratorInteractor.swift; sourceTree = ""; }; 4B1D7DF92029BF3400703228 /* HistoryItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryItemsFactory.swift; sourceTree = ""; }; - 4B1D7DFB2029C37900703228 /* FavoritesItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesItemsFactory.swift; sourceTree = ""; }; - 4B1D7DFD2029C41C00703228 /* AboutItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutItemsFactory.swift; sourceTree = ""; }; 4B1D7E002029C4BE00703228 /* OptionsItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OptionsItemsFactory.swift; sourceTree = ""; }; 4B1D7E022029C80800703228 /* ByContactsItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ByContactsItemsFactory.swift; sourceTree = ""; }; 4B1D7E042029CF2900703228 /* ShareContactsItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareContactsItemsFactory.swift; sourceTree = ""; }; @@ -2925,6 +2944,13 @@ 4B4266BE204D916000194BC1 /* ActionsView+Action.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ActionsView+Action.swift"; sourceTree = ""; }; 4B4266C0204D917800194BC1 /* ActionsView+Layout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ActionsView+Layout.swift"; sourceTree = ""; }; 4B4266C2204D923400194BC1 /* Array+UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+UIView.swift"; sourceTree = ""; }; + 4B483AAB21BEB0A900FCF879 /* MQTTConnectionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MQTTConnectionHandler.swift; sourceTree = ""; }; + 4B483AAD21BEB0D900FCF879 /* AppLifecycleConnectionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppLifecycleConnectionHandler.swift; sourceTree = ""; }; + 4B483AAF21BEB1D000FCF879 /* AppGroupConnectionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppGroupConnectionHandler.swift; sourceTree = ""; }; + 4B483AB121BEB42600FCF879 /* AutoReconnectConnectionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoReconnectConnectionHandler.swift; sourceTree = ""; }; + 4B483AB321BEB8B100FCF879 /* ReachabilityConnectionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReachabilityConnectionHandler.swift; sourceTree = ""; }; + 4B483AB521BEC0C100FCF879 /* UserIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserIdentifiers.swift; sourceTree = ""; }; + 4B483AB721BEC1C600FCF879 /* TokenConnectionHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenConnectionHandler.swift; sourceTree = ""; }; 4B5A0B6F216E3BDD002C4160 /* ActionsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionsView.swift; sourceTree = ""; }; 4B5A0B70216E3BDD002C4160 /* ForwardAvatarViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ForwardAvatarViewModel.swift; sourceTree = ""; }; 4B5A0B71216E3BDD002C4160 /* ProgressHUD.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProgressHUD.swift; sourceTree = ""; }; @@ -2958,6 +2984,7 @@ 4B752B502163A04800E852B9 /* Array+BaseChatCellModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+BaseChatCellModel.swift"; sourceTree = ""; }; 4B752B602163A5C900E852B9 /* DescExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DescExtension.swift; sourceTree = ""; }; 4B752B642163A64300E852B9 /* Desc+Place.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Desc+Place.swift"; sourceTree = ""; }; + 4B78E30321C3F7BB001B2F0E /* CallsItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallsItemsFactory.swift; sourceTree = ""; }; 4B7B81C52044790700C2EFCF /* TimeZoneLocal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeZoneLocal.swift; sourceTree = ""; }; 4B7C73E9215A5508007924DB /* SMSCodeProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMSCodeProvider.swift; sourceTree = ""; }; 4B7C73EA215A5508007924DB /* SMSCodeProviding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SMSCodeProviding.swift; sourceTree = ""; }; @@ -3020,6 +3047,8 @@ 4BBAEBCD21AE9F790089B703 /* ValidatorFactoryImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorFactoryImpl.swift; sourceTree = ""; }; 4BBAEBCF21AE9F9D0089B703 /* ValidatorFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ValidatorFactory.swift; sourceTree = ""; }; 4BC8B38C2191AC360086DC6C /* ContactsProvidingFetchingArgs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactsProvidingFetchingArgs.swift; sourceTree = ""; }; + 4BC95A7621C0077000B462AC /* LocalizableConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizableConstants.swift; sourceTree = ""; }; + 4BC95A7F21C1224100B462AC /* FeatureFlags.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeatureFlags.swift; sourceTree = ""; }; 4BDC7E60203492CA00BCD381 /* TopSwipable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopSwipable.swift; sourceTree = ""; }; 4BDC7E62203494C000BCD381 /* ScheduleButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScheduleButton.swift; sourceTree = ""; }; 4BDDAAE8218CA28300F775A7 /* HomeDataProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeDataProvider.swift; sourceTree = ""; }; @@ -3034,6 +3063,10 @@ 4BE2C5E12142EB0E00A73DD9 /* AudioManagerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioManagerDelegate.swift; sourceTree = ""; }; 4BE2C5E52142EB5A00A73DD9 /* NynjaCommunicatorService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NynjaCommunicatorService.swift; sourceTree = ""; }; 4BE2C5E62142EB5A00A73DD9 /* NynjaRingingService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NynjaRingingService.swift; sourceTree = ""; }; + 4BEF0F6421C265F40012B6E1 /* CommingSoonWheelItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CommingSoonWheelItemModel.swift; sourceTree = ""; }; + 4BEF0F6721C28FC70012B6E1 /* FavoritesMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesMode.swift; sourceTree = ""; }; + 4BEF0F6B21C290A10012B6E1 /* FavoritesP2pItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesP2pItemsFactory.swift; sourceTree = ""; }; + 4BEF0F6D21C290B10012B6E1 /* FavoritesGroupItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesGroupItemsFactory.swift; sourceTree = ""; }; 4BF090B821635B4700DCCA5C /* LogServiceProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogServiceProtocol.swift; sourceTree = ""; }; 4BF090BA21635B6600DCCA5C /* LogServiceTopic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogServiceTopic.swift; sourceTree = ""; }; 4BF090C421635E8600DCCA5C /* Message+LinkedId.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Message+LinkedId.swift"; sourceTree = ""; }; @@ -3044,6 +3077,7 @@ 4BF2C3FB218AFE9D00E59F6C /* FullNameRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FullNameRepresentable.swift; sourceTree = ""; }; 4BFED75921A6BE49003CF1B3 /* CLLocation+GPSMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CLLocation+GPSMetadata.swift"; sourceTree = ""; }; 4BFED75C21A6CE38003CF1B3 /* ExtendedImage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtendedImage.swift; sourceTree = ""; }; + 4BFF6C8121C84B6A00BB9432 /* DBUnreadInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBUnreadInfo.swift; sourceTree = ""; }; 4CDA2BE900351F21464CE687 /* DateTimePickerInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DateTimePickerInteractor.swift; sourceTree = ""; }; 4D247CBC45C1C1267BBBB289 /* QRCodeReaderInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = QRCodeReaderInteractor.swift; sourceTree = ""; }; 4F7C039B61A0663D43BE5AE5 /* SelectCountryProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SelectCountryProtocols.swift; sourceTree = ""; }; @@ -3074,7 +3108,7 @@ 5D3E868EE32625048BCB13A8 /* HistoryInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = HistoryInteractor.swift; sourceTree = ""; }; 5E0CEA9921490663004B3F7A /* TypingStatusCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypingStatusCache.swift; sourceTree = ""; }; 5EEA3D18EFB98D7959F993E4 /* AddParticipantsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AddParticipantsProtocols.swift; sourceTree = ""; }; - 5F509C0C8B9C738DBC7ABE07 /* SecurityViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SecurityViewController.swift; sourceTree = ""; }; + 5F509C0C8B9C738DBC7ABE07 /* ActiveSessionsViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ActiveSessionsViewController.swift; sourceTree = ""; }; 61B964D5CB991533BA5C164C /* HistoryPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = HistoryPresenter.swift; sourceTree = ""; }; 61CB12AA514912C6B8E4F670 /* Pods-Nynja.devautotests.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Nynja.devautotests.xcconfig"; path = "Pods/Target Support Files/Pods-Nynja/Pods-Nynja.devautotests.xcconfig"; sourceTree = ""; }; 628BB7CDB18FDAFAAB6FD17D /* EditGroupPhotoWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = EditGroupPhotoWireframe.swift; sourceTree = ""; }; @@ -3108,7 +3142,7 @@ 7154170549A4A686815BA4F0 /* SplashPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SplashPresenter.swift; sourceTree = ""; }; 718EF22D86A9656BB6ED89D5 /* Pods-Nynja.translate.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Nynja.translate.xcconfig"; path = "Pods/Target Support Files/Pods-Nynja/Pods-Nynja.translate.xcconfig"; sourceTree = ""; }; 7625A2CFF245BC8A47701724 /* AddParticipantsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AddParticipantsPresenter.swift; sourceTree = ""; }; - 762BA232B5D027BD943DFA18 /* SecurityPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SecurityPresenter.swift; sourceTree = ""; }; + 762BA232B5D027BD943DFA18 /* ActiveSessionsPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ActiveSessionsPresenter.swift; sourceTree = ""; }; 7ADCB0C891B31AF691307B4F /* Pods-Nynja.spotify.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Nynja.spotify.xcconfig"; path = "Pods/Target Support Files/Pods-Nynja/Pods-Nynja.spotify.xcconfig"; sourceTree = ""; }; 7C19AFE8E64821851F4112EE /* ProfileProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ProfileProtocols.swift; sourceTree = ""; }; 7C2CBB5F32D209160D00F744 /* CreateGroupViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CreateGroupViewController.swift; sourceTree = ""; }; @@ -3982,7 +4016,7 @@ B7F5051C2061252100C28FA1 /* DataAndStorageItemsFactory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataAndStorageItemsFactory.swift; sourceTree = ""; }; B9BA5392968EF1C9E844C927 /* AddParticipantsInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AddParticipantsInteractor.swift; sourceTree = ""; }; BD300AEDF58665DC0855B7F8 /* EditProfileViewController.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = EditProfileViewController.swift; sourceTree = ""; }; - C2144825E69D46CE96C0B7D8 /* SecurityProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SecurityProtocols.swift; sourceTree = ""; }; + C2144825E69D46CE96C0B7D8 /* ActiveSessionsProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ActiveSessionsProtocols.swift; sourceTree = ""; }; C22259D46BE5732B494C4C7D /* SplashWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SplashWireframe.swift; sourceTree = ""; }; C3E427A83589B2A635F99BC0 /* EditGroupPhotoProtocols.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = EditGroupPhotoProtocols.swift; sourceTree = ""; }; C45F64793E8126ABF4E69F7B /* QRCodeGeneratorWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = QRCodeGeneratorWireframe.swift; sourceTree = ""; }; @@ -4309,7 +4343,6 @@ FBCE840420E525A5003B7558 /* NetworkService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NetworkService.swift; sourceTree = ""; }; FBCE840520E525A5003B7558 /* URLRequestConvertible.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URLRequestConvertible.swift; sourceTree = ""; }; FBD885752147F9640099B8C3 /* FontsConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FontsConstants.swift; sourceTree = ""; }; - FBD885762147F9640099B8C3 /* LocalizableConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocalizableConstants.swift; sourceTree = ""; }; FBD885772147F9640099B8C3 /* AssetsConstants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AssetsConstants.swift; sourceTree = ""; }; FBDA34E820921079009F4FB6 /* KeyboardLayoutGuide.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyboardLayoutGuide.swift; sourceTree = ""; }; FBE3885C2118849000149721 /* AlertActionWrapper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertActionWrapper.swift; sourceTree = ""; }; @@ -4715,16 +4748,16 @@ path = Presenter; sourceTree = ""; }; - 173E53A365A073A0C8A259C6 /* Security */ = { + 173E53A365A073A0C8A259C6 /* ActiveSessions */ = { isa = PBXGroup; children = ( - C2144825E69D46CE96C0B7D8 /* SecurityProtocols.swift */, + C2144825E69D46CE96C0B7D8 /* ActiveSessionsProtocols.swift */, 8C67C8504942462464406A80 /* View */, EDEF587F75F23F688953AD44 /* Presenter */, 66937A3FE42A3A7C143B03DA /* Interactor */, A31F9E0E0E7FEA81D22A0ED7 /* WireFrame */, ); - path = Security; + path = ActiveSessions; sourceTree = ""; }; 18947FBBF486D31575BC5A8F /* View */ = { @@ -6051,7 +6084,6 @@ 3A768E1C1ECD152300108F7C /* Services */ = { isa = PBXGroup; children = ( - 4B2C502521B568FD00FBA9B1 /* MigrationManager */, 851769D420D584CA008ACF6B /* Amazon */, 26ABCA3D21189DA400EA4782 /* Aps.swift */, 4BE2C5CE2142EAC500A73DD9 /* Audio */, @@ -6067,6 +6099,7 @@ 26EA201120BECD6500FBB9CA /* ConversationLanguageSettingService */, 4B7C73E7215A5508007924DB /* Debug */, 26DCB255206924B3001EF0AB /* FeatureFactory.swift */, + 4BC95A7E21C1220D00B462AC /* FeatureFlags */, 26B5F7411FB0FF7B00CEC6AE /* FileManager.swift */, 8509FC832158F7B400734D93 /* Files */, 2625DBF720EFC5DE00E01C05 /* FourCharCode+StringLiteralConvertible.swift */, @@ -6081,6 +6114,7 @@ 26E3229120E4F18100271413 /* MessageParser */, E7EC77A21FD1B9BD00DC8245 /* MessageProcessing */, F11786D220A98D0A007A9A1B /* MessageSendingService */, + 4B2C502521B568FD00FBA9B1 /* MigrationManager */, 3AC321761EEAC4700068F3C8 /* Models */, 3A8045CC1F60C8E200AED866 /* MQTT */, A458FAC020EBA4D70075D55E /* MuteChatService */, @@ -6121,9 +6155,11 @@ 3A8045CC1F60C8E200AED866 /* MQTT */ = { isa = PBXGroup; children = ( - 4B030F392195CF7600F293B7 /* Entities */, 4B030F342195CD4A00F293B7 /* API */, + 4B483AAA21BEA80200FCF879 /* ConnectionHandlers */, + 4B030F392195CF7600F293B7 /* Entities */, 4B030F382195CDDA00F293B7 /* Extensions */, + 4B483AAB21BEB0A900FCF879 /* MQTTConnectionHandler.swift */, 3A8045CD1F60C8E200AED866 /* MQTTService.swift */, 4B030F312195CD4500F293B7 /* MQTTServiceDelegate.swift */, 4B055C3A219C4101001FE077 /* MQTTServiceProtocol.swift */, @@ -6646,14 +6682,14 @@ children = ( 4B06D3182028A66A003B275B /* Base */, A4494C7C2080F24300223B06 /* Channels */, - 4BFABA332028CD8800299EE7 /* Contacts */, - 4B06D3192028A675003B275B /* ChatsList */, 4B06D31A2028A690003B275B /* Chat */, - 4B1D7DFF2029C4A900703228 /* Options */, + 4B06D3192028A675003B275B /* ChatsList */, + 4BFABA332028CD8800299EE7 /* Contacts */, + B7F5051C2061252100C28FA1 /* DataAndStorageItemsFactory.swift */, 4B06D30B2028A25D003B275B /* HomeItemsFactory.swift */, - 4B1D7DFB2029C37900703228 /* FavoritesItemsFactory.swift */, + 4B1D7DFF2029C4A900703228 /* Options */, 4B1D7E062029D00000703228 /* OtherUserProfileItemsFactory.swift */, - B7F5051C2061252100C28FA1 /* DataAndStorageItemsFactory.swift */, + 4B78E30321C3F7BB001B2F0E /* CallsItemsFactory.swift */, ); name = Factory; sourceTree = ""; @@ -6671,9 +6707,11 @@ isa = PBXGroup; children = ( 4B06D30D2028A349003B275B /* ChatsItemsFactory.swift */, - 4B06D30F2028A472003B275B /* P2pChatsItemsFactory.swift */, - 4B06D3112028A4CF003B275B /* GroupChatsItemsFactory.swift */, 4B1D7E082029D86600703228 /* CreateGroupItemsFactory.swift */, + 4BEF0F6D21C290B10012B6E1 /* FavoritesGroupItemsFactory.swift */, + 4BEF0F6B21C290A10012B6E1 /* FavoritesP2pItemsFactory.swift */, + 4B06D3112028A4CF003B275B /* GroupChatsItemsFactory.swift */, + 4B06D30F2028A472003B275B /* P2pChatsItemsFactory.swift */, ); name = ChatsList; sourceTree = ""; @@ -6723,16 +6761,15 @@ 4B1D7DFF2029C4A900703228 /* Options */ = { isa = PBXGroup; children = ( + 00E9824B205C1E19008BF03D /* ActiveSessionsItemsFactory.swift */, + 85788C4D20443DD2003600C9 /* BuildNumberItemsFactory.swift */, 00E86468204D519600844FF1 /* LanguageSettingsItemsFactory.swift */, + 8503B52E20504904006F0593 /* NotificationSettingsItemsFactory.swift */, 4B1D7E002029C4BE00703228 /* OptionsItemsFactory.swift */, - 4B1D7DFD2029C41C00703228 /* AboutItemsFactory.swift */, - 85788C4D20443DD2003600C9 /* BuildNumberItemsFactory.swift */, - 00E9824B205C1E19008BF03D /* SecurityItemsFactory.swift */, - 85249D312045B1F800B43007 /* WheelPositionItemsFactory.swift */, - 8596CEF52048AEB8006FC65D /* ThemeItemsFactory.swift */, - 853FB06F2049B396000996C5 /* SupportItemsFactory.swift */, 850C3024204DAC1000DB26C2 /* PrivacyListItemsFactory.swift */, - 8503B52E20504904006F0593 /* NotificationSettingsItemsFactory.swift */, + 853FB06F2049B396000996C5 /* SupportItemsFactory.swift */, + 8596CEF52048AEB8006FC65D /* ThemeItemsFactory.swift */, + 85249D312045B1F800B43007 /* WheelPositionItemsFactory.swift */, ); name = Options; sourceTree = ""; @@ -6868,6 +6905,18 @@ path = ActionsView; sourceTree = ""; }; + 4B483AAA21BEA80200FCF879 /* ConnectionHandlers */ = { + isa = PBXGroup; + children = ( + 4B483AAD21BEB0D900FCF879 /* AppLifecycleConnectionHandler.swift */, + 4B483AAF21BEB1D000FCF879 /* AppGroupConnectionHandler.swift */, + 4B483AB121BEB42600FCF879 /* AutoReconnectConnectionHandler.swift */, + 4B483AB321BEB8B100FCF879 /* ReachabilityConnectionHandler.swift */, + 4B483AB721BEC1C600FCF879 /* TokenConnectionHandler.swift */, + ); + path = ConnectionHandlers; + sourceTree = ""; + }; 4B5A0B6E216E3BDD002C4160 /* Views */ = { isa = PBXGroup; children = ( @@ -7369,6 +7418,14 @@ name = Entity; sourceTree = ""; }; + 4BC95A7E21C1220D00B462AC /* FeatureFlags */ = { + isa = PBXGroup; + children = ( + 4BC95A7F21C1224100B462AC /* FeatureFlags.swift */, + ); + path = FeatureFlags; + sourceTree = ""; + }; 4BDDAAE7218CA27200F775A7 /* HomeDataProvider */ = { isa = PBXGroup; children = ( @@ -7446,6 +7503,14 @@ path = Services/NynjaCalls; sourceTree = ""; }; + 4BEF0F6621C28F740012B6E1 /* Entities */ = { + isa = PBXGroup; + children = ( + 4BEF0F6721C28FC70012B6E1 /* FavoritesMode.swift */, + ); + path = Entities; + sourceTree = ""; + }; 4BF090B721635B3700DCCA5C /* LogService */ = { isa = PBXGroup; children = ( @@ -7522,6 +7587,7 @@ 51D6048350255DBFEC3969A5 /* Favorites */ = { isa = PBXGroup; children = ( + 4BEF0F6621C28F740012B6E1 /* Entities */, 462440AD41D807CE8957FDD9 /* FavoritesProtocols.swift */, D07E02E41718EC43B68B94D0 /* View */, F53F982DD18212A69B499534 /* Presenter */, @@ -7676,7 +7742,7 @@ 66937A3FE42A3A7C143B03DA /* Interactor */ = { isa = PBXGroup; children = ( - 45739CD40D10B2FD5E35E0C0 /* SecurityInteractor.swift */, + 45739CD40D10B2FD5E35E0C0 /* ActiveSessionsInteractor.swift */, ); path = Interactor; sourceTree = ""; @@ -9204,7 +9270,7 @@ children = ( C9405152204C802D00D72B04 /* DataAndStorage */, B723C62A204D86BE00884FFD /* SettingsDataAndStorage */, - 173E53A365A073A0C8A259C6 /* Security */, + 173E53A365A073A0C8A259C6 /* ActiveSessions */, B3096BAC6982290B3CB41FD6 /* LanguageSettings */, 2648C3E72069B52000863614 /* ChangeNumber */, 0062D9252062EC4100B915AC /* InviteFriends */, @@ -9556,7 +9622,7 @@ children = ( 00E98258205C2773008BF03D /* Cell */, 00E98257205C274F008BF03D /* View */, - 5F509C0C8B9C738DBC7ABE07 /* SecurityViewController.swift */, + 5F509C0C8B9C738DBC7ABE07 /* ActiveSessionsViewController.swift */, ); path = View; sourceTree = ""; @@ -9841,7 +9907,7 @@ A31F9E0E0E7FEA81D22A0ED7 /* WireFrame */ = { isa = PBXGroup; children = ( - 48276F2EE408C27334B2894C /* SecurityWireframe.swift */, + 48276F2EE408C27334B2894C /* ActiveSessionsWireframe.swift */, ); path = WireFrame; sourceTree = ""; @@ -10290,6 +10356,7 @@ children = ( A4330A642109DFA00060BD93 /* UserInfo.swift */, 4B030F3D2195D88100F293B7 /* UserInfoImpl.swift */, + 4B483AB521BEC0C100FCF879 /* UserIdentifiers.swift */, ); name = UserInfo; sourceTree = ""; @@ -11166,9 +11233,9 @@ isa = PBXGroup; children = ( 4B3B35D521711981005A214A /* AmazonInitializer */, - 4B3B35D421711977005A214A /* SharedServiceFactory */, - 852C3DD0216E3A4300447878 /* Messaging */, A4A242462060372100B0A804 /* Handlers */, + 852C3DD0216E3A4300447878 /* Messaging */, + 4B3B35D421711977005A214A /* SharedServiceFactory */, ); path = Services; sourceTree = ""; @@ -12199,6 +12266,7 @@ FE58F9B2208F0583004AFDD3 /* DBMessageEditAction.swift */, 26771CC2212ED109006112B5 /* DBConvertMessage.swift */, 8514DE882136A50100718DD8 /* DBStarAction.swift */, + 4BFF6C8121C84B6A00BB9432 /* DBUnreadInfo.swift */, ); path = Models; sourceTree = ""; @@ -12455,16 +12523,17 @@ E77764B81FBDA9800042541D /* ItemModels */ = { isa = PBXGroup; children = ( - 3AE0A8401F20321A008A04F3 /* WheelItemModel.swift */, - E77764C01FBDA9BC0042541D /* ImageWheelItemModel.swift */, + 26F03C0C20698B0000712CB0 /* ChatWheelItemModel.swift */, + 4BEF0F6421C265F40012B6E1 /* CommingSoonWheelItemModel.swift */, + 26F5C8BD206BD49B003A7FF5 /* DefaultActionItemModel.swift */, 2657BE522012405600F21935 /* ImageActionItemModel.swift */, 2657BE50201233E300F21935 /* ImageFilledItemModel.swift */, E77764BF1FBDA9BC0042541D /* ImageFullWheelItemModel.swift */, + E77764C01FBDA9BC0042541D /* ImageWheelItemModel.swift */, 26610F5A2015476C00609F77 /* LocationFullWheelItemModel.swift */, 8504DEA820693588006722AC /* MediaFullWheelItemModel.swift */, - 26F03C0C20698B0000712CB0 /* ChatWheelItemModel.swift */, - 26F5C8BD206BD49B003A7FF5 /* DefaultActionItemModel.swift */, 8541BD69206CE0340093EF1E /* Placeholders */, + 3AE0A8401F20321A008A04F3 /* WheelItemModel.swift */, ); path = ItemModels; sourceTree = ""; @@ -12766,7 +12835,7 @@ EDEF587F75F23F688953AD44 /* Presenter */ = { isa = PBXGroup; children = ( - 762BA232B5D027BD943DFA18 /* SecurityPresenter.swift */, + 762BA232B5D027BD943DFA18 /* ActiveSessionsPresenter.swift */, ); path = Presenter; sourceTree = ""; @@ -13675,10 +13744,10 @@ FBD885742147F9640099B8C3 /* Generated */ = { isa = PBXGroup; children = ( + FBD885772147F9640099B8C3 /* AssetsConstants.swift */, FB61D661214FF96200CB2A1F /* ColorsConstants.swift */, FBD885752147F9640099B8C3 /* FontsConstants.swift */, - FBD885762147F9640099B8C3 /* LocalizableConstants.swift */, - FBD885772147F9640099B8C3 /* AssetsConstants.swift */, + 4BC95A7621C0077000B462AC /* LocalizableConstants.swift */, ); path = Generated; sourceTree = ""; @@ -14465,7 +14534,6 @@ A4B544F820EFC0AD00EB7B0F /* StatusCodes.strings in Resources */, 85EBBE052056E8B2009BB269 /* outcoming_message.mp3 in Resources */, E77B9B7C1FDEC6E20035CA12 /* NotoSans-Bold.ttf in Resources */, - F10AFE9B20EF8B9B00C7CE83 /* DevAutoTests.xcconfig in Resources */, 00F7B348202B317000E443E1 /* timezones.json in Resources */, 5BBEF53C212DE09F00F10768 /* ringback.m4a in Resources */, 3A2843291EF9317100EFE21A /* Avenir.ttc in Resources */, @@ -14504,7 +14572,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "if which swiftgen >/dev/null; then\nswiftgen\nfi"; + shellScript = "if which swiftgen >/dev/null; then\nswiftgen\nfi\n"; }; 3ABCE9081EC93B4A00A80B15 /* Run Script */ = { isa = PBXShellScriptBuildPhase; @@ -14518,7 +14586,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Fabric/run\" 595b68a8c4deb3533dcdfc24ca73fd3cffd99f3c 27e6d0f170d463c67f2968218ccba54d2f8f44cfa13615771a1dee6f72469dcb"; + shellScript = "\"${PODS_ROOT}/Fabric/run\" 595b68a8c4deb3533dcdfc24ca73fd3cffd99f3c 27e6d0f170d463c67f2968218ccba54d2f8f44cfa13615771a1dee6f72469dcb\nsh \"${SRCROOT}/Pods/TestFairy/upload-dsym.sh\" f921f39811d4cb2eced9675f802b7fa30cc3ce58\n"; }; 5EF78D1226FD7A5DAFF4A6A5 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; @@ -14763,6 +14831,8 @@ A42CE56C20692EDB000889CC /* p2p.swift in Sources */, 85458CF6212D770900BA8814 /* Message+Files.swift in Sources */, A42CE5F620692EDB000889CC /* Person_Spec.swift in Sources */, + 4B11630121BFC277003859ED /* AppNotificationsProviding.swift in Sources */, + 4B1162FE21BFC1FB003859ED /* TokenConnectionHandler.swift in Sources */, A42CE57220692EDB000889CC /* chain.swift in Sources */, 269848CC200EA0ED00590D6F /* StarModels.swift in Sources */, FB61D653214FEC8500CB2A1F /* AssetsConstants.swift in Sources */, @@ -14781,7 +14851,6 @@ A42CE5F020692EDB000889CC /* ok2_Spec.swift in Sources */, 4B7C73FD215A553F007924DB /* LogWriter.swift in Sources */, A42CE60220692EDB000889CC /* sequenceFlow_Spec.swift in Sources */, - FB61D650214FEC8200CB2A1F /* LocalizableConstants.swift in Sources */, A42CE60020692EDB000889CC /* Message_Spec.swift in Sources */, A4F3DAA42084935400FF71C7 /* Constants.swift in Sources */, E7ED35131FB33806008B5704 /* CellModel.swift in Sources */, @@ -14817,6 +14886,7 @@ A42CE55C20692EDB000889CC /* error.swift in Sources */, 4B030F3F2195D88100F293B7 /* UserInfoImpl.swift in Sources */, 267D465C20AB4CD500D42242 /* AuthExtension.swift in Sources */, + 4BC95A7821C0077100B462AC /* LocalizableConstants.swift in Sources */, A42CE5F420692EDB000889CC /* Loc_Spec.swift in Sources */, A42CE57A20692EDB000889CC /* serviceTask.swift in Sources */, A42CE5DE20692EDB000889CC /* Star_Spec.swift in Sources */, @@ -14840,8 +14910,11 @@ 26C0C1DD2073D96F00C530DA /* MucExtension.swift in Sources */, 26A856362074D24300C642EA /* Theme.swift in Sources */, 4B5A0B7D216E3D20002C4160 /* AttachmentProvider.swift in Sources */, + 4B1162FD21BFC1FB003859ED /* ReachabilityConnectionHandler.swift in Sources */, 26C0C1E72073DABB00C530DA /* DateExtensions.swift in Sources */, 26A8561E2074C38F00C642EA /* NavigationView.swift in Sources */, + 4B1162FF21BFC213003859ED /* AppNotificationsProvider.swift in Sources */, + 4B1162FA21BFC1FB003859ED /* AppLifecycleConnectionHandler.swift in Sources */, 359EB2571F9A1E5000147437 /* BaseMQTTModel.swift in Sources */, A42CE5FE20692EDB000889CC /* Test_Spec.swift in Sources */, A42CE58C20692EDB000889CC /* sequenceFlow.swift in Sources */, @@ -14863,6 +14936,7 @@ 8509FC8A2159095900734D93 /* AppGroupFlagContainer.swift in Sources */, 4B5A0B84216F4A61002C4160 /* AttachmentTransformer.swift in Sources */, 4B5A0B75216E3BDD002C4160 /* ProgressHUD.swift in Sources */, + 4BC95A8121C1246800B462AC /* FeatureFlags.swift in Sources */, A42CE58820692EDB000889CC /* Cursor.swift in Sources */, A49E1BD320A9AA0E0074DFD3 /* BaseChatModel.swift in Sources */, A42CE5C820692EDB000889CC /* act_Spec.swift in Sources */, @@ -14927,6 +15001,7 @@ A42CE59A20692EDB000889CC /* writer.swift in Sources */, A42CE60620692EDB000889CC /* History_Spec.swift in Sources */, A42CE61820692EDB000889CC /* Tag_Spec.swift in Sources */, + 4BEF0F6F21C294A40012B6E1 /* FavoritesMode.swift in Sources */, 4BF2C3E12188B27F00E59F6C /* Injectable.swift in Sources */, A42CE5F820692EDB000889CC /* Friend_Spec.swift in Sources */, A42CE61620692EDB000889CC /* Roster_Spec.swift in Sources */, @@ -15028,6 +15103,7 @@ A4330A722109EBB30060BD93 /* CountriesProviding.swift in Sources */, A42CE5FC20692EDB000889CC /* userTask_Spec.swift in Sources */, A42CE5CE20692EDB000889CC /* Vox_Spec.swift in Sources */, + 4B483ABA21BED06A00FCF879 /* MQTTConnectionHandler.swift in Sources */, A42CE56620692EDB000889CC /* receiveTask.swift in Sources */, A42CE5E220692EDB000889CC /* ExtendedStar_Spec.swift in Sources */, A42CE61220692EDB000889CC /* Typing_Spec.swift in Sources */, @@ -15054,6 +15130,7 @@ 26C0C1D22073CBA200C530DA /* DialogCellModel.swift in Sources */, 26C0C1CC2073C93F00C530DA /* ForwardSelectorMode.swift in Sources */, A45F114D20B4222F00F45004 /* PresenceStatus.swift in Sources */, + 4B483AB921BEC84200FCF879 /* UserIdentifiers.swift in Sources */, 26C0C1C02073C70F00C530DA /* ForwardAvatarCollectionViewCell.swift in Sources */, 4BF090CA21635F6900DCCA5C /* Message+LocalStatus.swift in Sources */, 8524C4DB21777456003BF374 /* Service+Construct.swift in Sources */, @@ -15082,6 +15159,7 @@ 4B3B35DA217119C9005A214A /* AmazonInitializer.swift in Sources */, A42CE58220692EDB000889CC /* CDR.swift in Sources */, 4B3B35D32171120F005A214A /* SharedServiceFactory.swift in Sources */, + 4B1162FC21BFC1FB003859ED /* AutoReconnectConnectionHandler.swift in Sources */, 4BAE7DDB21B69AC70018D3C2 /* TimerHandler.swift in Sources */, A4B544EB20EFB36100EB7B0F /* errors.swift in Sources */, 8551CF12217094CD00829CF1 /* Array+Desc.swift in Sources */, @@ -15138,7 +15216,6 @@ A42D51B6206A361400EEB952 /* iter.swift in Sources */, 9B967098215151760058E98F /* LeaveVoiceMessageViewController.swift in Sources */, 2603139E20A0A4BA009AC66D /* ChatLanguageSettingsPresenter.swift in Sources */, - 4B1D7DFC2029C37900703228 /* FavoritesItemsFactory.swift in Sources */, 26771CC3212ED109006112B5 /* DBConvertMessage.swift in Sources */, 269848CA200E9F1300590D6F /* StarModels.swift in Sources */, 4B058F0D204EAEC3004C7D9F /* RoomDAO.swift in Sources */, @@ -15146,6 +15223,7 @@ 4B1D7E112029FF5000703228 /* Array+WheelItemModel.swift in Sources */, A46C36342121999100172773 /* DDMechanism.swift in Sources */, 854A4B302080D6C400759152 /* CellWithImageTableViewCell.swift in Sources */, + 4B483AB621BEC0C100FCF879 /* UserIdentifiers.swift in Sources */, 3A8045D81F60C98200AED866 /* MQTTService+Helper.swift in Sources */, 8E9601971FF2EC8100E0C21D /* GroupFilesListVC.swift in Sources */, 4B06D3222028A9C6003B275B /* GroupChatItemsFactory.swift in Sources */, @@ -15183,6 +15261,7 @@ A42D52C6206A53AA00EEB952 /* Feature_Spec.swift in Sources */, F10AFEB620F7B1B000C7CE83 /* WheelImageFullItemPreview.swift in Sources */, A45F112A20B4218D00F45004 /* BubbleInjectible.swift in Sources */, + 4B483AAE21BEB0D900FCF879 /* AppLifecycleConnectionHandler.swift in Sources */, 4B1D7E14202A0A0200703228 /* GroupMode.swift in Sources */, 3A27B0A71EF307A900B4B3CB /* DeleteUserModel.swift in Sources */, 3A1F74FA1F5ED344009A11E4 /* PushService.swift in Sources */, @@ -15222,6 +15301,7 @@ C9C694FD201FA55800A57297 /* SwipeBackHelper.swift in Sources */, 85CE26D820C5593600553FE7 /* HapticSelectionFeedbackGenerator.swift in Sources */, A49381AA21355EE1006D28DD /* MessageInteractor+Forward.swift in Sources */, + 4B483AB421BEB8B100FCF879 /* ReachabilityConnectionHandler.swift in Sources */, 26FA4210201821B400E6F6EC /* StarHandler.swift in Sources */, 4BE2C5DA2142EAC500A73DD9 /* AudioSessionManager.swift in Sources */, 00E98252205C26F7008BF03D /* SessionLineView.swift in Sources */, @@ -15243,6 +15323,7 @@ E7EED2361F740CEA005DAE20 /* NewContactItem.swift in Sources */, FEA65617216779F700B44029 /* WalletServiceWallet.swift in Sources */, 26DCB2502064BA3D001EF0AB /* ContactsPresenter.swift in Sources */, + 4B483AAC21BEB0A900FCF879 /* MQTTConnectionHandler.swift in Sources */, FEA655E92167777E00B44029 /* TransferHistoryPresenter.swift in Sources */, A42D51B4206A361400EEB952 /* container.swift in Sources */, 265F5D29209B6E1F008ACCC8 /* ParticipantsViewControllerLayout.swift in Sources */, @@ -15288,7 +15369,6 @@ F10B0E2120B4CF3800528E7A /* CameraCoordinator.swift in Sources */, 2657BE532012405600F21935 /* ImageActionItemModel.swift in Sources */, 26A0CFE12005138C006F6617 /* MemberExtension+BERT.swift in Sources */, - FBD885792147F9640099B8C3 /* LocalizableConstants.swift in Sources */, 2652D6181FA85B28005E62C7 /* ImageSelector.swift in Sources */, 26DE8D9120FE1AF500C41096 /* ChatCellFooterView.swift in Sources */, 6D485DE51F0AD96D00E12FB1 /* Localizable.swift in Sources */, @@ -15357,7 +15437,7 @@ 4B02130220372C5700650298 /* OtherItemView.swift in Sources */, 853801282052CCAD002C6960 /* SoundCellModel.swift in Sources */, A458FABB20EB87BF0075D55E /* ActionContainerContent.swift in Sources */, - 00E9824C205C1E19008BF03D /* SecurityItemsFactory.swift in Sources */, + 00E9824C205C1E19008BF03D /* ActiveSessionsItemsFactory.swift in Sources */, 26342CA920ECBAEF00D2196B /* TranscribeNetworkClient.swift in Sources */, 852003F620D4194A007C0036 /* DBRecentSticker.swift in Sources */, 267BE2831FDE905D00C47E18 /* SettingsProtocols.swift in Sources */, @@ -15381,6 +15461,7 @@ 268C340F21067BAD00F1472A /* AudioUploadOperation.swift in Sources */, 8509FC812158E11000734D93 /* TableAlternationExtension.swift in Sources */, 8580BAF320BD9B8000239D9D /* String+Suffix.swift in Sources */, + 4B483AB021BEB1D000FCF879 /* AppGroupConnectionHandler.swift in Sources */, A43B259620AB1DFA00FF8107 /* RecordDisplayInputContent.swift in Sources */, 4B4266C1204D917800194BC1 /* ActionsView+Layout.swift in Sources */, AF440BA5CEBE5170D082FF60 /* LoginProtocols.swift in Sources */, @@ -15943,7 +16024,6 @@ 4B2C502E21B56AB700FBA9B1 /* AddAutoColumnToConvertMessage.swift in Sources */, 6D6731101F29E1F4003E8F8F /* BottomCallView.swift in Sources */, 26245F40204EF58E00C8D3DD /* BaseViewProtocol.swift in Sources */, - 4B1D7DFE2029C41C00703228 /* AboutItemsFactory.swift in Sources */, A4688DFC20652DE30013660D /* StorageChange.swift in Sources */, 5683555B8382F7F37FEE1AF5 /* ProfileWireframe.swift in Sources */, A42D51AC206A361400EEB952 /* Auth.swift in Sources */, @@ -15963,6 +16043,7 @@ E735853D1F6C2705003354B5 /* Geometry.swift in Sources */, 85B0013421272694000C89FE /* MessageInteractor+History.swift in Sources */, 4B030F2F2195BFF300F293B7 /* AuthHandler.swift in Sources */, + 4B78E30421C3F7BB001B2F0E /* CallsItemsFactory.swift in Sources */, F119E67720D27E990043A532 /* ImagePreviewCVCell.swift in Sources */, 260313A720A0A4BA009AC66D /* ChatLanguageSettingsTableDataSource.swift in Sources */, 260313A520A0A4BA009AC66D /* BaseCell.swift in Sources */, @@ -15990,6 +16071,7 @@ A42D51A5206A361400EEB952 /* act.swift in Sources */, E7C36C371FC469E600740630 /* ProfileExtension.swift in Sources */, 26ED2C1820042683002DBBE8 /* RepliesDS.swift in Sources */, + 4B483AB821BEC1C600FCF879 /* TokenConnectionHandler.swift in Sources */, FEA6562121677B3500B44029 /* MessageTransferView.swift in Sources */, 2605311F21274124002E1CF1 /* LogOutputInteractor.swift in Sources */, 9BE521222189B2E10070C664 /* ThreeButtonHeaderView.swift in Sources */, @@ -16298,6 +16380,7 @@ A45F59AD2058263F00EAA780 /* RosterDAO.swift in Sources */, FEA655DB2167777E00B44029 /* WalletDetailsWireFrame.swift in Sources */, 4C5EEA13EBC6A8398F08DCD1 /* MainWireframe.swift in Sources */, + 4BEF0F6521C265F40012B6E1 /* CommingSoonWheelItemModel.swift in Sources */, A42D52CF206A53AB00EEB952 /* Person_Spec.swift in Sources */, B77C11E82109254800CCB42E /* InterpretationTypeProtocols.swift in Sources */, B77C11E72109254800CCB42E /* InterpretationTypeViewController.swift in Sources */, @@ -16550,6 +16633,7 @@ 54FFFD58388E2B660C1E5A05 /* MapPresenter.swift in Sources */, A42D52D6206A53AB00EEB952 /* serviceTask_Spec.swift in Sources */, 0AB08BA89A51118248FA3233 /* MapInteractor.swift in Sources */, + 4BEF0F6821C28FC70012B6E1 /* FavoritesMode.swift in Sources */, 8540A331211B34B4007F65AF /* MessageCollectionViewDataSource.swift in Sources */, A48C154220EF76EE002DA994 /* LinkExtension.swift in Sources */, A42D52AD206A53AA00EEB952 /* log_Spec.swift in Sources */, @@ -16569,6 +16653,7 @@ C99D6CD77325A09D045DB760 /* FavoritesViewController.swift in Sources */, 00E98256205C2740008BF03D /* SessionItemCell.swift in Sources */, 85D77807211D9B980044E72F /* ScrollPosition.swift in Sources */, + 4BFF6C8221C84B6A00BB9432 /* DBUnreadInfo.swift in Sources */, 4B030F362195CD9B00F293B7 /* MQTTService+QueuePool.swift in Sources */, FEA655F22167777E00B44029 /* PaymentWireFrame.swift in Sources */, DF55CCC682DAB5392F2A763D /* FavoritesPresenter.swift in Sources */, @@ -16607,6 +16692,7 @@ 85629ECA2137EF2400A79C97 /* VoiceAudioInteractive.swift in Sources */, 265EB71D20A86A1900C1483E /* ConvertionProgressModel.swift in Sources */, 85D66A0320BD963C00FBD803 /* NSAttributedStringKey+Mention.swift in Sources */, + 4BC95A8021C1224100B462AC /* FeatureFlags.swift in Sources */, E7417E991FBED91100E5C124 /* Table.swift in Sources */, 0008E9192032F4C8003E316E /* SendJob.swift in Sources */, 4DAEBCF361B86B0AD3C98749 /* EditUsernameInteractor.swift in Sources */, @@ -16628,6 +16714,7 @@ 26E7D04A1FCB8973001C69B7 /* Amazon+FileSync.swift in Sources */, E70938411FBEE488006CCDC6 /* TableDefinitionExtension.swift in Sources */, 850D220020D2E7E20018BBA4 /* SelectionFeedbackInteractive.swift in Sources */, + 4BEF0F6C21C290A10012B6E1 /* FavoritesP2pItemsFactory.swift in Sources */, 43711F24FF65C36730467BFF /* EditPhotoViewController.swift in Sources */, A42D519F206A361400EEB952 /* messageEvent.swift in Sources */, F11DF06520BD96D000F3E005 /* GalleryFilterType.swift in Sources */, @@ -16722,6 +16809,7 @@ 3362A56D731AC1411C02D037 /* MyGroupAliasWireframe.swift in Sources */, 260313A020A0A4BA009AC66D /* SwitchableActionCell.swift in Sources */, 4B055C37219C313A001FE077 /* FileDownloaderFactory.swift in Sources */, + 4BC95A7721C0077100B462AC /* LocalizableConstants.swift in Sources */, 8ED0F3D11FBC5CF2004916AB /* GroupsListViewController.swift in Sources */, BBF46945EB64E07C58817ACA /* EditGroupNameProtocols.swift in Sources */, 8520040020D466CE007C0036 /* StickerPack_Spec.swift in Sources */, @@ -16876,6 +16964,7 @@ 8509AC62206A54420089089B /* ResponseResult.swift in Sources */, 926E70F8DA5310B1129B0277 /* MapSearchPresenter.swift in Sources */, A49CC1D620E4AAC600879D41 /* InputBar+DisplayModeConfig.swift in Sources */, + 4BEF0F6E21C290B10012B6E1 /* FavoritesGroupItemsFactory.swift in Sources */, FEA6560F2167797E00B44029 /* WalletFundingNetworkResponse.swift in Sources */, 5ED473EC698E99DC021E553A /* MapSearchInteractor.swift in Sources */, F1607B2A20B2DE6500BDF60A /* CameraQRPreviewWireframe.swift in Sources */, @@ -16932,6 +17021,7 @@ 4B7C73F4215A5509007924DB /* LogService.swift in Sources */, A42D52D0206A53AB00EEB952 /* Friend_Spec.swift in Sources */, F11786D120A98685007A9A1B /* MessageFactory.swift in Sources */, + 4B483AB221BEB42600FCF879 /* AutoReconnectConnectionHandler.swift in Sources */, 84BB63C68EA124AA7DD21B30 /* LanguageSettingsProtocols.swift in Sources */, FEA656022167777F00B44029 /* WalletBalancesViewController.swift in Sources */, 69CA7311E49F87A5CACC8A73 /* LanguageSettingsViewController.swift in Sources */, @@ -16940,19 +17030,19 @@ BC1BA70218B40F3F64841848 /* LanguageSettingsInteractor.swift in Sources */, F922EF38E4C1662D54CE533D /* LanguageSettingsWireframe.swift in Sources */, 26A421CF217E541800120542 /* SnackBarLayoutGuide.swift in Sources */, - E8AFC57E49EED25C3F5001B7 /* SecurityProtocols.swift in Sources */, - 3219C8F242591BA17953FF33 /* SecurityViewController.swift in Sources */, + E8AFC57E49EED25C3F5001B7 /* ActiveSessionsProtocols.swift in Sources */, + 3219C8F242591BA17953FF33 /* ActiveSessionsViewController.swift in Sources */, A45F110720B4218D00F45004 /* ChatConfiguration.swift in Sources */, 8580BAED20BD9A7100239D9D /* LinkLongPressGestureRecognizer.swift in Sources */, 4BF090C521635E8600DCCA5C /* Message+LinkedId.swift in Sources */, - C6B308C6734EFB77892832A0 /* SecurityPresenter.swift in Sources */, + C6B308C6734EFB77892832A0 /* ActiveSessionsPresenter.swift in Sources */, A42D52B4206A53AA00EEB952 /* ok_Spec.swift in Sources */, B74BAFFD21076AFA0049CD27 /* Sector.swift in Sources */, - 8E54E93EA25B11D417A6100E /* SecurityInteractor.swift in Sources */, + 8E54E93EA25B11D417A6100E /* ActiveSessionsInteractor.swift in Sources */, A43B259420AB1DFA00FF8107 /* InputBar.swift in Sources */, F11DF06820BD996200F3E005 /* NavigationProtocol.swift in Sources */, 855C9FE62125B4C0000E3429 /* MessageHandlerSubscriber.swift in Sources */, - 2CB54DD94DA23D7160F36472 /* SecurityWireframe.swift in Sources */, + 2CB54DD94DA23D7160F36472 /* ActiveSessionsWireframe.swift in Sources */, 26EA201520BECDCA00FBB9CA /* ConversationLanguageSettingService.swift in Sources */, F11786ED20AC383D007A9A1B /* CollapsedView.swift in Sources */, F11786C920A8E4FD007A9A1B /* CameraVideoPreviewProtocols.swift in Sources */, @@ -16998,13 +17088,13 @@ 4B8FC31C2163CD8C00602D6B /* ChatCellModel.swift in Sources */, 2611CEF92182090900FFD4DD /* LogWriterProtocol.swift in Sources */, 85458CE4212D731300BA8814 /* MessageIdentifiers.swift in Sources */, - FB61D651214FEC8200CB2A1F /* LocalizableConstants.swift in Sources */, A4330A562109D60D0060BD93 /* QueryFactoryProtocol.swift in Sources */, 85458CE6212D73CF00BA8814 /* P2pExtension.swift in Sources */, A4330A582109D6130060BD93 /* QueryFactory.swift in Sources */, 4B8FC31E2163D98F00602D6B /* CollectionsExtensions.swift in Sources */, A49EE6DC210B257000B700B1 /* UserInfo.swift in Sources */, A49EE6D8210B110C00B700B1 /* Service.swift in Sources */, + 4BC95A7921C0077100B462AC /* LocalizableConstants.swift in Sources */, 4BF090C921635F4300DCCA5C /* Message+LocalStatus.swift in Sources */, A4AB8E582105F47C005F9B0C /* InputsCachePolicyTest.swift in Sources */, FB816EF920B5B8A700093DCD /* Desc.swift in Sources */, @@ -17044,6 +17134,7 @@ files = ( 4B348FD8216366AE00CCB0E3 /* LogServiceTopic.swift in Sources */, 2611CEFA2182090900FFD4DD /* LogWriterProtocol.swift in Sources */, + 4BC95A7A21C0077100B462AC /* LocalizableConstants.swift in Sources */, FE21ACB92113AB3C006010A0 /* KeychainServiceTest.swift in Sources */, FE21ACBC2113AB92006010A0 /* QueryFactoryProtocol.swift in Sources */, 4B348FD7216366A900CCB0E3 /* LogServiceProtocol.swift in Sources */, @@ -17051,7 +17142,6 @@ FE21ACBA2113AB4B006010A0 /* KeychainService.swift in Sources */, 4BF2C3E92189B49500E59F6C /* Localizable.swift in Sources */, 85458CDC212D6FFF00BA8814 /* String+Split.swift in Sources */, - FB61D652214FEC8300CB2A1F /* LocalizableConstants.swift in Sources */, 85458CE5212D731300BA8814 /* MessageIdentifiers.swift in Sources */, FB61D64F214FEC7E00CB2A1F /* FontsConstants.swift in Sources */, FB61D665214FF96200CB2A1F /* ColorsConstants.swift in Sources */, @@ -17222,6 +17312,7 @@ SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; + TARGETED_DEVICE_FAMILY = 1; }; name = LoadDB; }; @@ -17251,7 +17342,7 @@ SKIP_INSTALL = YES; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = LoadDB; }; @@ -17422,7 +17513,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = Dev; }; @@ -17454,7 +17545,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = Release; }; @@ -17607,6 +17698,7 @@ SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; + TARGETED_DEVICE_FAMILY = 1; }; name = Dev; }; @@ -17638,6 +17730,7 @@ SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; + TARGETED_DEVICE_FAMILY = 1; }; name = Release; }; @@ -17726,6 +17819,7 @@ SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; + TARGETED_DEVICE_FAMILY = 1; }; name = "Release-Debug"; }; @@ -17758,7 +17852,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = "Release-Debug"; }; @@ -17906,6 +18000,7 @@ SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; + TARGETED_DEVICE_FAMILY = 1; }; name = Spotify; }; @@ -17937,7 +18032,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = Spotify; }; @@ -18152,7 +18247,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Nynja/Resources/Nynja.entitlements; CODE_SIGN_IDENTITY = "iPhone Distribution"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEFINES_MODULE = YES; @@ -18165,7 +18260,7 @@ PRODUCT_BUNDLE_IDENTIFIER = "$(BundleIdentifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = "e4b654e5-ea23-4135-bb19-3edc95e49642"; - PROVISIONING_PROFILE_SPECIFIER = DevBundle_adhoc; + PROVISIONING_PROFILE_SPECIFIER = DevBundle_Dev; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_COMPILATION_MODE = singlefile; SWIFT_OBJC_BRIDGING_HEADER = "Nynja-Bridging-Header.h"; @@ -18173,6 +18268,7 @@ SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; + TARGETED_DEVICE_FAMILY = 1; }; name = PrereleaseDebug; }; @@ -18185,7 +18281,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = "Nynja-Share/Resources/Nynja-Share.entitlements"; CODE_SIGN_IDENTITY = "iPhone Distribution"; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Manual; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = 9GKQ5AMF2B; @@ -18198,14 +18294,14 @@ PRODUCT_BUNDLE_IDENTIFIER = "$(ExtensionBundleIdentifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = "5dca1418-4061-4c52-958f-3edf7251f19b"; - PROVISIONING_PROFILE_SPECIFIER = DevBundle_AdHocExt; + PROVISIONING_PROFILE_SPECIFIER = DevBundle_DevExt; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_COMPILATION_MODE = singlefile; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = PrereleaseDebug; }; @@ -18352,6 +18448,7 @@ SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; + TARGETED_DEVICE_FAMILY = 1; }; name = DevAutoTests; }; @@ -18383,7 +18480,7 @@ SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = DevAutoTests; }; @@ -18547,6 +18644,7 @@ SWIFT_SWIFT3_OBJC_INFERENCE = Off; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; + TARGETED_DEVICE_FAMILY = 1; }; name = Prerelease; }; @@ -18572,13 +18670,13 @@ PRODUCT_BUNDLE_IDENTIFIER = "$(ExtensionBundleIdentifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE = "5dca1418-4061-4c52-958f-3edf7251f19b"; - PROVISIONING_PROFILE_SPECIFIER = NynjaRC_devExt; + PROVISIONING_PROFILE_SPECIFIER = NynjaRC_adhocExt; SKIP_INSTALL = YES; SWIFT_ACTIVE_COMPILATION_CONDITIONS = RELEASE; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_VERSION = 4.2; SWIFT_WHOLE_MODULE_OPTIMIZATION = YES; - TARGETED_DEVICE_FAMILY = "1,2"; + TARGETED_DEVICE_FAMILY = 1; }; name = Prerelease; }; diff --git a/Nynja/AboutItemsFactory.swift b/Nynja/AboutItemsFactory.swift deleted file mode 100644 index 2fcaefddbcdc8840a9de1a209fc5da5ae92c4685..0000000000000000000000000000000000000000 --- a/Nynja/AboutItemsFactory.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// AboutItemsFactory.swift -// Nynja -// -// Created by Volodymyr Hryhoriev on 2/6/18. -// Copyright © 2018 TecSynt Solutions. All rights reserved. -// - -class AboutItemsFactory: OptionsItemsFactory { - - // MARK: - Second lvl - - override var about: ImageActionItemModel { - let item = super.about - // TODO: state - item.state = .highlighted - return item - } - -} diff --git a/Nynja/SecurityItemsFactory.swift b/Nynja/ActiveSessionsItemsFactory.swift similarity index 54% rename from Nynja/SecurityItemsFactory.swift rename to Nynja/ActiveSessionsItemsFactory.swift index f94137083e6c5f28667c2cc1e14f163c3b67dfb1..5d44515bd2b0d38d622f1ac3d6f0a9a389f1befb 100644 --- a/Nynja/SecurityItemsFactory.swift +++ b/Nynja/ActiveSessionsItemsFactory.swift @@ -1,17 +1,17 @@ // -// SessionsItemsFactory.swift +// ActiveSessionsItemsFactory.swift // Nynja // // Created by Michael Katkov on 3/16/18. // Copyright © 2018 TecSynt Solutions. All rights reserved. // -class SecurityItemsFactory: OptionsItemsFactory { +class ActiveSessionsItemsFactory: OptionsItemsFactory { // MARK: - Second lvl - override var security: ImageActionItemModel { - let item = super.security + override var activeSessions: ImageActionItemModel { + let item = super.activeSessions item.state = .highlighted return item } diff --git a/Nynja/AppDelegate.swift b/Nynja/AppDelegate.swift index 6e9bfadb2b64959ad64939d42956c2bb2d614a4d..93abd7815e6f754497f983cdc29deea2ca760728 100644 --- a/Nynja/AppDelegate.swift +++ b/Nynja/AppDelegate.swift @@ -29,9 +29,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD return imgView }() - private let storageService = StorageService.sharedInstance private let antiDebuggingService = AntiDebuggingService() + private var storageService: StorageService { + return .sharedInstance + } + // FIXME: need to be removed from here when share extension won't require new mqtt connection. private var appGroupObserver: AppGroupFlagObserver? @@ -42,9 +45,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD configureDependencies() - observeGroupAppChanges() - - wipeStorage() + wipeKeychain() configureWindow() @@ -70,18 +71,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD func applicationDidBecomeActive(_ application: UIApplication) { backgroundImageView.removeFromSuperview() } - - func applicationDidEnterBackground(_ application: UIApplication) { - MQTTService.sharedInstance.disconnect() - } - - func applicationWillEnterForeground(_ application: UIApplication) { - MQTTService.sharedInstance.reconnect() - } - - func applicationWillTerminate(_ application: UIApplication) { - MQTTService.sharedInstance.disconnect() - } } // MARK: - UNUserNotificationCenterDelegate @@ -124,30 +113,13 @@ private extension AppDelegate { FileManagerService.sharedInstance.createDirectory(dirName: Constants.Folders.downloads) } - private func wipeStorage() { + private func wipeKeychain() { if !storageService.wasRun { LogService.log(topic: .db) { return "Clear storage: AppDelegate - if it is first runs" } - storageService.clearStorage() + storageService.wipeKeychain() storageService.wasRun = true } } - - private func observeGroupAppChanges() { - self.appGroupObserver = AppGroupFlagObserver(fileManager: .default, appGroup: Bundle.main.appGroupName) - do { - try appGroupObserver?.prepare() - try appGroupObserver?.removeFlagIfExists(.shareExtension) - try appGroupObserver?.observe { flags in - if flags.contains(.shareExtension) { - MQTTService.sharedInstance.disconnect() - } else { - MQTTService.sharedInstance.reconnect() - } - } - } catch { - LogService.log(topic: .fileSystem) { error.localizedDescription } - } - } } // MARK: - Setup third party services diff --git a/Nynja/BadgeNumberService.swift b/Nynja/BadgeNumberService.swift index f86d18afc3f0d43a54293c74e215acc32d4c5280..639f1f0b75c53074be99a4ae0e6c7696b3a8170e 100644 --- a/Nynja/BadgeNumberService.swift +++ b/Nynja/BadgeNumberService.swift @@ -32,7 +32,10 @@ final class BadgeNumberService: BadgeNumberServiceProtocol, StorageSubscriber { } func initCounters() { - self.badgeNumber = conversationsProvider.fetchUnreadMessagesCount() + conversationsProvider.fetchUnreadsInfo().forEach { info in + counters[info.id] = info.unread + badgeNumber += info.unread + } } deinit { diff --git a/Nynja/CallsItemsFactory.swift b/Nynja/CallsItemsFactory.swift new file mode 100644 index 0000000000000000000000000000000000000000..6b1f90eb40af60c07f7cae6b669eb6684d5dc3b5 --- /dev/null +++ b/Nynja/CallsItemsFactory.swift @@ -0,0 +1,68 @@ +// +// CallsItemsFactory.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 12/14/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +final class CallsItemsFactory: WCBaseItemsFactory { + + // MARK: - First lvl + + override var calls: ImageActionItemModel { + let item = super.calls + item.state = .highlighted + return item + } + + + // MARK: - Second lvl + + override var secondLevelItems: ItemModels { + let voiceCall = self.voiceCall + voiceCall.subitems = [dialNumber, callContact] + + return [callHistory, videoCall, voiceCall] + } + + + // MARK: - Items + + var voiceCall: ImageActionItemModel { + return ImageActionItemModel( + nameImage: UIImage.nynja.Wheel.WheelItems.icCalls.name, + navItem: .voiceCall) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.expandVoiceCall(indexPath: indexPath) + } + } + + var callContact: ImageActionItemModel { + return ImageFilledItemModel(navItem: .callContact) { [weak navigateDelegate] (item, indexPath) in + // TODO: need to implement + }.asCommingSoon(navigateDelegate: navigateDelegate) + } + + var dialNumber: ImageActionItemModel { + return ImageFilledItemModel(navItem: .dialNumber) { [weak navigateDelegate] (item, indexPath) in + // TODO: need to implement + }.asCommingSoon(navigateDelegate: navigateDelegate) + } + + var videoCall: ImageActionItemModel { + return ImageActionItemModel( + nameImage: UIImage.nynja.Wheel.WheelItems.icVideo.name, + navItem: .videoCall) { [weak navigateDelegate] (item, indexPath) in + // TODO: need to implement + }.asCommingSoon(navigateDelegate: navigateDelegate) + } + + var callHistory: ImageActionItemModel { + return ImageActionItemModel( + nameImage: UIImage.nynja.Wheel.WheelItems.icHistory.name, + navItem: .callHistory) { [weak navigateDelegate] (item, indexPath) in + // TODO: need to implement + }.asCommingSoon(navigateDelegate: navigateDelegate) + } +} + diff --git a/Nynja/ChatItemsFactory.swift b/Nynja/ChatItemsFactory.swift index 14cc2957a719de7a68faebcd0c87ce597d9ad1a8..9ae090895550e0b6fec606d451334943152f01e7 100644 --- a/Nynja/ChatItemsFactory.swift +++ b/Nynja/ChatItemsFactory.swift @@ -14,15 +14,6 @@ class ChatItemsFactory: WCBaseItemsFactory { }) return item } - - var payment: ImageActionItemModel { - return ImageActionItemModel( - nameImage: "ic_pay", - navItem: .payment, - action: { [weak navigateDelegate] (item, indexPath) in - navigateDelegate?.showPayment(indexPath: indexPath) - }) - } var camera: ImageActionItemModel { let item = ImageActionItemModel(nameImage: "ic_camera", navItem: .camera, isSelectable: false, action: { [weak navigateDelegate] (item, indexPath) in @@ -107,11 +98,12 @@ class ChatItemsFactory: WCBaseItemsFactory { }) } - var videoGroupCall: ImageFilledItemModel { - return ImageFilledItemModel(nameImage: "ic_video", navItem: .videoCall, isSelectable: false, action: { [weak navigateDelegate] (item, indexPath) in - navigateDelegate?.unavailableFunctionality() -// navigateDelegate?.showVideoGroupCall(indexPath: indexPath) - }) + var videoGroupCall: ImageActionItemModel { + return ImageFilledItemModel( + nameImage: UIImage.nynja.Wheel.WheelItems.icVideo.name, + navItem: .videoCall) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showVideoGroupCall(indexPath: indexPath) + }.asCommingSoon(navigateDelegate: navigateDelegate) } // MARK: - Media diff --git a/Nynja/ChatService/ChatService.swift b/Nynja/ChatService/ChatService.swift index ddd931eddb21f5a9a86dff48a1ec2caf0976f5b4..ec936a274e24b7df2f9ea0eb2465e1f5a7ff8a99 100644 --- a/Nynja/ChatService/ChatService.swift +++ b/Nynja/ChatService/ChatService.swift @@ -86,15 +86,13 @@ final class ChatService { guard let chatModel = chat ?? fetchChatModel(from: message) else { return false } - - if let shouldUpdate = shouldUpdate, let lastId = chatModel.last_msg?.id, !shouldUpdate(lastId) { + + if let lastId = chatModel.last_msg?.id, let shouldUpdate = shouldUpdate, !shouldUpdate(lastId) { return false } chatModel.last_msg = nil - if let serverId = message.id, let lastMessageId = MessageDAO.fetchMessagePrimaryKey(with: serverId) { - chatModel.lastMessageId = lastMessageId - } + chatModel.lastMessageId = message.msg_id let shouldIncrementUnread = (!message.isOwn || message.isCursor) && !message.isEdited && shouldChangeUnread if shouldIncrementUnread { @@ -175,10 +173,10 @@ final class ChatService { // MARK: - Remove message static func removeMessages(_ messages: [Message]) { - messages.forEach { removeMessage($0, shouldUpdateChat: false) } + messages.forEach { removeMessage($0) } } - static func removeMessage(_ message: Message, shouldUpdateChat: Bool = true) { + static func removeMessage(_ message: Message) { guard MessageDAO.removeMessage(using: message), let id = message.linkedId else { return } @@ -187,9 +185,23 @@ final class ChatService { try? storageService.perform(action: .delete, with: action) } + updateAfterRemove(using: message, id: id) + } + + static func removeLocal(message: Message) { + try? storageService.perform(action: .save, with: message) + + guard let id = message.id else { + return + } + updateAfterRemove(using: message, id: id) + } + + private static func updateAfterRemove(using message: Message, id: MessageServerId) { guard let chat = fetchChatModel(from: message) else { return } + updateUnreadMentionsAfterRemove(for: chat, serverId: id) updateUnreadCounterAfterRemove(for: chat, serverId: id) updateLastMessageAfterRemove(for: chat, message: message) @@ -215,8 +227,9 @@ final class ChatService { updateUnreadCounter(for: chat) } - private static func updateLastMessageAfterRemove(for chat: ChatModel, message: Message) { + static func updateLastMessageAfterRemove(for chat: ChatModel, message: Message) { guard let lastMessage = MessageDAO.fetchLastMessage(feed: message.feed) else { + removeLast(message: message, inChat: chat) return } updateLastMessage(lastMessage, chat: chat, shouldChangeUnread: false, shouldUpdateMentions: false) { lastMessageId in @@ -224,6 +237,17 @@ final class ChatService { } } + private static func removeLast(message: Message, inChat chat: ChatModel) { + chat.last_msg = nil + chat.lastMessageId = nil + chat.unread = 0 + + if let room = chat as? Room { + room.mentions = [] + } + + try? storageService.perform(action: .save, with: chat) + } // MARK: - Clear History diff --git a/Nynja/ChatsItemsFactory.swift b/Nynja/ChatsItemsFactory.swift index d75f095c26ee529bb0d8fa61abd119eab138562f..73001416e923313e5d8e8166ddd9759221bd17b8 100644 --- a/Nynja/ChatsItemsFactory.swift +++ b/Nynja/ChatsItemsFactory.swift @@ -12,7 +12,6 @@ class ChatsItemsFactory: WCBaseItemsFactory { override var actions: ImageActionItemModel { let item = super.actions - // TODO: state item.state = .disabled return item } @@ -21,7 +20,11 @@ class ChatsItemsFactory: WCBaseItemsFactory { // MARK: - Second lvl override var secondLevelItems: ItemModels { - return [family, friends, work, all, recent, starred, new] + if FeatureFlags.isChatGroupingEnabled.value { + return [family, friends, work, all, recent, starred, new] + } else { + return [all, recent, starred, new] + } } @@ -51,13 +54,10 @@ class ChatsItemsFactory: WCBaseItemsFactory { var recent : WheelItemModel { return WheelItemModel() - } - var starred : ImageActionItemModel { - return ImageActionItemModel(nameImage: "ic_starred", navItem: .starred, state: .disabled, action: { [weak navigateDelegate] (item, indexPath) in - navigateDelegate?.showMessages(indexPath: indexPath) - }) + var starred : WheelItemModel { + return WheelItemModel() } var new: WheelItemModel { diff --git a/Nynja/ConversationsProvider.swift b/Nynja/ConversationsProvider.swift index f5d011edfcf0a3f7988d9c86873ac737e5206ba7..1f60c01701aa6f0a0e229b468405f14f876e56dd 100644 --- a/Nynja/ConversationsProvider.swift +++ b/Nynja/ConversationsProvider.swift @@ -95,6 +95,44 @@ class ConversationsProvider: ConversationsProviding, InitializeInjectable { where \(unreadColumn) > 0 """ } + + func fetchUnreadsInfo() -> [DBUnreadInfo] { + return dbManager.fetch { db in + return try makeUnreadsInfoRequest().fetchAll(db) + } + } + + private func makeUnreadsInfoRequest() -> AnyTypedRequest { + let idAlias = "id" + + let contactSql = makeUnreadsInfoSQL(for: ContactTable.name, idColumn: Column.phoneId, idAlias: idAlias) + let roomSql = makeUnreadsInfoSQL(for: RoomTable.name, idColumn: Column.id) + + let sql = """ + select \(idAlias), \(Column.unread) + from + (\(contactSql) + union + \(roomSql)) + """ + + return SQLRequest(sql).asRequest(of: DBUnreadInfo.self) + } + + private func makeUnreadsInfoSQL(for tableName: String, + idColumn: Column, + idAlias: String? = nil) -> String { + let unreadColumn = Column.unread.asString(tableName: tableName) + let idColumn = idColumn.asString(tableName: tableName) + + let asIdAlias = idAlias.map { "as '\($0)'" } ?? "" + + return """ + select \(unreadColumn), \(idColumn) \(asIdAlias) + from \(tableName) + where \(unreadColumn) > 0 + """ + } } diff --git a/Nynja/ConversationsProviding.swift b/Nynja/ConversationsProviding.swift index 10bf1bb955f721ec0ae074d7df4fb179e8d90357..7106e447b97937d5bc7d4c684008f2ffe33e5ab8 100644 --- a/Nynja/ConversationsProviding.swift +++ b/Nynja/ConversationsProviding.swift @@ -20,4 +20,5 @@ protocol ConversationsProviding { func comparator(lhs: ChatModel, rhs: ChatModel) -> Bool func fetchUnreadMessagesCount() -> Int64 + func fetchUnreadsInfo() -> [DBUnreadInfo] } diff --git a/Nynja/DB/Models/DBMessage.swift b/Nynja/DB/Models/DBMessage.swift index 414d6098eb58e568b2eebbd6d6773ee1c352856a..71380ce5e480fd1ef4b9bf4ebcaf28488a6a7d3b 100644 --- a/Nynja/DB/Models/DBMessage.swift +++ b/Nynja/DB/Models/DBMessage.swift @@ -358,9 +358,10 @@ final class DBMessage: Record, DBModel { static func condition(feed: Feed, messageTable: String) -> String { let feedIdCondition: String - if feed.type == .p2p { + switch feed.type { + case .p2p: feedIdCondition = conditionP2p(id: feed.id, messageTable: messageTable) - } else { + case .muc: feedIdCondition = conditionMuc(id: feed.id, messageTable: messageTable) } diff --git a/Nynja/DB/Models/DBUnreadInfo.swift b/Nynja/DB/Models/DBUnreadInfo.swift new file mode 100644 index 0000000000000000000000000000000000000000..0592cc6c4998f112f6367fabc3c5334096a6d286 --- /dev/null +++ b/Nynja/DB/Models/DBUnreadInfo.swift @@ -0,0 +1,14 @@ +// +// DBUnreadInfo.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 12/17/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import GRDBCipher + +struct DBUnreadInfo: RowConvertible, Codable { + let id: String + let unread: Int64 +} diff --git a/Nynja/DBObserver.swift b/Nynja/DBObserver.swift index 99546361620be2cf04dd912c825740bbf6a0a49f..280fa9d6faadf53635f494b444898ff4fe7cc687 100644 --- a/Nynja/DBObserver.swift +++ b/Nynja/DBObserver.swift @@ -176,17 +176,17 @@ final class DBObserver: StorageObserver, TransactionObserver { } private func handleContactDidCommit(changes: [ChangeInfo]) { - if changes.count == 1, let info = changes.first { - let contact = changedValue(from: info) as? DBContact - notify(with: info.event, entity: contact, type: .contact(nil)) - } else { - notify(with: [], type: .contact(nil)) - } + var storageChanges: [StorageChange] = [] changes.forEach { info in - let contact = changedValue(from: info) as? DBContact - notify(with: info.event, entity: contact, type: .contact(contact?.phoneId)) + let change = storageChange(from: info) + storageChanges.append(change) + + let contact = change.entity as? DBContact + notify(with: [change], type: .contact(contact?.phoneId)) } + + notify(with: storageChanges, type: .contact(nil)) } private func handleRoomDidCommit(changes: [ChangeInfo]) { diff --git a/Nynja/DatabaseManager.swift b/Nynja/DatabaseManager.swift index 3ac46cf9bc6a29a3e7b43f0e8be3ea40b395abe2..c803157bb477ad0e8d8644d26d111211d0af4d84 100644 --- a/Nynja/DatabaseManager.swift +++ b/Nynja/DatabaseManager.swift @@ -18,7 +18,7 @@ final class DatabaseManager: DBManagerProtocol { private(set) var dbPool: DatabasePool? - private let migrationsProvider = MigrationsProviderImpl() + private let migrationManager = MigrationManager() private let fileManagerService = FileManagerService.sharedInstance private let folderName = "DataBases" @@ -104,34 +104,15 @@ final class DatabaseManager: DBManagerProtocol { try $0.create(in: db) } - try fillMigrationsTable(db) + try migrationManager.fillMigrationsTable(db) return .commit } } - private func fillMigrationsTable(_ database: Database) throws { - let values = migrationsProvider.migrationTitles - - guard !values.isEmpty else { - return - } - - let tableName = "grdb_migrations" - let identifierColumn = "identifier" - - if try !database.tableExists(tableName) { - try database.execute("CREATE TABLE \(tableName) (\(identifierColumn) TEXT NOT NULL PRIMARY KEY)") - - try values.forEach { (value) in - try database.execute("insert into grdb_migrations (identifier) values('\(value)')") - } - } - } - private func performMigration() throws { if let dbPool = dbPool { - try MigrationManager().migrate(dbPool) + try migrationManager.migrate(dbPool) } } diff --git a/Nynja/Extensions/UIDeviceExtension.swift b/Nynja/Extensions/UIDeviceExtension.swift index 60e4be86e063b5b1b7dceebba2a7e0e73cb1ada3..f5d27a4bb4fab81082c0b39df2a8838beadfa4b4 100644 --- a/Nynja/Extensions/UIDeviceExtension.swift +++ b/Nynja/Extensions/UIDeviceExtension.swift @@ -82,7 +82,11 @@ extension UIDevice { "iPhone10,1" : .iPhone8, "iPhone10,2" : .iPhone8plus, "iPhone10,3" : .iPhoneX, - "iPhone10,6" : .iPhoneX + "iPhone10,6" : .iPhoneX, + "iPhone11,2": .iPhoneXS, + "iPhone11,4": .iPhoneXSMax, + "iPhone11,6": .iPhoneXSMax, + "iPhone11,8": .iPhoneXR ] if let model = modelMap[String.init(validatingUTF8: modelCode!)!] { @@ -128,6 +132,9 @@ public enum PhoneModel : String { iPhone8 = "iPhone 8", iPhone8plus = "iPhone 8 Plus", iPhoneX = "iPhone X", + iPhoneXS = "iPhone XS", + iPhoneXSMax = "iPhone XS Max", + iPhoneXR = "iPhone XR", unrecognized = "?unrecognized?" } diff --git a/Nynja/FavoritesGroupItemsFactory.swift b/Nynja/FavoritesGroupItemsFactory.swift new file mode 100644 index 0000000000000000000000000000000000000000..61149150a043fe6c5f8483d77117dd5ad3f56a94 --- /dev/null +++ b/Nynja/FavoritesGroupItemsFactory.swift @@ -0,0 +1,22 @@ +// +// FavoritesGroupItemsFactory.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 12/13/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +final class FavoritesGroupItemsFactory: GroupChatsItemsFactory { + + override var all: ImageActionItemModel { + let item = super.all + item.state = .normal + return item + } + + override var starred: ImageActionItemModel { + let item = super.starred + item.state = .highlighted + return item + } +} diff --git a/Nynja/FavoritesItemsFactory.swift b/Nynja/FavoritesItemsFactory.swift deleted file mode 100644 index 267d4dfca9c4d305f21be11d4ea3ac80de324f94..0000000000000000000000000000000000000000 --- a/Nynja/FavoritesItemsFactory.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// FavoritesItemsFactory.swift -// Nynja -// -// Created by Volodymyr Hryhoriev on 2/6/18. -// Copyright © 2018 TecSynt Solutions. All rights reserved. -// - -class FavoritesItemsFactory: WCBaseItemsFactory { - - override var home: ImageActionItemModel { - let item = super.home - // TODO: highlight (clarified by Dima designer). - return item - } - -} diff --git a/Nynja/FavoritesP2pItemsFactory.swift b/Nynja/FavoritesP2pItemsFactory.swift new file mode 100644 index 0000000000000000000000000000000000000000..08794f376e47df80a745408e0847dac37a873779 --- /dev/null +++ b/Nynja/FavoritesP2pItemsFactory.swift @@ -0,0 +1,22 @@ +// +// FavoritesP2pItemsFactory.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 12/13/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +final class FavoritesP2pItemsFactory: P2pChatsItemsFactory { + + override var all: ImageActionItemModel { + let item = super.all + item.state = .normal + return item + } + + override var starred: ImageActionItemModel { + let item = super.starred + item.state = .highlighted + return item + } +} diff --git a/Nynja/FeatureFlags/FeatureFlags.swift b/Nynja/FeatureFlags/FeatureFlags.swift new file mode 100644 index 0000000000000000000000000000000000000000..bc6fdf4fb6d03ce4e46da5581d01a6843a09686a --- /dev/null +++ b/Nynja/FeatureFlags/FeatureFlags.swift @@ -0,0 +1,69 @@ +// +// FeatureFlags.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 12/12/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation + +enum FeatureFlags { + static let isRepliesCounterEnabled: Flag = Flag(value: false, reasons: [.notReadyForVersion("0.8.0 Live"), .blockedByFeature("Threads")]) + static let isMarketplaceEnabled: Flag = Flag(value: false, reason: .notReadyForVersion("0.8.0 Live")) + static let isChatGroupingEnabled: Flag = Flag(value: false, reason: .notReadyForVersion("0.8.0 Live")) + static let isTransferActionEnabled: Flag = Flag(value: false, reason: .notReadyForVersion("0.8.0 Live")) + static let shouldShowCommingSoon: Flag = Flag(value: true, reason: .notReadyForVersion("0.8.0 Live")) +} + +extension FeatureFlags { + + struct Flag { + let value: T + let reasons: [Reason] + + init(value: T, reasons: [Reason] = []) { + self.value = value + self.reasons = reasons + } + + init (value: T, reason: Reason? = nil) { + self.init( + value: value, + reasons: reason.map { [$0] } ?? []) + } + } + + enum Reason: CustomStringConvertible { + case notReadyForVersion(String) + case blockedByFeature(String) + + var description: String { + switch self { + case let .notReadyForVersion(version): + return "Not ready for version: \(version)." + case let .blockedByFeature(feature): + return "Blocked by '\(feature)' feature." + } + } + } +} + +extension FeatureFlags.Flag: CustomStringConvertible where T: CustomStringConvertible { + + var description: String { + var text = """ + ##Feature Flag## + value: \(value) + + """ + + if !reasons.isEmpty { + text += "reasons: " + reasons + .map { $0.description } + .joined(separator: " ") + } + + return text + } +} diff --git a/Nynja/Generated/ColorsConstants.swift b/Nynja/Generated/ColorsConstants.swift index 713effb5a1ab28dada95cc238069203679fe8c6e..98d2940735e34184ab450f73a26cfc3cd883aea4 100644 --- a/Nynja/Generated/ColorsConstants.swift +++ b/Nynja/Generated/ColorsConstants.swift @@ -99,6 +99,8 @@ internal extension SGColor { static let violet = #colorLiteral(red: 0.62352943, green: 0.40784314, blue: 0.65882355, alpha: 1.0) /// 0x45484dff (r: 69, g: 72, b: 77, a: 255) static let wheelBackHighlitedGray = #colorLiteral(red: 0.27058825, green: 0.28235295, blue: 0.3019608, alpha: 1.0) + /// 0xffffff80 (r: 255, g: 255, b: 255, a: 128) + static let wheelItemDisabledColor = #colorLiteral(red: 1.0, green: 1.0, blue: 1.0, alpha: 0.5019608) /// 0x32353bff (r: 50, g: 53, b: 59, a: 255) static let wheelTopLevelSeparatorColor = #colorLiteral(red: 0.19607843, green: 0.20784314, blue: 0.23137255, alpha: 1.0) /// 0xffffffff (r: 255, g: 255, b: 255, a: 255) diff --git a/Nynja/Generated/LocalizableConstants.swift b/Nynja/Generated/LocalizableConstants.swift index 2066e5d6ed6188f5175c66a918afb5bf09d3e40e..17335aa698b9d2fe28b80d109e29ee490e750317 100644 --- a/Nynja/Generated/LocalizableConstants.swift +++ b/Nynja/Generated/LocalizableConstants.swift @@ -20,6 +20,36 @@ internal extension String { static var actions: String { return localizable.tr("Localizable", "Actions") } /// active static var active: String { return localizable.tr("Localizable", "active") } + /// active + static var activeSessionsActive: String { return localizable.tr("Localizable", "active_sessions_active") } + /// Current session + static var activeSessionsCurrentSession: String { return localizable.tr("Localizable", "active_sessions_current_session") } + /// Logs out all devices except for this one. + static var activeSessionsLogsOutAllDevices: String { return localizable.tr("Localizable", "active_sessions_logs_out_all_devices") } + /// No + static var activeSessionsNo: String { return localizable.tr("Localizable", "active_sessions_no") } + /// No Data + static var activeSessionsNoData: String { return localizable.tr("Localizable", "active_sessions_no_data") } + /// Please check Internet connection and try again. + static var activeSessionsNoInternetConnection: String { return localizable.tr("Localizable", "active_sessions_no_internet_connection") } + /// NYNJA + static var activeSessionsNynja: String { return localizable.tr("Localizable", "active_sessions_nynja") } + /// Tap on a session to terminate. + static var activeSessionsTapOnASession: String { return localizable.tr("Localizable", "active_sessions_tap_on_a_session") } + /// Terminate this session? + static var activeSessionsTerminate: String { return localizable.tr("Localizable", "active_sessions_terminate") } + /// Terminate All Other Sessions + static var activeSessionsTerminateAllOtherSessions: String { return localizable.tr("Localizable", "active_sessions_terminate_all_other_sessions") } + /// Active sessions + static var activeSessionsTitle: String { return localizable.tr("Localizable", "active_sessions_title") } + /// Undefined + static var activeSessionsUndefined: String { return localizable.tr("Localizable", "active_sessions_undefined") } + /// Waiting for Network... + static var activeSessionsWaitingForNetwork: String { return localizable.tr("Localizable", "active_sessions_waiting_for_network") } + /// Yes + static var activeSessionsYes: String { return localizable.tr("Localizable", "active_sessions_yes") } + /// Are you sure you want to terminate all other sessions? + static var activeSessionsYouSure: String { return localizable.tr("Localizable", "active_sessions_you_sure") } /// Can't add conference member static var addConferenceMemberFailed: String { return localizable.tr("Localizable", "Add_conference_member_failed") } /// Add to contacts @@ -794,7 +824,7 @@ internal extension String { static var numberOrRegionEmpty: String { return localizable.tr("Localizable", "number_or_region_empty") } /// NYNJA static var nynja: String { return localizable.tr("Localizable", "nynja") } - /// I'm using the new SuperApp! called NYNJA! It is an amazing productivity and communications app for everyone like you've never seen before https://beta.nynja.net/ + /// I'm using the new SuperApp! called NYNJA! It is an amazing productivity and communications app for everyone like you've never seen before https://www.nynja.io/ static var nynjaShareString: String { return localizable.tr("Localizable", "nynja_share_string") } /// NYNJA Support static var nynjaSupport: String { return localizable.tr("Localizable", "nynjaSupport") } @@ -958,38 +988,6 @@ internal extension String { static var searchInterpreter: String { return localizable.tr("Localizable", "search_interpreter") } /// seconds static var seconds: String { return localizable.tr("Localizable", "seconds") } - /// active - static var securityActive: String { return localizable.tr("Localizable", "security_active") } - /// Active sessions - static var securityActiveSessions: String { return localizable.tr("Localizable", "security_active_sessions") } - /// Current session - static var securityCurrentSession: String { return localizable.tr("Localizable", "security_current_session") } - /// Logs out all devices except for this one. - static var securityLogsOutAllDevices: String { return localizable.tr("Localizable", "security_logs_out_all_devices") } - /// No - static var securityNo: String { return localizable.tr("Localizable", "security_no") } - /// No Data - static var securityNoData: String { return localizable.tr("Localizable", "security_no_data") } - /// Please check Internet connection and try again. - static var securityNoInternetConnection: String { return localizable.tr("Localizable", "security_no_internet_connection") } - /// NYNJA - static var securityNynja: String { return localizable.tr("Localizable", "security_nynja") } - /// Tap on a session to terminate. - static var securityTapOnASession: String { return localizable.tr("Localizable", "security_tap_on_a_session") } - /// Terminate this session? - static var securityTerminate: String { return localizable.tr("Localizable", "security_terminate") } - /// Terminate All Other Sessions - static var securityTerminateAllOtherSessions: String { return localizable.tr("Localizable", "security_terminate_all_other_sessions") } - /// SECURITY - static var securityTitle: String { return localizable.tr("Localizable", "security_title") } - /// Undefined - static var securityUndefined: String { return localizable.tr("Localizable", "security_undefined") } - /// Waiting for Network... - static var securityWaitingForNetwork: String { return localizable.tr("Localizable", "security_waiting_for_network") } - /// Yes - static var securityYes: String { return localizable.tr("Localizable", "security_yes") } - /// Are you sure you want to terminate all other sessions? - static var securityYouSure: String { return localizable.tr("Localizable", "security_you_sure") } /// Select Country static var selectCountryTitle: String { return localizable.tr("Localizable", "select_country_title") } /// Send as File @@ -1324,14 +1322,14 @@ internal extension String { static var wheelPositionTitle: String { return localizable.tr("Localizable", "wheel position title") } /// Right hand static var wheelRightHand: String { return localizable.tr("Localizable", "wheel right hand") } + /// Active sessions + static var wheelActiveSessions: String { return localizable.tr("Localizable", "wheel_active_sessions") } /// Build number static var wheelBuildNumber: String { return localizable.tr("Localizable", "wheel_build_number") } /// Data and Storage static var wheelDataAndStorage: String { return localizable.tr("Localizable", "wheel_data_and_storage") } /// Invite Friends static var wheelInviteFriends: String { return localizable.tr("Localizable", "wheel_invite_friends") } - /// About - static var wheelItemAbout: String { return localizable.tr("Localizable", "wheel_item_about") } /// Actions static var wheelItemActions: String { return localizable.tr("Localizable", "wheel_item_actions") } /// All @@ -1348,6 +1346,10 @@ internal extension String { static var wheelItemByUsername: String { return localizable.tr("Localizable", "wheel_item_byUsername") } /// Call static var wheelItemCall: String { return localizable.tr("Localizable", "wheel_item_call") } + /// Call Сontact + static var wheelItemCallContact: String { return localizable.tr("Localizable", "wheel_item_call_contact") } + /// Call History + static var wheelItemCallHistory: String { return localizable.tr("Localizable", "wheel_item_call_history") } /// Calls static var wheelItemCalls: String { return localizable.tr("Localizable", "wheel_item_calls") } /// Camera @@ -1366,6 +1368,8 @@ internal extension String { static var wheelItemContacts: String { return localizable.tr("Localizable", "wheel_item_contacts") } /// Delete Account static var wheelItemDeleteAccount: String { return localizable.tr("Localizable", "wheel_item_deleteAccount") } + /// Dial Number + static var wheelItemDialNumber: String { return localizable.tr("Localizable", "wheel_item_dial_number") } /// DONE static var wheelItemDone: String { return localizable.tr("Localizable", "wheel_item_done") } /// Edit Profile @@ -1462,8 +1466,6 @@ internal extension String { static var wheelPosition: String { return localizable.tr("Localizable", "wheel_position") } /// Privacy static var wheelPrivacy: String { return localizable.tr("Localizable", "wheel_privacy") } - /// Security - static var wheelSecurity: String { return localizable.tr("Localizable", "wheel_security") } /// Support static var wheelSupport: String { return localizable.tr("Localizable", "wheel_support") } /// Theme diff --git a/Nynja/GroupChatsItemsFactory.swift b/Nynja/GroupChatsItemsFactory.swift index 2a8a6e67ea69b1a07f61b6b661249582ddd930ad..8a354ff97fc9ffacd8f5e16ba8ebe782258a6e41 100644 --- a/Nynja/GroupChatsItemsFactory.swift +++ b/Nynja/GroupChatsItemsFactory.swift @@ -19,23 +19,36 @@ class GroupChatsItemsFactory: ChatsItemsFactory { // MARK: - Items override var all : ImageActionItemModel { - let item = ImageActionItemModel(nameImage: "ic_list", navItem: .all, action: { [weak navigateDelegate] (item, indexPath) in - navigateDelegate?.showGroupsList(indexPath: indexPath) - }) + let item = ImageActionItemModel( + nameImage: UIImage.nynja.Wheel.WheelItems.icList.name, + navItem: .all) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showGroupsList(indexPath: indexPath) + } item.state = .highlighted return item } override var recent : ImageActionItemModel { - let item = ImageActionItemModel(nameImage: "ic_recents", navItem: .recents, action: { [weak navigateDelegate] (item, indexPath) in - navigateDelegate?.showRecentGroupChats(indexPath: indexPath) - }) - return item + return ImageActionItemModel( + nameImage: UIImage.nynja.Wheel.WheelItems.icRecents.name, + navItem: .recents) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showRecentGroupChats(indexPath: indexPath) + } + } + + override var starred: ImageActionItemModel { + return ImageActionItemModel( + nameImage: UIImage.nynja.Wheel.WheelItems.icStarred.name, + navItem: .starred) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showFavorites(indexPath: indexPath, mode: .groups) + } } override var new: WheelItemModel { - return ImageActionItemModel(nameImage: "ic_new_group", navItem: .newGroup, action: { [weak navigateDelegate] (item, indexPath) in - navigateDelegate?.showCreateGroup(indexPath: indexPath) - }) + return ImageActionItemModel( + nameImage: UIImage.nynja.Wheel.WheelItems.icNewGroup.name, + navItem: .newGroup) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showCreateGroup(indexPath: indexPath) + } } } diff --git a/Nynja/HomeItemsFactory.swift b/Nynja/HomeItemsFactory.swift index c4c64d1b6e9dbe58880dea14b42813f21752a771..b9aad501dbc6f51c7ca9755c87cb3ececdd1e203 100644 --- a/Nynja/HomeItemsFactory.swift +++ b/Nynja/HomeItemsFactory.swift @@ -42,11 +42,12 @@ class HomeItemsFactory: WCBaseItemsFactory { }) } - var videoCall: ImageFilledItemModel { - return ImageFilledItemModel(nameImage: "ic_video", navItem: .videoCall, isSelectable: false, action: { [weak navigateDelegate] (item, indexPath) in - navigateDelegate?.unavailableFunctionality() -// navigateDelegate?.conferenceVideoCall(indexPath: indexPath) - }) + var videoCall: ImageActionItemModel { + return ImageFilledItemModel( + nameImage: UIImage.nynja.Wheel.WheelItems.icVideo.name, + navItem: .videoCall) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.conferenceVideoCall(indexPath: indexPath) + }.asCommingSoon(navigateDelegate: navigateDelegate) } // MARK: - Edit Profile @@ -69,10 +70,10 @@ class HomeItemsFactory: WCBaseItemsFactory { }) } - var phoneNumber: ImageFilledItemModel { - return ImageFilledItemModel(navItem: .phoneNumber, isSelectable: false, action: { [weak navigateDelegate] (item, indexPath) in - navigateDelegate?.unavailableFunctionality() - }) + var phoneNumber: ImageActionItemModel { + return ImageFilledItemModel(navItem: .phoneNumber) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showChangeNumber(indexPath: indexPath) + }.asCommingSoon(navigateDelegate: navigateDelegate) } diff --git a/Nynja/Library/UI/ContextMenu/NynjaContextMenuItemsFactory+Messages.swift b/Nynja/Library/UI/ContextMenu/NynjaContextMenuItemsFactory+Messages.swift index a031bd1651cc52971a91472a7d3b6b284d58fa96..dda5b6bf33197f961dfaa12f6abd909503633696 100644 --- a/Nynja/Library/UI/ContextMenu/NynjaContextMenuItemsFactory+Messages.swift +++ b/Nynja/Library/UI/ContextMenu/NynjaContextMenuItemsFactory+Messages.swift @@ -10,7 +10,7 @@ import NynjaUIKit extension NynjaContextMenuItemsFactory { - convenience init(type: SendMessageType, model: BaseChatCellModel, userInfo: NynjaContextMenuUserInfo?) { + convenience init?(type: SendMessageType, model: BaseChatCellModel, userInfo: NynjaContextMenuUserInfo?) { let rows: [ContextMenuRow] switch type { case .text: @@ -28,7 +28,11 @@ extension NynjaContextMenuItemsFactory { case .sticker: rows = NynjaContextMenuItemsFactory.stickerMessageItems(for: model) case .audioCall: - rows = NynjaContextMenuItemsFactory.audioCallMessageItems(for: model) + if FeatureFlags.isMarketplaceEnabled.value { + rows = NynjaContextMenuItemsFactory.audioCallMessageItems(for: model) + } else { + return nil + } case .transfer: rows = NynjaContextMenuItemsFactory.makeTransferMessageItems(for: model) default: @@ -81,7 +85,7 @@ extension NynjaContextMenuItemsFactory { } private static func textMessageItems(for model: BaseChatCellModel) -> [ContextMenuRow] { - return [ + var rows = [ ContextMenuRow(items: [ starItem(for: model), reply(), forward(), delete()] ), @@ -89,10 +93,15 @@ extension NynjaContextMenuItemsFactory { translation(for: model), copy(), shouldAddEdit(for: model) ? edit() : placeholder()] - ), - ContextMenuRow(items: [marketplace(with: .full)] ) ] + + if FeatureFlags.isMarketplaceEnabled.value { + let marketplaceRow = ContextMenuRow(items: [marketplace(with: .full)]) + rows.append(marketplaceRow) + } + + return rows } private static func audioMessageItems(for model: BaseChatCellModel) -> [ContextMenuRow] { diff --git a/Nynja/Library/UI/Extensions/DateExtensions.swift b/Nynja/Library/UI/Extensions/DateExtensions.swift index 01dacd82ede18c1ad48139ce1a16efa82dd6aa75..08062571f703ff1e880b6d16758d3bdcbc2879b3 100644 --- a/Nynja/Library/UI/Extensions/DateExtensions.swift +++ b/Nynja/Library/UI/Extensions/DateExtensions.swift @@ -72,3 +72,14 @@ extension Date { } } } + +extension Date { + var millisecondsSince1970:Int { + return Int((self.timeIntervalSince1970 * 1000.0).rounded()) + } + + init(milliseconds:Int) { + self = Date(timeIntervalSince1970: TimeInterval(milliseconds) / 1000) + } +} + diff --git a/Nynja/Library/UI/NoInternetNavigationView.swift b/Nynja/Library/UI/NoInternetNavigationView.swift index 2f112c9dcf1be7091ed950b71638e02b50f2de6a..60bcaf1e8fa4ebf227105c754d5433462e111de5 100644 --- a/Nynja/Library/UI/NoInternetNavigationView.swift +++ b/Nynja/Library/UI/NoInternetNavigationView.swift @@ -24,7 +24,7 @@ class NoInternetNavigationView: UIView { func setUp() { backgroundColor = UIColor.nynja.mainRed - label.text = String.localizable.securityWaitingForNetwork + label.text = String.localizable.activeSessionsWaitingForNetwork } struct Constraints { diff --git a/Nynja/Library/UI/TextInput/Material/Base/MaterialTextInput.swift b/Nynja/Library/UI/TextInput/Material/Base/MaterialTextInput.swift index 039bda01277b4accfd8ff76b04a7994341f89f5a..2e1b381fb3babcdc62d7af32966f085c87f2b3e7 100644 --- a/Nynja/Library/UI/TextInput/Material/Base/MaterialTextInput.swift +++ b/Nynja/Library/UI/TextInput/Material/Base/MaterialTextInput.swift @@ -148,6 +148,10 @@ extension MaterialTextInput { } func validate(text: String) { + guard !validators.isEmpty else { + return + } + let infos = validators .map { $0.validate(text: text) } .compactMap { $0 } diff --git a/Nynja/Library/UI/UIViewController+Child.swift b/Nynja/Library/UI/UIViewController+Child.swift index 3aa0ea24da3becb35782dfad34d2bd59474278b3..5d22a3d9f4ac539ada75e71b029311aead0c7372 100644 --- a/Nynja/Library/UI/UIViewController+Child.swift +++ b/Nynja/Library/UI/UIViewController+Child.swift @@ -33,6 +33,7 @@ extension UIViewController { } extension UIViewController { + func dismissAll(animated: Bool, rootCompletion: (() -> Void)? = nil) { var vcs: [UIViewController] = [self] @@ -41,7 +42,7 @@ extension UIViewController { } func remove() { - vcs.last?.dismiss(animated: true, completion: { + vcs.last?.dismiss(animated: true) { rootCompletion?() vcs.removeLast() @@ -49,16 +50,9 @@ extension UIViewController { if vcs.last != nil { remove() } - }) + } } remove() } - - - func dismissTwoViews(){ - - self.presentingViewController?.presentingViewController?.dismiss(animated: true, completion: nil) - - } } diff --git a/Nynja/Library/UI/View/TimerView/TimerView.swift b/Nynja/Library/UI/View/TimerView/TimerView.swift index 0b4595cba84e01df6b1fc38ba9c2b76cfd7c81e0..5a5346f17fd1fb5aad7e62a8a1b6dc3b0964d16a 100644 --- a/Nynja/Library/UI/View/TimerView/TimerView.swift +++ b/Nynja/Library/UI/View/TimerView/TimerView.swift @@ -16,15 +16,21 @@ final class TimerView: UIView { //MARK: - Public extension TimerView { - func setTimeValue(seconds: Int) { + func setTimeValue(seconds: Int, animated: Bool = true) { if timerLabel == nil { timerLabel = makeTimerLabel() timerLabel?.alpha = 0 - UIView.animate(withDuration: 0.25) { [weak self] in + let layout = { [weak self] in self?.timerLabel?.alpha = 1 self?.layoutIfNeeded() } + + if animated { + UIView.animate(withDuration: 0.25, animations: layout) + } else { + layout() + } } var secondsStr = "\((seconds % 3600) % 60)" @@ -35,10 +41,16 @@ extension TimerView { minutesStr = appendZeroIfNedeed(time: minutesStr) hoursStr = appendZeroIfNedeed(time: hoursStr) - UIView.animate(withDuration: 0.25) { [weak self] in + let layout = { [weak self] in self?.timerLabel?.text = hoursStr + ":" + minutesStr + ":" + secondsStr self?.layoutIfNeeded() } + + if animated { + UIView.animate(withDuration: 0.25, animations: layout) + } else { + layout() + } } func setFontSize(size: Int) { diff --git a/Nynja/Library/UI/WheelContainer/Wheel/ItemModels/CommingSoonWheelItemModel.swift b/Nynja/Library/UI/WheelContainer/Wheel/ItemModels/CommingSoonWheelItemModel.swift new file mode 100644 index 0000000000000000000000000000000000000000..5633f7232db5befdbe7ce19994fef028f8ae8d83 --- /dev/null +++ b/Nynja/Library/UI/WheelContainer/Wheel/ItemModels/CommingSoonWheelItemModel.swift @@ -0,0 +1,63 @@ +// +// CommingSoonWheelItemModel.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 12/13/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +final class CommingSoonWheelItemModel: ImageActionItemModel { + + override var backgroundColor: [WheelItemState : UIColor]! { + get { + return item.backgroundColor + } + } + + override var contentColor : [WheelItemState: UIColor]! { + get { + return [.normal : WheelItemState.disabled.defaultContentColor, + .disabled : WheelItemState.disabled.defaultContentColor, + .selected : WheelItemState.selected.defaultContentColor, + .highlighted : WheelItemState.highlighted.defaultContentColor + ] + } + } + + private var item: ImageActionItemModel! + + init(item: ImageActionItemModel, navigateDelegate: NavigateProtocol?) { + self.item = item + + super.init( + nameImage: item.nameImage, + navItem: item.navItem, + isSelectable: false) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.unavailableFunctionality() + } + } + + override init(model: WheelItemModel) { + super.init(model: model) + + if let _model = model as? CommingSoonWheelItemModel { + self.item = _model.item + } + } + + override func cloned() -> CommingSoonWheelItemModel { + return CommingSoonWheelItemModel(model: self) + } +} + + +extension ImageActionItemModel { + + func asCommingSoon(navigateDelegate: NavigateProtocol?) -> ImageActionItemModel { + if FeatureFlags.shouldShowCommingSoon.value { + return CommingSoonWheelItemModel(item: self, navigateDelegate: navigateDelegate) + } + + return self + } +} diff --git a/Nynja/Library/UI/WheelContainer/Wheel/ItemModels/ImageActionItemModel.swift b/Nynja/Library/UI/WheelContainer/Wheel/ItemModels/ImageActionItemModel.swift index aa558f1777a4e8bd99a4cb238a28de8b400df3d1..9476a2b6423eba2e8dda5e525339189b100bdff2 100644 --- a/Nynja/Library/UI/WheelContainer/Wheel/ItemModels/ImageActionItemModel.swift +++ b/Nynja/Library/UI/WheelContainer/Wheel/ItemModels/ImageActionItemModel.swift @@ -15,7 +15,7 @@ class ImageActionItemModel: ImageWheelItemModel { isSelectable: Bool = true, action: ItemAction? = nil) { - super.init(nameImage: nameImage ?? "", navItem: navItem, action: action ) + super.init(nameImage: nameImage ?? "", navItem: navItem, action: action) self.isUserInteractionEnabled = isUserInteractionEnabled self.isSelectable = isSelectable diff --git a/Nynja/Library/UI/WheelContainer/Wheel/ItemModels/WheelItemModel.swift b/Nynja/Library/UI/WheelContainer/Wheel/ItemModels/WheelItemModel.swift index 76aea093048c2ab17870e0df6928ce1bb628795c..efaed3598c057f8c0c9393c062e7231c137b30a1 100644 --- a/Nynja/Library/UI/WheelContainer/Wheel/ItemModels/WheelItemModel.swift +++ b/Nynja/Library/UI/WheelContainer/Wheel/ItemModels/WheelItemModel.swift @@ -17,10 +17,8 @@ enum WheelItemState : Int { case selected case highlighted - var defaultBackgroundColor : UIColor { + var defaultBackgroundColor: UIColor { switch self { - case .normal: - return UIColor.nynja.clear case .selected: return UIColor.nynja.mainRed case .highlighted: @@ -30,10 +28,10 @@ enum WheelItemState : Int { } } - var defaultContentColor : UIColor { + var defaultContentColor: UIColor { switch self { case .disabled: - return UIColor.nynja.contentDisabledGray + return UIColor.nynja.wheelItemDisabledColor default: return UIColor.nynja.white } @@ -41,12 +39,8 @@ enum WheelItemState : Int { var defaultMarkerColor : UIColor { switch self { - case .normal: - return UIColor.nynja.mainRed case .selected: return UIColor.nynja.darkRed - case .highlighted: - return UIColor.nynja.mainRed default: return UIColor.nynja.mainRed } diff --git a/Nynja/MigrationManager.swift b/Nynja/MigrationManager.swift new file mode 100644 index 0000000000000000000000000000000000000000..940a922b49e725d8efebf357d9a4f219a84a79b2 --- /dev/null +++ b/Nynja/MigrationManager.swift @@ -0,0 +1,93 @@ +// +// MigrationManager.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 12/11/17. +// Copyright © 2017 TecSynt Solutions. All rights reserved. +// + +import GRDBCipher + +enum Migration: Int, Describable { + case addSeenByColumnToMessage = 0 + case updateDBFeatureTargetTypes + case addAutoColumnToConvertMessage + + static var allTitles: [String] = { + var i = 0 + + var strings: [String] = [] + + while let migration = Migration(rawValue: i) { + i += 1 + strings.append(migration.title) + } + + return strings + }() +} + +final class MigrationManager { + + private var migrator: DatabaseMigrator + + init() { + migrator = DatabaseMigrator() + registerMigrations() + } + + + // MARK: - Migrate + + func migrate(to migration: Migration?, poolOrQueue: DatabaseWriter) throws { + do { + if let migration = migration { + try migrator.migrate(poolOrQueue, upTo: migration.title) + } else { + try migrator.migrate(poolOrQueue) + } + } catch let error { + LogService.log(topic: .db) { return error.localizedDescription } + } + } + + + // MARK: - Private methods + + private func registerMigrations() { + + migrator.registerMigration(.addSeenByColumnToMessage) { db in + try MessageTable.alter(in: db) { t in + t.add(column: MessageTable.Column.seenBy, .text) + } + } + + migrator.registerMigration(.updateDBFeatureTargetTypes) { db in + let targetType = Column(FeatureTable.Column.targetType.title) + let sql = """ + UPDATE \(FeatureTable.name) + SET \(targetType.name) = ? + WHERE \(targetType.name) = ? + """ + + try db.execute(sql, arguments: [DBFeature.TargetType.message.rawValue, "desc"]) + try db.execute(sql, arguments: [DBFeature.TargetType.job.rawValue, "schedule"]) + } + + migrator.registerMigration(.addAutoColumnToConvertMessage) { db in + try ConvertMessageTable.alter(in: db) { t in + t.add(column: ConvertMessageTable.Column.auto, .boolean) + } + } + } +} + + +// MARK: - DatabaseMigrator + +private extension DatabaseMigrator { + + mutating func registerMigration(_ migration: Migration, migrate: @escaping (Database) throws -> Void) { + registerMigration(migration.title, migrate: migrate) + } +} diff --git a/Nynja/MigrationManager/Migration.swift b/Nynja/MigrationManager/Migration.swift index 9056538d26a746b88ab830cb2a96968b4c81fd2a..2c346011a6242a371d4fe5b77b74aac070a610c5 100644 --- a/Nynja/MigrationManager/Migration.swift +++ b/Nynja/MigrationManager/Migration.swift @@ -10,7 +10,7 @@ import GRDBCipher protocol Migration { var identifier: String { get } - var isDisabledFKConstraints: Bool { get } + var isDisabledForeignKeyConstraints: Bool { get } func migrate(_ db: Database) throws } @@ -23,7 +23,7 @@ extension Migration { return "\(firstLetter)\(remainder)" } - var isDisabledFKConstraints: Bool { + var isDisabledForeignKeyConstraints: Bool { return false } } diff --git a/Nynja/MigrationManager/MigrationManager.swift b/Nynja/MigrationManager/MigrationManager.swift index 79ee1bad815b0c8f7797fbba8da1adb0b4a5448a..a3f98817fe3b7f38af6623da5cae2f9a96277d79 100644 --- a/Nynja/MigrationManager/MigrationManager.swift +++ b/Nynja/MigrationManager/MigrationManager.swift @@ -31,12 +31,30 @@ final class MigrationManager { } } + func fillMigrationsTable(_ db: Database) throws { + let values = migrationsProvider.migrationTitles + + guard !values.isEmpty else { + return + } + + let tableName = "grdb_migrations" + let identifierColumn = "identifier" + + if try !db.tableExists(tableName) { + try db.execute("CREATE TABLE \(tableName) (\(identifierColumn) TEXT NOT NULL PRIMARY KEY)") + + try values.forEach { (value) in + try db.execute("insert into grdb_migrations (identifier) values('\(value)')") + } + } + } // MARK: - Private methods private func registerMigrations() { migrationsProvider.migrations.forEach { migration in - if migration.isDisabledFKConstraints { + if migration.isDisabledForeignKeyConstraints { migrator.registerMigrationWithDeferredForeignKeyCheck(migration.identifier, migrate: migration.migrate) } else { migrator.registerMigration(migration.identifier, migrate: migration.migrate) diff --git a/Nynja/MigrationManager/Migrations/RemoveP2pAndMucTables.swift b/Nynja/MigrationManager/Migrations/RemoveP2pAndMucTables.swift index e8fd8e39b2a1edecbe789f358cd785e218fd06e1..a08f44e69b0cefccb60828413f0c8e537da68e57 100644 --- a/Nynja/MigrationManager/Migrations/RemoveP2pAndMucTables.swift +++ b/Nynja/MigrationManager/Migrations/RemoveP2pAndMucTables.swift @@ -10,7 +10,7 @@ import GRDBCipher final class RemoveP2pAndMucTables: Migration { - var isDisabledFKConstraints: Bool { + var isDisabledForeignKeyConstraints: Bool { return true } diff --git a/Nynja/Modules/Auth/Login/Interactor/LoginInteractor.swift b/Nynja/Modules/Auth/Login/Interactor/LoginInteractor.swift index 9e673cac10c137eaa50911a40f51a652cbbf88de..7215b961b2d72de465c75674abf76c78360b1e70 100644 --- a/Nynja/Modules/Auth/Login/Interactor/LoginInteractor.swift +++ b/Nynja/Modules/Auth/Login/Interactor/LoginInteractor.swift @@ -12,19 +12,25 @@ class LoginInteractor: BaseInteractor, LoginInteractorInputProtocol, IoHandlerDe private var mqttService: MQTTService! - private var phone: String? + private var phone: String? { + didSet { + if oldValue != phone { + accessDenied = false + } + } + } private var isBadProtocolVersion: Bool = false private var connectionTimerHandler: TimerHandler? + private var accessDenied: Bool = false // MARK: - Configure func configure() { IoHandler.delegate = self mqttService.addSubscriber(self) - mqttService.tryReconnect() } deinit { @@ -52,6 +58,7 @@ class LoginInteractor: BaseInteractor, LoginInteractorInputProtocol, IoHandlerDe } func numberNotAllowed() { + accessDenied = true presenter.numberNotAllowed() } @@ -68,7 +75,7 @@ class LoginInteractor: BaseInteractor, LoginInteractorInputProtocol, IoHandlerDe func mqttServiceDidConnect(_ mqttService: MQTTService) { invalidateConnectionTimer() - if let phone = phone { + if let phone = phone, !accessDenied { login(phone: phone) } } diff --git a/Nynja/Modules/Auth/Login/View/LoginViewController.swift b/Nynja/Modules/Auth/Login/View/LoginViewController.swift index d0ac878f79b4630372d22bf925bff8509472fec5..cb3357cca1fa841c49c973b6ce4e07c06251d728 100644 --- a/Nynja/Modules/Auth/Login/View/LoginViewController.swift +++ b/Nynja/Modules/Auth/Login/View/LoginViewController.swift @@ -19,6 +19,8 @@ class LoginViewController: BaseVC, LoginViewProtocol, LoginWheelContainerViewPro let util = NBPhoneNumberUtil.sharedInstance() var isContainerShown = false + private var keyboardEnabled = false + /// Responsible for items for wheel container var wheelContainerDS: LoginWheelContainerDataSource! @@ -92,9 +94,10 @@ class LoginViewController: BaseVC, LoginViewProtocol, LoginWheelContainerViewPro override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) - - showContainer() - isContainerShown = true + if !keyboardEnabled { + showContainer() + isContainerShown = true + } } // MARK: Configure views @@ -141,6 +144,7 @@ class LoginViewController: BaseVC, LoginViewProtocol, LoginWheelContainerViewPro self.loginView.nextButton.snp.updateConstraints({ (make) in make.bottom.equalTo(self.loginView).inset(bottomInset) }) + keyboardEnabled = false } else { if isContainerShown { hideContainer() @@ -150,6 +154,7 @@ class LoginViewController: BaseVC, LoginViewProtocol, LoginWheelContainerViewPro self.loginView.nextButton.snp.updateConstraints({ (make) in make.bottom.equalTo(self.loginView).inset(endFrame.height + bottomInset) }) + keyboardEnabled = true } } diff --git a/Nynja/Modules/ChatsList/Interactor/ChatsListInteractor.swift b/Nynja/Modules/ChatsList/Interactor/ChatsListInteractor.swift index 1698753810b5910be5b64dae4f346e5dbacd2721..6dde34fcda20a9cb35b2bb00a572d87ec0458c22 100644 --- a/Nynja/Modules/ChatsList/Interactor/ChatsListInteractor.swift +++ b/Nynja/Modules/ChatsList/Interactor/ChatsListInteractor.swift @@ -102,8 +102,7 @@ class ChatsListInteractor: BaseInteractor, ChatsListInteractorInputProtocol, Ini } private func updateChatsList(with contact: Contact) -> [Contact] { - guard let phoneId = contact.phone_id, - phoneId != storageService.phoneId else { + guard let phoneId = contact.phone_id else { return chats } diff --git a/Nynja/Modules/Contacts/View/ViewController/ContactsViewController.swift b/Nynja/Modules/Contacts/View/ViewController/ContactsViewController.swift index c3422ff1236bed945ff8764007f956660c69bafa..0324b414adc49d7e6f88affe6beda8033ea72544 100644 --- a/Nynja/Modules/Contacts/View/ViewController/ContactsViewController.swift +++ b/Nynja/Modules/Contacts/View/ViewController/ContactsViewController.swift @@ -8,7 +8,7 @@ import UIKit -class ContactsViewController: BaseVC, ContactsViewProtocol, ContactCellDelegate, FastScrollable, KeyboardInteractive { +class ContactsViewController: BaseVC, ContactsViewProtocol, ContactCellDelegate, FastScrollable, KeyboardInteractive, BackSwipable { var presenter: ContactsPresenterProtocol! { didSet { @@ -23,6 +23,10 @@ class ContactsViewController: BaseVC, ContactsViewProtocol, ContactCellDelegate, return dataSource }() + private(set) lazy var swipeBackHelper: SwipeBackHelper = { + return SwipeBackHelper(with: self) + }() + var scrollBar: ScrollBar? var scrollOffset: CGFloat = 0 @@ -108,7 +112,7 @@ class ContactsViewController: BaseVC, ContactsViewProtocol, ContactCellDelegate, // MARK: - BaseVC override func initialize() { super.initialize() - + swipeBackHelper.addGesture() scrollBar = ScrollBar(scrollView: tableView) scrollBar?.verticalInset = ScrollBar.VerticalInset(top: 0, bottom: 0) scrollBar?.shouldShowAction = { [unowned self] in diff --git a/Nynja/Modules/Favorites/Entities/FavoritesMode.swift b/Nynja/Modules/Favorites/Entities/FavoritesMode.swift new file mode 100644 index 0000000000000000000000000000000000000000..db0145c455f8bc25da85425205cfd25dd9de3d80 --- /dev/null +++ b/Nynja/Modules/Favorites/Entities/FavoritesMode.swift @@ -0,0 +1,13 @@ +// +// FavoritesMode.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 12/13/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +enum FavoritesMode { + case chats + case groups + case home +} diff --git a/Nynja/Modules/Favorites/FavoritesProtocols.swift b/Nynja/Modules/Favorites/FavoritesProtocols.swift index e4c98f353448ec3956425ff31c49a6e589fa3b28..0fa79db3817ccb79799c45cb51a15b351377f018 100644 --- a/Nynja/Modules/Favorites/FavoritesProtocols.swift +++ b/Nynja/Modules/Favorites/FavoritesProtocols.swift @@ -10,7 +10,7 @@ import UIKit protocol FavoritesWireFrameProtocol: class { - func presentFavorites(navigation: UINavigationController, main: MainWireFrame?) + func presentFavorites(navigation: UINavigationController, main: MainWireFrame?, mode: FavoritesMode) /** * Add here your methods for communication PRESENTER -> WIREFRAME diff --git a/Nynja/Modules/Favorites/Presenter/FavoritesPresenter.swift b/Nynja/Modules/Favorites/Presenter/FavoritesPresenter.swift index f1661ea99fcf19f449f17e184386587ac93a53c9..947746787acf36019a396b53533e9bd58fcf693c 100644 --- a/Nynja/Modules/Favorites/Presenter/FavoritesPresenter.swift +++ b/Nynja/Modules/Favorites/Presenter/FavoritesPresenter.swift @@ -9,11 +9,19 @@ class FavoritesPresenter: BasePresenter, FavoritesPresenterProtocol, FavoritesInteractorOutputProtocol { override var itemsFactory: WCItemsFactory? { - return FavoritesItemsFactory() + switch mode! { + case .chats: + return FavoritesP2pItemsFactory() + case .groups: + return FavoritesGroupItemsFactory() + case .home: + return WCBaseItemsFactory() + } } weak var view: FavoritesViewProtocol! var wireFrame: FavoritesWireFrameProtocol! + var mode: FavoritesMode! var interactor: FavoritesInteractorInputProtocol! { didSet { @@ -46,5 +54,4 @@ class FavoritesPresenter: BasePresenter, FavoritesPresenterProtocol, FavoritesIn func deleteStar(_ star: Star) { interactor.deleteStar(star) } - } diff --git a/Nynja/Modules/Favorites/WireFrame/FavoritesWireframe.swift b/Nynja/Modules/Favorites/WireFrame/FavoritesWireframe.swift index a296e7d1750a72ea95a35a07867754ae3bca3a56..ad92e0a0f082b59880f9bf01e4d72a6af6ab533e 100644 --- a/Nynja/Modules/Favorites/WireFrame/FavoritesWireframe.swift +++ b/Nynja/Modules/Favorites/WireFrame/FavoritesWireframe.swift @@ -14,7 +14,7 @@ class FavoritesWireFrame: FavoritesWireFrameProtocol { weak var main: MainWireFrame? - func presentFavorites(navigation: UINavigationController, main: MainWireFrame?) { + func presentFavorites(navigation: UINavigationController, main: MainWireFrame?, mode: FavoritesMode) { let view = FavoritesViewController() let presenter = FavoritesPresenter() let interactor = FavoritesInteractor() @@ -24,13 +24,15 @@ class FavoritesWireFrame: FavoritesWireFrameProtocol { // Connecting view.presenter = presenter + presenter.view = view presenter.wireFrame = self presenter.interactor = interactor + presenter.mode = mode + interactor.presenter = presenter navigation.pushViewController(view as UIViewController, animated: false) - //self.navigation?.viewControllers = [view] } func showChat(with contact: Contact, message: Message? = nil) { diff --git a/Nynja/Modules/Flows/CameraFlow/CameraCoordinator.swift b/Nynja/Modules/Flows/CameraFlow/CameraCoordinator.swift index d794fabb4a198fb1ed94722c5a08416e5cedb035..f60eae879329d6d3c1b466ad3d24396646d1e895 100644 --- a/Nynja/Modules/Flows/CameraFlow/CameraCoordinator.swift +++ b/Nynja/Modules/Flows/CameraFlow/CameraCoordinator.swift @@ -18,7 +18,7 @@ final class CameraFlowCoordinator: CameraFlowCoordinatorProtocol, SetInjectable private var rootViewController: UIViewController! private var serviceFactory: ServiceFactoryProtocol! - private var mainFlowVC: UIViewController? + private var mainFlowVC: UINavigationController? } // MARK: - Injectable @@ -54,9 +54,12 @@ extension CameraFlowCoordinator { cameraSettingsService: serviceFactory.makeCameraSettingsService(with: .cameraFlow), locationService: serviceFactory.makeLocationService())) - mainFlowVC = view + let navigationController = UINavigationController(rootViewController: view) + navigationController.isNavigationBarHidden = true + + mainFlowVC = navigationController - rootViewController.present(view, animated: true, completion: nil) + rootViewController.present(navigationController, animated: true, completion: nil) } func end() { @@ -69,11 +72,16 @@ extension CameraFlowCoordinator { extension CameraFlowCoordinator { func wireframe(_ wireframe: CameraWireframe, with mainView: UIViewController, didEndWith state: CameraWireframe.State) { switch state { - case .back, .send: mainView.dismiss(animated: true, completion: nil) - case .continueWithImage(let image): self.cameraWireframe(wireframe, with: mainView, didEndWith: image) - case .continueWithVideoUrl(let videoURL): self.cameraWireframe(wireframe, with: mainView, didEndWith: videoURL) - case .settings: cameraWireframeOpenSettings(wireframe, with: mainView) - case .continueWithQRCode(let qrCode): cameraWireframeOpenQRCodePreview(wireframe, with: mainView, text: qrCode) + case .back, .send: + end() + case .continueWithImage(let image): + cameraWireframe(wireframe, with: mainView, didEndWith: image) + case .continueWithVideoUrl(let videoURL): + cameraWireframe(wireframe, with: mainView, didEndWith: videoURL) + case .settings: + cameraWireframeOpenSettings(wireframe, with: mainView) + case .continueWithQRCode(let qrCode): + cameraWireframeOpenQRCodePreview(wireframe, with: mainView, text: qrCode) } } @@ -81,40 +89,53 @@ extension CameraFlowCoordinator { let wireframe = PhotoPreviewWireframe(coordinator: self) let view = wireframe.prepareModule( - parameters: PhotoPreviewWireframe.Parameters( + parameters: .init( image: image, isCanSave: true, isHaveAdditionalFunctionality: true, isHaveCrop: false, - source: .chat), - dependencies: PhotoPreviewWireframe.Dependencies( + source: .chat + ), + dependencies: .init( resourceManager: serviceFactory.makeResourceManager(), - cameraSettingsService: serviceFactory.makeCameraSettingsService(with: .cameraFlow))) - - mainView.present(view, animated: false, completion: nil) + cameraSettingsService: serviceFactory.makeCameraSettingsService(with: .cameraFlow) + ) + ) + + mainFlowVC?.pushViewController(view, animated: true) } private func cameraWireframe(_ cameraWireframe: CameraWireframe, with mainView: UIViewController, didEndWith videoURL: URL) { let wireframe = CameraVideoPreviewWireframe(coordinator: self) let view = wireframe.prepareModule( - parameters: CameraVideoPreviewWireframe.Parameters(videoURL: videoURL, contact: contact, room: room, isCanSave: true), - dependencies: CameraVideoPreviewWireframe.Dependencies( + parameters: .init( + videoURL: videoURL, + contact: contact, + room: room, + isCanSave: true + ), + dependencies: .init( resourceManager: serviceFactory.makeResourceManager(), audioSessionManager: serviceFactory.makeAudioSessionManager(), messageFactory: serviceFactory.makeMessageFactory(), messageSendingService: serviceFactory.makeMessageSendingService(), - cameraSettingsService: serviceFactory.makeCameraSettingsService(with: .cameraFlow))) - - mainView.present(view, animated: false, completion: nil) + cameraSettingsService: serviceFactory.makeCameraSettingsService(with: .cameraFlow) + ) + ) + + mainFlowVC?.pushViewController(view, animated: true) } private func cameraWireframeOpenSettings(_ cameraWireframe: CameraWireframe, with mainView: UIViewController) { let cameraSettingsCoordinator = CameraSettingsFlowCoordinator() cameraSettingsCoordinator.inject( - dependencies: CameraSettingsFlowCoordinator.Dependencies( + dependencies: .init( rootViewController: mainView, - serviceFactory: serviceFactory, sourceFlow: .cameraFlow)) + serviceFactory: serviceFactory, + sourceFlow: .cameraFlow + ) + ) cameraSettingsCoordinator.start() } @@ -123,12 +144,18 @@ extension CameraFlowCoordinator { let qrCodePreviewWireframe = CameraQRPreviewWireframe(coordinator: self) let view = qrCodePreviewWireframe.prepareModule( - parameters: CameraQRPreviewWireframe.Parameters(text: text, contact: contact, room: room), - dependencies: CameraQRPreviewWireframe.Dependencies( + parameters: .init( + text: text, + contact: contact, + room: room + ), + dependencies: .init( messageFactory: serviceFactory.makeMessageFactory(), - messageSendingService: serviceFactory.makeMessageSendingService())) + messageSendingService: serviceFactory.makeMessageSendingService() + ) + ) - mainView.present(view, animated: true, completion: nil) + mainFlowVC?.pushViewController(view, animated: true) } } @@ -137,7 +164,9 @@ extension CameraFlowCoordinator { extension CameraFlowCoordinator { func wireframe(_ wireframe: PhotoPreviewWireframe, with mainView: UIViewController, didEndWithState state: PhotoPreviewWireframe.State) { switch state { - case .back: mainView.dismiss(animated: false, completion: nil) + case .back: + mainFlowVC?.popViewController(animated: true) + case .send(let imageURL): let messageFactory = serviceFactory.makeMessageFactory() let messageSendingService = serviceFactory.makeMessageSendingService() @@ -163,8 +192,10 @@ extension CameraFlowCoordinator { extension CameraFlowCoordinator { func wireframe(_ vwireframe: CameraVideoPreviewWireframe, with mainView: UIViewController, didEndWithState state: CameraVideoPreviewWireframe.State) { switch state { - case .back: mainView.dismiss(animated: false, completion: nil) - case .send: end() + case .back: + mainFlowVC?.popViewController(animated: true) + case .send: + end() } } } @@ -174,8 +205,10 @@ extension CameraFlowCoordinator { extension CameraFlowCoordinator { func wireframe(_ wireframe: CameraQRPreviewWireframe, with mainView: UIViewController, didEndWithState state: CameraQRPreviewWireframe.State) { switch state { - case .back: mainView.dismiss(animated: false, completion: nil) - case .send: end() + case .back: + mainFlowVC?.popViewController(animated: true) + case .send: + end() } } } diff --git a/Nynja/Modules/Flows/CameraFlow/PhotoPreview/View/PhotoPreviewViewController.swift b/Nynja/Modules/Flows/CameraFlow/PhotoPreview/View/PhotoPreviewViewController.swift index edf8dc83ddc3d65fdaa73615d892a4f2ca86c63f..7634a1f6c2b0a9f9a6a64ce0e6498fffbd31034e 100644 --- a/Nynja/Modules/Flows/CameraFlow/PhotoPreview/View/PhotoPreviewViewController.swift +++ b/Nynja/Modules/Flows/CameraFlow/PhotoPreview/View/PhotoPreviewViewController.swift @@ -165,7 +165,8 @@ extension PhotoPreviewViewController { title: presenter.getTitle(), navigationHandler: presenter, backButtonImage: UIImage.nynja.icBackNavigation.image)) - + headerView.backgroundColor = UIColor.nynja.darkLight + statusBarBackgroundView.backgroundColor = UIColor.nynja.darkLight headerView.layer.zPosition = 1 makeFooterView(isHaveAdditionalFunctionality: presenter.isHaveAdditionalFunctionality) diff --git a/Nynja/Modules/Flows/CameraFlow/VideoPreview/Presenter/CameraVideoPreviewPresenter.swift b/Nynja/Modules/Flows/CameraFlow/VideoPreview/Presenter/CameraVideoPreviewPresenter.swift index 1e864adbbab1a2bbc0a1ad9edfeda1916c7e8117..440faaabe0286c4b1a1543c2026d3c935ac58af9 100644 --- a/Nynja/Modules/Flows/CameraFlow/VideoPreview/Presenter/CameraVideoPreviewPresenter.swift +++ b/Nynja/Modules/Flows/CameraFlow/VideoPreview/Presenter/CameraVideoPreviewPresenter.swift @@ -11,7 +11,7 @@ import Foundation final class CameraVideoPreviewPresenter: CameraVideoPreviewPresenterProtocol, CameraVideoPreviewOutputInteractorProtocol, SetInjectable { private var interactor: CameraVideoPreviewInputInteractorProtocol! private var wireframe: CameraVideoPreviewWireframe! - private var view: CameraVideoPreviewViewProtocol! + private weak var view: CameraVideoPreviewViewProtocol! } //MARK: - CameraVideoPreviewPresenterProtocol diff --git a/Nynja/Modules/Flows/CameraFlow/VideoPreview/View/CameraVideoPreviewViewController.swift b/Nynja/Modules/Flows/CameraFlow/VideoPreview/View/CameraVideoPreviewViewController.swift index 8325918a18cbd24f195694d6b095740be2fef7ce..45a373ec86bf4fd81f299f4ac793c660f2024003 100644 --- a/Nynja/Modules/Flows/CameraFlow/VideoPreview/View/CameraVideoPreviewViewController.swift +++ b/Nynja/Modules/Flows/CameraFlow/VideoPreview/View/CameraVideoPreviewViewController.swift @@ -48,13 +48,9 @@ final class CameraVideoPreviewViewController: UIViewController, CameraVideoPrevi private weak var playButton: UIButton! - private weak var screenshot: UIView? - override func viewDidLoad() { super.viewDidLoad() - - UINavigationBar.appearance().tintColor = UIColor.nynja.darkLight - + videoPreviewView = makeVideoPreviewView(on: view) statusBarBackgroundView = UIView.makeStatusBarBackgroundView(on: view) @@ -68,6 +64,9 @@ final class CameraVideoPreviewViewController: UIViewController, CameraVideoPrevi navigationHandler: presenter, backButtonImage: UIImage.nynja.icBackNavigation.image)) + // FIXME: remove it and replace with normal navigation view + ([statusBarBackgroundView, headerView] as [UIView]).forEach { $0.backgroundColor = UIColor.nynja.darkLight } + timerView = makeTimerView(on: headerView) footerView = makeFooterView(on: view) @@ -93,33 +92,7 @@ final class CameraVideoPreviewViewController: UIViewController, CameraVideoPrevi setupNotifications() - timerView.setTimeValue(seconds: presenter.getVideoLenghtInSeconds()) - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - if let screenshot = presentingViewController?.view.snapshotView(afterScreenUpdates: false) { - view.addSubview(screenshot) - self.screenshot = screenshot - - screenshot.snp.makeConstraints { (maker) in - maker.top.left.right.bottom.equalToSuperview() - } - } - } - - override func viewDidAppear(_ animated: Bool) { - super.viewWillDisappear(animated) - - UIView.animate( - withDuration: 0.25, - animations: { [weak self] in - self?.screenshot?.alpha = 0 - self?.setNeedsStatusBarAppearanceUpdate() - }) { [weak self] (result) in - self?.screenshot?.removeFromSuperview() - } + timerView.setTimeValue(seconds: presenter.getVideoLenghtInSeconds(), animated: false) } override func viewDidLayoutSubviews() { @@ -256,7 +229,7 @@ private extension CameraVideoPreviewViewController { func makeTimerView(on view: UIView) -> TimerView { let timerView = TimerView() view.addSubview(timerView) - timerView.setTimeValue(seconds: 0) + timerView.setTimeValue(seconds: 0, animated: false) timerView.snp.makeConstraints { (maker) in maker.bottom.equalTo(view).offset(-TimerViewlayout.bottom) @@ -498,12 +471,12 @@ private extension CameraVideoPreviewViewController { // MARK: - Layout extension CameraVideoPreviewViewController { - struct TimerViewlayout { + enum TimerViewlayout { static let right = 17 static let bottom = 9 } - struct FooterViewLayout { + enum FooterViewLayout { static let collapsedHeight = 100.adjustedByHeight static let expandedHeight = 180.adjustedByHeight @@ -511,7 +484,7 @@ extension CameraVideoPreviewViewController { static let arrowWidth = 44 } - struct SendButtonLayout { + enum SendButtonLayout { static let right = 16.adjustedByWidth static let width = 77.adjustedByHeight static let height = 44.adjustedByHeight @@ -519,28 +492,28 @@ extension CameraVideoPreviewViewController { static let cornerRadius = height / 2 } - struct SendAsFileButtonLayout { + enum SendAsFileButtonLayout { static let bottom = 22 } - struct SaveButtonLayout { + enum SaveButtonLayout { static let left = 16.adjustedByWidth static let height = 44.adjustedByHeight } - struct PlayerButtonLayout { + enum PlayerButtonLayout { static let height = 44.adjustedByHeight static let width = 44.adjustedByWidth } - struct MuteButtonLayout { + enum MuteButtonLayout { static let width = 50.adjustedByHeight static let height = 50.adjustedByHeight static let left = 16.adjustedByWidth static let bottom = 20.adjustedByHeight } - struct ProgressViewLayout { + enum ProgressViewLayout { static let height = 3 } } diff --git a/Nynja/Modules/Flows/CameraFlow/VideoPreview/View/Subviews/VideoPreviewView.swift b/Nynja/Modules/Flows/CameraFlow/VideoPreview/View/Subviews/VideoPreviewView.swift index 2a4904f7df64cbc4e493e6b47ec87db9f6defe0f..02b07fc33f7ca209f1c54e0bf5e0d771d7055b52 100644 --- a/Nynja/Modules/Flows/CameraFlow/VideoPreview/View/Subviews/VideoPreviewView.swift +++ b/Nynja/Modules/Flows/CameraFlow/VideoPreview/View/Subviews/VideoPreviewView.swift @@ -13,6 +13,10 @@ class VideoPreviewView: UIView { override func layoutSublayers(of layer: CALayer) { super.layoutSublayers(of: layer) + + CATransaction.begin() + CATransaction.setDisableActions(true) playerLayer?.frame = bounds + CATransaction.commit() } } diff --git a/Nynja/Modules/Flows/CameraSettingsFlow/CameraSettings/Interactor/CameraSettingsInteractor.swift b/Nynja/Modules/Flows/CameraSettingsFlow/CameraSettings/Interactor/CameraSettingsInteractor.swift index 9de9413ee1a57fd03ca834f0846a465c772ea2a0..8cb3e6699c3c7527c24bb517e490ec1102b49973 100644 --- a/Nynja/Modules/Flows/CameraSettingsFlow/CameraSettings/Interactor/CameraSettingsInteractor.swift +++ b/Nynja/Modules/Flows/CameraSettingsFlow/CameraSettings/Interactor/CameraSettingsInteractor.swift @@ -9,7 +9,7 @@ import Foundation final class CameraSettingsInteractor: CameraSettingsInputInteractorProtocol, SetInjectable { - private var presenter: CameraSettingsOutputInteractorProtocol! + private weak var presenter: CameraSettingsOutputInteractorProtocol! private var cameraSettingsService: CameraSettingsServiceProtocol! private var locationService: LocationService! private let appNotificationsProvider = AppNotificationsProvider() diff --git a/Nynja/Modules/Flows/CreateGroupFlow/CreateGroup/WireFrame/CreateGroupWireframe.swift b/Nynja/Modules/Flows/CreateGroupFlow/CreateGroup/WireFrame/CreateGroupWireframe.swift index 8fcddd64150e919e448db1261711911997429635..1b159fcb14e18e3a4ef858935015404559cfc59a 100644 --- a/Nynja/Modules/Flows/CreateGroupFlow/CreateGroup/WireFrame/CreateGroupWireframe.swift +++ b/Nynja/Modules/Flows/CreateGroupFlow/CreateGroup/WireFrame/CreateGroupWireframe.swift @@ -14,7 +14,7 @@ class CreateGroupWireFrame: CreateGroupWireFrameProtocol { weak var external: CreateGroupExternalProtocol? weak var mainWireFrame: MainWireFrame? - func presentCreateGroup(navigation: UINavigationController, mainWireFrame: MainWireFrame?,contacts: [Contact]) { + func presentCreateGroup(navigation: UINavigationController, mainWireFrame: MainWireFrame?, contacts: [Contact]) { let view = CreateGroupViewController() let presenter = CreateGroupPresenter() let interactor = CreateGroupInteractor() @@ -34,13 +34,11 @@ class CreateGroupWireFrame: CreateGroupWireFrameProtocol { } func changeGroupName(name: String) { - EditGroupNameWireFrame().presentEditGroupName(navigation: navigation!, currentName: name, delegate: external, mode: .create) - self.navigation?.view.layoutIfNeeded() + mainWireFrame?.showGroupName(name, delegate: external, mode: .create) } func changeAlias(alias: String) { - MyGroupAliasWireFrame().presentMyGroupAlias(navigation: navigation!, currentAlias: alias, delegate: external, mode: .create) - self.navigation?.view.layoutIfNeeded() + mainWireFrame?.showGroupAlias(alias, delegate: external, mode: .create) } func updateParticipants(contacts: [Contact]) { diff --git a/Nynja/Modules/Flows/CreateGroupFlow/MyGroupAlias/Presenter/MyGroupAliasPresenter.swift b/Nynja/Modules/Flows/CreateGroupFlow/MyGroupAlias/Presenter/MyGroupAliasPresenter.swift index 13799f69d1a21be090d600d34ed48c6e3c841263..2911c8a9c35756e28179d900be8b0de49ec94455 100644 --- a/Nynja/Modules/Flows/CreateGroupFlow/MyGroupAlias/Presenter/MyGroupAliasPresenter.swift +++ b/Nynja/Modules/Flows/CreateGroupFlow/MyGroupAlias/Presenter/MyGroupAliasPresenter.swift @@ -69,7 +69,7 @@ class MyGroupAliasPresenter: BasePresenter, GroupInputPresenterProtocol, Initial // MARK: - MyGroupAliasPresenterProtocol var validators: [MTIValidator] { - return validatorFactory.makeGroupInputValidators(maxLength: 64, emptyWarningMessage: String.localizable.aliasEmptyMessage) + return validatorFactory.makeGroupInputValidators(maxLength: 65, emptyWarningMessage: String.localizable.groupNameEmptyMessage) } func cancel() { diff --git a/Nynja/Modules/History/Presenter/HistoryPresenter.swift b/Nynja/Modules/History/Presenter/HistoryPresenter.swift index 9e56816a1c857a0a029a13b264d374f80c43995e..3d6cf8a7107e24e620dc5b4ba836258da82341f6 100644 --- a/Nynja/Modules/History/Presenter/HistoryPresenter.swift +++ b/Nynja/Modules/History/Presenter/HistoryPresenter.swift @@ -37,7 +37,7 @@ class HistoryPresenter: BasePresenter, HistoryPresenterProtocol, HistoryInteract } func showChat(contact: Contact) { - guard [.friend, .ban, .banned].contains(contact.originalStatus) else { + guard [.authorization,.friend, .ban, .banned].contains(contact.originalStatus) else { return } wireFrame.showChat(contact: contact) diff --git a/Nynja/Modules/History/WireFrame/HistoryWireframe.swift b/Nynja/Modules/History/WireFrame/HistoryWireframe.swift index e61768b69efc1061de6768e6c6f2a6640e6a26d2..3c02184447cec6baf6dafbdc71a1d14c6e8647a8 100644 --- a/Nynja/Modules/History/WireFrame/HistoryWireframe.swift +++ b/Nynja/Modules/History/WireFrame/HistoryWireframe.swift @@ -34,7 +34,7 @@ class HistoryWireFrame: HistoryWireFrameProtocol { } func showChat(contact: Contact) { - mainWF?.showChat(contact) + mainWF?.showAddContact(contact: contact) } func showInviteFriends() { diff --git a/Nynja/Modules/Main/Interactor/MainInteractor.swift b/Nynja/Modules/Main/Interactor/MainInteractor.swift index 244af25b0b4a4c74f89e9e7161a96ca7a9d55b70..6829492127ad6cf912179f89e1fbc6853394f3d5 100644 --- a/Nynja/Modules/Main/Interactor/MainInteractor.swift +++ b/Nynja/Modules/Main/Interactor/MainInteractor.swift @@ -81,10 +81,6 @@ final class MainInteractor: BaseInteractor, MainInteractorInputProtocol, EditPho // MARK: - MainInteractorInputProtocol - - func checkSession() { - mqttService.reconnect() - } func findContactBy(phoneId: String) -> Contact? { return ContactDAO.findContactBy(phoneId: phoneId) @@ -94,7 +90,6 @@ final class MainInteractor: BaseInteractor, MainInteractorInputProtocol, EditPho mqttService.logout() LogService.log(topic: .db) { return "Clear storage: logout" } cleanServices() - mqttService.reconnect() } func deleteAccount() { @@ -108,7 +103,6 @@ final class MainInteractor: BaseInteractor, MainInteractorInputProtocol, EditPho private func handleProfileDeleting() { cleanServices() alertManager.showAlertOk(message: String.localizable.authAttemptsRemoved) - mqttService.reconnect() presenter.hideUILocker() } diff --git a/Nynja/Modules/Main/MainProtocols.swift b/Nynja/Modules/Main/MainProtocols.swift index 48a9e0382f33ac5202f7c18610e72afd17441cab..4b247bc715a1bcb50baee06faaa5e66b5c2d235c 100644 --- a/Nynja/Modules/Main/MainProtocols.swift +++ b/Nynja/Modules/Main/MainProtocols.swift @@ -22,7 +22,7 @@ protocol MainWireFrameProtocol: class { /** * Add here your methods for communication PRESENTER -> WIREFRAME */ - func presentMain(navigation: UINavigationController, isRegistered: Bool, checkSession: Bool) + func presentMain(navigation: UINavigationController, isRegistered: Bool) func sendStatus(status: TypingModelType) func showQRReader() @@ -62,7 +62,7 @@ protocol MainWireFrameProtocol: class { func showBuildNumber() func showChangeNumber() func showChangeNumberStep2() - func showSecuritySettings() + func showActiveSessions() func showSupport() func showLanguageSettings() func showThemePicker() @@ -80,7 +80,6 @@ protocol MainWireFrameProtocol: class { func showImagePreview(with url: URL, target imageView: UIImageView) func openMapView() func showMySelfChat(contact: Contact) - func showFavorites() func showQRGenerator() func showSelectCountry(_ selectCountryDelegate: SelectCountryDelegate) func showAddContactByUserName() @@ -91,12 +90,16 @@ protocol MainWireFrameProtocol: class { func getStarredLocation() -> [LocationType] func getRecentsMedia() -> [Media] func openMarketplace() + + func showFavorites(mode: FavoritesMode) // Group func showAddParticipants() func showGroupsList() func showGroupsOptions() func showChatOptions() + func showGroupName(_ name: String, delegate: GroupNameEditorDelegate?, mode: GroupMode) + func showGroupAlias(_ alias: String, delegate: MyGroupAliasEditorDelegate?, mode: GroupMode) // Channel func showNewChannel() @@ -174,7 +177,7 @@ protocol MainPresenterProtocol: BasePresenterProtocol { func showWheelPositionPicker() func showBuildNumber() func showChangeNumber() - func showSecuritySettings() + func showActiveSessions() func showSupport() func showThemePicker() func showPrivacy() @@ -188,6 +191,8 @@ protocol MainPresenterProtocol: BasePresenterProtocol { func showEditUsername() func showAddContactByUserName() + func showFavorites(mode: FavoritesMode) + func conferenceVoiceCall() func conferenceVideoCall() @@ -231,7 +236,6 @@ protocol MainInteractorInputProtocol: BaseInteractorProtocol { /** * Add here your methods for communication PRESENTER -> INTERACTOR */ - func checkSession () func call(phoneId: String) func videoCall(phoneId: String) func logout() diff --git a/Nynja/Modules/Main/Presenter/MainPresenter.swift b/Nynja/Modules/Main/Presenter/MainPresenter.swift index f934d3da675704f4e95e6e98bccce8d898d09fbd..76ac6c20c4066f56fbc88a9ef84685d197008b59 100644 --- a/Nynja/Modules/Main/Presenter/MainPresenter.swift +++ b/Nynja/Modules/Main/Presenter/MainPresenter.swift @@ -51,7 +51,11 @@ final class MainPresenter: BasePresenter, MainPresenterProtocol, MainInteractorO } func showMarketplace() { - self.wireFrame.openMarketplace() + wireFrame.openMarketplace() + } + + func showFavorites(mode: FavoritesMode) { + wireFrame.showFavorites(mode: mode) } func voiceCall() { @@ -203,8 +207,8 @@ final class MainPresenter: BasePresenter, MainPresenterProtocol, MainInteractorO self.wireFrame.showThemePicker() } - func showSecuritySettings() { - self.wireFrame.showSecuritySettings() + func showActiveSessions() { + self.wireFrame.showActiveSessions() } func showSupport() { diff --git a/Nynja/Modules/Main/View/MainNavigationItem.swift b/Nynja/Modules/Main/View/MainNavigationItem.swift index 7fd4c306413810e6247d79d89c61eab97321b37b..cb92fed3ab5ae20281567f254d649bb825dd6164 100644 --- a/Nynja/Modules/Main/View/MainNavigationItem.swift +++ b/Nynja/Modules/Main/View/MainNavigationItem.swift @@ -47,6 +47,11 @@ enum MainNavigationItem: String { case payment = "wheel_item_transfer" case help = "wheel_item_help" + // Calls section + case callContact = "wheel_item_call_contact" + case dialNumber = "wheel_item_dial_number" + case callHistory = "wheel_item_call_history" + // Chats section case starred = "wheel_item_starred" case recents = "wheel_item_recents" @@ -93,10 +98,9 @@ enum MainNavigationItem: String { case language = "wheel_item_language" case theme = "wheel_theme" case dataAndStorage = "wheel_data_and_storage" - case security = "wheel_security" + case activeSessions = "wheel_active_sessions" case privacy = "wheel_privacy" case logOut = "wheel_item_logOut" - case about = "wheel_item_about" case deleteAccount = "wheel_item_deleteAccount" // Location subsection @@ -120,6 +124,8 @@ enum MainNavigationItem: String { anyClass = ContactsItemsFactory.self case .options: anyClass = OptionsItemsFactory.self + case .calls: + anyClass = CallsItemsFactory.self default: anyClass = nil } diff --git a/Nynja/Modules/Main/View/MainViewController+NavigateProtocol.swift b/Nynja/Modules/Main/View/MainViewController+NavigateProtocol.swift index 23e4a8d39e0b308a790ee78844f7d69ebc0a6c14..f41cbf57720f4447579b98f066c0e9ed49b8ed84 100644 --- a/Nynja/Modules/Main/View/MainViewController+NavigateProtocol.swift +++ b/Nynja/Modules/Main/View/MainViewController+NavigateProtocol.swift @@ -41,7 +41,7 @@ extension MainViewController: NavigateProtocol { } func showCalls(indexPath: IndexPath?) { - // TODO: will be implemented in future with 'Calls' module. + openNextLevel(indexPath: indexPath) } func showMarketplace(indexPath: IndexPath?) { @@ -101,11 +101,13 @@ extension MainViewController: NavigateProtocol { closeWheel(indexPath: indexPath) } - func showMessages(indexPath: IndexPath?) { + func showFavorites(indexPath: IndexPath?, mode: FavoritesMode) { + presenter.showFavorites(mode: mode) closeWheel(indexPath: indexPath) } func showGroupCall(indexPath: IndexPath?) { + // TODO: need to implement } func showVoiceGroupCall(indexPath: IndexPath?) { @@ -287,8 +289,8 @@ extension MainViewController: NavigateProtocol { closeWheel(indexPath: indexPath) } - func showSecuritySettings(indexPath: IndexPath?) { - presenter.showSecuritySettings() + func showActiveSessions(indexPath: IndexPath?) { + presenter.showActiveSessions() closeWheel(indexPath: indexPath) } @@ -334,4 +336,9 @@ extension MainViewController: NavigateProtocol { closeWheel(indexPath: indexPath) } + // MARK: - Calls + + func expandVoiceCall(indexPath: IndexPath?) { + expand(by: indexPath) + } } diff --git a/Nynja/Modules/Main/View/NavigateProtocol.swift b/Nynja/Modules/Main/View/NavigateProtocol.swift index 8b2368203c20631312073fb168baf9866d840231..47047467e0516b1fd20d71454f066fb36c63723e 100644 --- a/Nynja/Modules/Main/View/NavigateProtocol.swift +++ b/Nynja/Modules/Main/View/NavigateProtocol.swift @@ -33,7 +33,8 @@ protocol SecondLevelNavigateProtocol: class { func showCreateGroup(indexPath: IndexPath?) func showGroupOptions(indexPath: IndexPath?) func showChatOptions(indexPath: IndexPath?) - func showMessages(indexPath: IndexPath?) + + func showFavorites(indexPath: IndexPath?, mode: FavoritesMode) // MARK: - Chat Actions func showLocation(indexPath: IndexPath?) @@ -93,7 +94,7 @@ protocol SecondLevelNavigateProtocol: class { func showPrivacy(indexPath: IndexPath?) func logout(indexPath: IndexPath?) func showAbout(indexPath: IndexPath?) - func showSecuritySettings(indexPath: IndexPath?) + func showActiveSessions(indexPath: IndexPath?) func deleteAccount(indexPath: IndexPath?) func showChangeNumber(indexPath: IndexPath?) func dataAndStorage(indexPath: IndexPath?) @@ -104,6 +105,9 @@ protocol SecondLevelNavigateProtocol: class { func showRecentChannels(indexPath: IndexPath?) func showMyChannels(indexPath: IndexPath?) func showNewChannel(indexPath: IndexPath?) + + // MARK: - Calls + func expandVoiceCall(indexPath: IndexPath?) } protocol ThirdLevelNavigateProtocol: class { diff --git a/Nynja/Modules/Main/WireFrame/MainWireframe.swift b/Nynja/Modules/Main/WireFrame/MainWireframe.swift index 1091b979ea6413eb3a72014ab5217ffb7d83bc58..af3c5c06d01591527ec41d3238953243b3d58cdc 100644 --- a/Nynja/Modules/Main/WireFrame/MainWireframe.swift +++ b/Nynja/Modules/Main/WireFrame/MainWireframe.swift @@ -12,14 +12,14 @@ import SnapKit final class MainWireFrame: MainWireFrameProtocol, NynjaCommunicatorServiceDelegate { - weak var navigation : UINavigationController? + weak var navigation : UINavigationController! weak var contentNavigation: UINavigationController! weak var view: MainViewController? weak var messageinteractor: MessageInteractor? weak var external: EditParticipantsDelegate? = nil - func presentMain(navigation: UINavigationController, isRegistered: Bool, checkSession: Bool = false) { + func presentMain(navigation: UINavigationController, isRegistered: Bool) { let serviceFactory = ServiceFactory() let view = MainViewController() @@ -69,10 +69,6 @@ final class MainWireFrame: MainWireFrameProtocol, NynjaCommunicatorServiceDelega } view.addViewControllerAsChild(childViewController: contentNavigation) - - if checkSession { - interactor.checkSession() - } } private func startNavigate() { @@ -355,8 +351,8 @@ final class MainWireFrame: MainWireFrameProtocol, NynjaCommunicatorServiceDelega transitionInfo: transitionInfo) } - func showFavorites() { - FavoritesWireFrame().presentFavorites(navigation: contentNavigation, main: self) + func showFavorites(mode: FavoritesMode) { + FavoritesWireFrame().presentFavorites(navigation: contentNavigation, main: self, mode: mode) } func shareContact(contact: Contact) { @@ -442,9 +438,9 @@ final class MainWireFrame: MainWireFrameProtocol, NynjaCommunicatorServiceDelega ChangeNumberStep2WireFrame().presentChangeNumberStep2(navigation: nav) } - func showSecuritySettings() { + func showActiveSessions() { if let navigation = contentNavigation { - SecurityWireFrame().presentSecurity(navigation: navigation, mainWireFrame: self) + ActiveSessionsWireFrame().presentActiveSessions(navigation: navigation, mainWireFrame: self) } } @@ -570,6 +566,16 @@ final class MainWireFrame: MainWireFrameProtocol, NynjaCommunicatorServiceDelega func showChatOptions() { OtherUserWireFrame().present(navigation: contentNavigation, main: self) } + + func showGroupName(_ name: String, delegate: GroupNameEditorDelegate?, mode: GroupMode) { + EditGroupNameWireFrame().presentEditGroupName(navigation: navigation, currentName: name, delegate: delegate, mode: mode) + navigation.view.layoutIfNeeded() + } + + func showGroupAlias(_ alias: String, delegate: MyGroupAliasEditorDelegate?, mode: GroupMode) { + MyGroupAliasWireFrame().presentMyGroupAlias(navigation: navigation, currentAlias: alias, delegate: delegate, mode: mode) + navigation.view.layoutIfNeeded() + } // MARK: Chats p2p diff --git a/Nynja/Modules/Message/Interactor/MessageInteractor+StorageSubscriber.swift b/Nynja/Modules/Message/Interactor/MessageInteractor+StorageSubscriber.swift index 2d0a2fee00d02cb942c2854b93a6480ca0d6c65c..09e44ecca9f959f37dfef673ede2a5266e3db7aa 100644 --- a/Nynja/Modules/Message/Interactor/MessageInteractor+StorageSubscriber.swift +++ b/Nynja/Modules/Message/Interactor/MessageInteractor+StorageSubscriber.swift @@ -212,11 +212,11 @@ extension MessageInteractor { removeProgressIfNeeded(for: message) let config = createMessageConfiguration(message) presenter?.updateMessage(with: config) - } else { + } else if let serverId = message.id { if isMyselfChat { - presenter?.messageRead(localId) + presenter?.messageRead(localId, serverId: serverId) } else { - presenter?.messageSent(localId) + presenter?.messageSent(localId, serverId: serverId) } } } diff --git a/Nynja/Modules/Message/Interactor/MessageInteractor.swift b/Nynja/Modules/Message/Interactor/MessageInteractor.swift index 140aa53c72ff10f2c45130679c0c3184a464c016..ced1d8a03fcfd336e5cb27da292459f9e80e6606 100644 --- a/Nynja/Modules/Message/Interactor/MessageInteractor.swift +++ b/Nynja/Modules/Message/Interactor/MessageInteractor.swift @@ -849,7 +849,7 @@ final class MessageInteractor: BaseInteractor, MessageInteractorInputProtocol, H message.localStatus = .deleted message.seenby = messageForSave.seenby - try? storageService.perform(action: .save, with: messageForSave) + ChatService.removeLocal(message: messageForSave) if let feed = self.feed, let newLastMessage = MessageDAO.fetchLastMessage(feed: feed) { ChatService.updateLastMessage(newLastMessage, shouldChangeUnread: false) @@ -1013,18 +1013,38 @@ final class MessageInteractor: BaseInteractor, MessageInteractorInputProtocol, H private func notifyAboutRead(withOld oldReader: MessageServerId?, new newReader: MessageServerId?) { guard let newReader = newReader, oldReader != newReader, - let localId = configuration.messages + let message = message(reader: newReader), + let localId = message.msg_id, + let serverId = message.id else { + return + } + + presenter?.messageRead(localId, serverId: serverId) + } + + private func message(reader: MessageServerId) -> Message? { + func message(isEqual: Bool) -> Message? { + return configuration.messages .last(where: { (message) -> Bool in guard let id = message.id else { return false } - return id <= newReader - })? - .msg_id else { - return + + if isEqual { + return id == reader + } else { + return id <= reader + } + }) + } + + if let message = message(isEqual: true) { + return message + } else if let message = message(isEqual: false) { + return message + } else { + return nil } - - presenter?.messageRead(localId) } private func updateContact(_ contact: Contact) { @@ -1078,6 +1098,7 @@ extension MessageInteractor { let sendingLang = conversationLanguageSettingService.outgoingTranslateLanguage try? storageService.perform(action: .save, with: message) + ChatService.updateLastMessage(message) translate(message: message, language: sendingLang) { [weak self] result in guard let self = self else { return } @@ -1092,20 +1113,19 @@ extension MessageInteractor { break } - if let repliedMessage = self.repliedMessage { - self.messageSendingService.sendRepliedMessage(repliedMessage, message: message) - self.declineReply() - } else { - self.messageSendingService.sendMessage(message) - } + self.startSend(message: message) } } else { - if let repliedMessage = repliedMessage { - messageSendingService.sendRepliedMessage(repliedMessage, message: message) - declineReply() - } else { - messageSendingService.sendMessage(message) - } + startSend(message: message) + } + } + + private func startSend(message: Message) { + if let repliedMessage = repliedMessage { + messageSendingService.sendRepliedMessage(repliedMessage, message: message) + declineReply() + } else { + messageSendingService.sendMessage(message) } } diff --git a/Nynja/Modules/Message/Presenter/MessagePresenter.swift b/Nynja/Modules/Message/Presenter/MessagePresenter.swift index ab06e074e499e744319557df21316cb83290fb92..372619dfe7609741ea07d50521bde4eb2af75b60 100644 --- a/Nynja/Modules/Message/Presenter/MessagePresenter.swift +++ b/Nynja/Modules/Message/Presenter/MessagePresenter.swift @@ -774,7 +774,10 @@ class MessagePresenter: BasePresenter, MessagePresenterProtocol, MessageInteract model.isOwner = isOutgoingMessage(message) - model.replied = message.repliedby?.count ?? 0 + if FeatureFlags.isRepliesCounterEnabled.value { + model.replied = message.repliedby?.count ?? 0 + } + model.timeStamp = Date(timestamp: message.createdInt) let size = attach.size ?? 0 @@ -975,16 +978,16 @@ class MessagePresenter: BasePresenter, MessagePresenterProtocol, MessageInteract view.updateHeaderStatus(lastStatus) } - func messageSent(_ localId: String) { - view.updateDeliveryStatus(.sent, messageId: localId) + func messageSent(_ localId: MessageLocalId, serverId: MessageServerId) { + view.updateDeliveryStatus(.sent, localId: localId, serverId: serverId) } func update(sender: MessageSender, inMessagesWithIds messageIds: [String]) { view.update(sender: sender, inMessagesWithIds: messageIds) } - func messageRead(_ localId: String) { - view.updateDeliveryStatus(.read, messageId: localId) + func messageRead(_ localId: MessageLocalId, serverId: MessageServerId) { + view.updateDeliveryStatus(.read, localId: localId, serverId: serverId) } func starMessage(with localId: MessageLocalId, starId: MessageLocalId) { diff --git a/Nynja/Modules/Message/Protocols/MessageProtocols.swift b/Nynja/Modules/Message/Protocols/MessageProtocols.swift index 58b3050bd09a9c51dcb3e7201b5414978373161c..3147d52c16c84e2a731649c7f7647026f26e1bde 100644 --- a/Nynja/Modules/Message/Protocols/MessageProtocols.swift +++ b/Nynja/Modules/Message/Protocols/MessageProtocols.swift @@ -160,8 +160,8 @@ protocol MessageInteractorOutputProtocol: class, MentionFetchOutputProtocol, Mes func actionStatusChanged(_ status: ActionStatus) func restoreStatus() - func messageSent(_ localId: MessageLocalId) - func messageRead(_ localId: MessageLocalId) + func messageSent(_ localId: MessageLocalId, serverId: MessageServerId) + func messageRead(_ localId: MessageLocalId, serverId: MessageServerId) func update(sender: MessageSender, inMessagesWithIds messageIds: [String]) @@ -303,7 +303,7 @@ protocol MessageViewProtocol: class { func scrollToBottom() func updateHeaderStatus(_ status: String) - func updateDeliveryStatus(_ status: DeliveryStatus, messageId: String) + func updateDeliveryStatus(_ status: DeliveryStatus, localId: MessageLocalId, serverId: MessageServerId) func removeMessage(_ messageId: MessageLocalId, isForAllUsers: Bool) func update(sender: MessageSender, inMessagesWithIds messageIds: [String]) diff --git a/Nynja/Modules/Message/View/MessageVC.swift b/Nynja/Modules/Message/View/MessageVC.swift index f9c89e06c5260bff27702d973a2209d85a0620b2..a2ee470f1b7e43f905c7a50870a0ca33a1171f45 100644 --- a/Nynja/Modules/Message/View/MessageVC.swift +++ b/Nynja/Modules/Message/View/MessageVC.swift @@ -1050,13 +1050,12 @@ final class MessageVC: BaseVC, MessageViewProtocol, ReplyPreviewDelegate, BackSw } let userInfo = contextMenuUserInfo(for: model, ofType: type, convertionModel: convertingModel) - let itemsFactory: NynjaContextMenuItemsFactory - if let convertingModel = convertingModel { - itemsFactory = NynjaContextMenuItemsFactory.messageConvertedMenuConfig( - cellModel: model, convertionModel: convertingModel, userInfo: userInfo - ) - } else { - itemsFactory = NynjaContextMenuItemsFactory(type: type, model: model, userInfo: userInfo) + guard let itemsFactory = tryMakeContextMenuItemsFactory( + convertingModel: convertingModel, + model: model, + type: type, + userInfo: userInfo) else { + return } let maskFrame = inputBar.superview!.convert(inputBar.frame, to: inputBar.window!) @@ -1077,6 +1076,25 @@ final class MessageVC: BaseVC, MessageViewProtocol, ReplyPreviewDelegate, BackSw contextMenuPresented = true } + + private func tryMakeContextMenuItemsFactory( + convertingModel: ConvertionMessageModel?, + model: BaseChatCellModel, + type: SendMessageType, + userInfo: NynjaContextMenuUserInfo) -> NynjaContextMenuItemsFactory? { + + if let convertingModel = convertingModel { + return NynjaContextMenuItemsFactory.messageConvertedMenuConfig( + cellModel: model, + convertionModel: convertingModel, + userInfo: userInfo) + } else { + return NynjaContextMenuItemsFactory( + type: type, + model: model, + userInfo: userInfo) + } + } private func contextMenuUserInfo(for model: BaseChatCellModel, ofType type: SendMessageType, convertionModel: ConvertionMessageModel? = nil) -> NynjaContextMenuUserInfo { let userInfo = NynjaContextMenuUserInfo() @@ -1125,11 +1143,14 @@ final class MessageVC: BaseVC, MessageViewProtocol, ReplyPreviewDelegate, BackSw avatarView.isUserInteractionEnabled = !isBlock } - func updateDeliveryStatus(_ status: DeliveryStatus, messageId: String) { - guard let index = messageDS.index(where: { $0.id == messageId }) else { + func updateDeliveryStatus(_ status: DeliveryStatus, localId: MessageLocalId, serverId: MessageServerId) { + guard let index = messageDS.index(where: { $0.id == localId }) else { return } + let model = messageDS.cellModel(at: index) + model.serverID = serverId + if status != .read, model.deliveryStatus != .read { model.deliveryStatus = status } else { @@ -1362,19 +1383,23 @@ final class MessageVC: BaseVC, MessageViewProtocol, ReplyPreviewDelegate, BackSw private func markMesssagesAsRead(from presentationIndex: Int) { for i in (presentationIndex.. CornerRadius { - return ([.topLeft, .bottomLeft, .topRight], radius) + return (corners, radius) } //MARK: Utils diff --git a/Nynja/Modules/Message/View/Views/CollectionView/Cells/ChatCells/BaseChatCell/OponentChatCell.swift b/Nynja/Modules/Message/View/Views/CollectionView/Cells/ChatCells/BaseChatCell/OponentChatCell.swift index 255242771010ab4b73ef77bf0dc2060edec8bfb5..10216a4992184171d2ec175df0793623856404de 100644 --- a/Nynja/Modules/Message/View/Views/CollectionView/Cells/ChatCells/BaseChatCell/OponentChatCell.swift +++ b/Nynja/Modules/Message/View/Views/CollectionView/Cells/ChatCells/BaseChatCell/OponentChatCell.swift @@ -26,6 +26,11 @@ class OponentChatCell: BaseChatCell { private static let topInset = OpponentConstraints.messageView.topInset + override var corners: UIRectCorner { + return [.topRight, .bottomRight, .bottomLeft] + } + + // MARK: - Layout enum OpponentConstraints { @@ -63,14 +68,12 @@ class OponentChatCell: BaseChatCell { } } - private(set) var messageViewTopToBubbleConstraint: Constraint? private(set) var messageViewTopToAliasMinimizedConstraint: Constraint? override func makeMessageView() -> UIView { let view = super.makeMessageView() view.snp.makeConstraints { maker in - messageViewTopToBubbleConstraint = maker.top.equalTo(bubble.snp.top).constraint messageViewTopToAliasMinimizedConstraint = maker.top.equalTo(fromLabel.snp.bottom).offset(-OponentChatCell.topInset).constraint } @@ -83,20 +86,12 @@ class OponentChatCell: BaseChatCell { override func setupMessageContent(_ model: BaseChatCellModel) { super.setupMessageContent(model) - if !OponentChatCell.shouldDisplayAlias(for: model) { - fromLabel.isHidden = true - messageViewTopToAliasConstraint?.deactivate() - messageViewTopToAliasMinimizedConstraint?.deactivate() - messageViewTopToBubbleConstraint?.activate() - - } else if OponentChatCell.shouldMinimizeTopOffset(for: model) { + if OponentChatCell.shouldMinimizeTopOffset(for: model) { messageViewTopToAliasConstraint?.deactivate() messageViewTopToAliasMinimizedConstraint?.activate() - messageViewTopToBubbleConstraint?.deactivate() } else { messageViewTopToAliasConstraint?.activate() messageViewTopToAliasMinimizedConstraint?.deactivate() - messageViewTopToBubbleConstraint?.deactivate() } guard let content = messageContent else { return } @@ -113,7 +108,7 @@ class OponentChatCell: BaseChatCell { override func updateData(_ model: BaseChatCellModel) { super.updateData(model) - if !OponentChatCell.shouldDisplayAlias(for: model), OponentChatCell.shouldShowSender(model) { + if model.type == .sticker, OponentChatCell.shouldShowSender(model) { bubbleLeftToSuperviewConstraint?.deactivate() bubbleLeftToAvatarConstraint?.activate() } else { @@ -122,10 +117,6 @@ class OponentChatCell: BaseChatCell { } } - private static func shouldDisplayAlias(for model: BaseChatCellModel) -> Bool { - return model.type != .sticker - } - private static func shouldMinimizeTopOffset(for model: BaseChatCellModel) -> Bool { guard shouldShowSender(model) else { return false } @@ -149,28 +140,11 @@ class OponentChatCell: BaseChatCell { override class func size(for model: BaseChatCellModel) -> CGSize { var size = super.size(for: model) - if !shouldDisplayAlias(for: model) && shouldShowSender(model) { - size.height -= OponentChatCell.Constraints.fromImageView.height.adjustedByWidth - - } else if shouldMinimizeTopOffset(for: model) { + if shouldMinimizeTopOffset(for: model) { size.height -= OponentChatCell.topInset } return size } - - // MARK: Layout - override func layoutSubviews() { - super.layoutSubviews() - let corners: UIRectCorner = [.topRight, .bottomRight, .bottomLeft] - bubble.roundCorners(corners, radius: radius) - messageView.roundCorners(corners, radius: radius) - } - - // MARK: - MessageContentAppearance - override func corners(_ messageContent: MessageContentProtocol) -> CornerRadius { - return ([.bottomRight, .bottomLeft, .topRight], radius) - } - } diff --git a/Nynja/Modules/Message/View/Views/CollectionView/Cells/Views/Base/MessageContentView.swift b/Nynja/Modules/Message/View/Views/CollectionView/Cells/Views/Base/MessageContentView.swift index 60ec6e6c11ea51cc7c6e31915cef6394dd109da6..cd73fb3f8747f24413221fc7dd4db1174dd4eddb 100644 --- a/Nynja/Modules/Message/View/Views/CollectionView/Cells/Views/Base/MessageContentView.swift +++ b/Nynja/Modules/Message/View/Views/CollectionView/Cells/Views/Base/MessageContentView.swift @@ -36,6 +36,16 @@ class MessageContentView: BaseView, BubbleInjectible { self.contentAppearance = contentAppearance } + override func layoutSubviews() { + super.layoutSubviews() + + guard let (corners, radius) = contentAppearance?.corners(self) else { + return + } + + roundCorners(corners, radius: radius) + } + // MARK: - BubbleInjectible diff --git a/Nynja/Modules/Message/WireFrame/MessageWireframe.swift b/Nynja/Modules/Message/WireFrame/MessageWireframe.swift index 71987cd8cb5f6cfbdcb08beb1386e8ef126d680d..7e71ff8c609ee347fb710c3b92bdfba232a9f38c 100644 --- a/Nynja/Modules/Message/WireFrame/MessageWireframe.swift +++ b/Nynja/Modules/Message/WireFrame/MessageWireframe.swift @@ -62,7 +62,7 @@ class MessageWireFrame: MessageWireframeProtocol, DocumentInteractionWireFrame { } func openReplies(redirectAction: ((String)->Void)?) { - RepliesWireFrame().present(navigation: navigation!, main: main, redirectAction: redirectAction) + RepliesWireFrame().presentReplies(navigation: navigation!, main: main, redirectAction: redirectAction) } func showProfileScreen(contact: Contact) { diff --git a/Nynja/Modules/Profile/View/ProfileViewController.swift b/Nynja/Modules/Profile/View/ProfileViewController.swift index d5459dd4df20c979d9483f6a6e43574a0842cbdf..33c4711463679b7324ade5cce5ed2f8846eaabd2 100644 --- a/Nynja/Modules/Profile/View/ProfileViewController.swift +++ b/Nynja/Modules/Profile/View/ProfileViewController.swift @@ -208,6 +208,10 @@ extension ProfileViewController: ProfileViewSectionDelegate { func contactTapped(_ contact: Contact) { presenter.showChat(with: contact) } + + func historyAvatarTapped(_ contact: Contact) { + presenter.showProfile(contact) + } func scheduledMessageTapped(_ jobId: Int64) { presenter.showScheduledMessage(with: jobId) diff --git a/Nynja/Modules/Profile/View/TableView/ProfileTableViewDelegate.swift b/Nynja/Modules/Profile/View/TableView/ProfileTableViewDelegate.swift index 9f9bb38ca28c9a3ccef0219e5c84bf4eb993b086..3feabc3d57afd1f82e7719200ab3ff68fa189cac 100644 --- a/Nynja/Modules/Profile/View/TableView/ProfileTableViewDelegate.swift +++ b/Nynja/Modules/Profile/View/TableView/ProfileTableViewDelegate.swift @@ -37,7 +37,7 @@ class ProfileTableViewDelegate: NSObject, UITableViewDelegate { if sectionType == .unreadMessages { sectionDelegate?.messageTapped(contact) } else if sectionType == .contactRequests { - sectionDelegate?.contactTapped(contact) + sectionDelegate?.historyAvatarTapped(contact) } } else if let scheduledMessage = model as? ScheduledMessage, sectionModel.profileSection == .scheduledMessages, let id = scheduledMessage.job?.id { sectionDelegate?.scheduledMessageTapped(id) diff --git a/Nynja/Modules/Profile/View/TableView/ProfileViewSectionDelegate.swift b/Nynja/Modules/Profile/View/TableView/ProfileViewSectionDelegate.swift index 686c4097ef1906aab0c42d26b9e6934591de1547..95e8d34688184b99e9894bd41c514610f03bd65b 100644 --- a/Nynja/Modules/Profile/View/TableView/ProfileViewSectionDelegate.swift +++ b/Nynja/Modules/Profile/View/TableView/ProfileViewSectionDelegate.swift @@ -12,6 +12,7 @@ protocol ProfileViewSectionDelegate: class { func groupMessageTapped(_ room: Room) func contactTapped(_ contact: Contact) func scheduledMessageTapped(_ jobId: Int64) + func historyAvatarTapped(_ contact: Contact) func showMoreTapped(for profileSection: ProfileSection) func actionTapped(_ action: ProfileAction) diff --git a/Nynja/Modules/Profile/WireFrame/ProfileWireframe.swift b/Nynja/Modules/Profile/WireFrame/ProfileWireframe.swift index 3e001cd9d92c3d22955b5d6180d71f77b2ddf96a..81858cee209174f15527ec12bf1f44995d630d99 100644 --- a/Nynja/Modules/Profile/WireFrame/ProfileWireframe.swift +++ b/Nynja/Modules/Profile/WireFrame/ProfileWireframe.swift @@ -93,6 +93,6 @@ class ProfileWireFrame: ProfileWireFrameProtocol { } func showFavorites() { - main?.showFavorites() + main?.showFavorites(mode: .home) } } diff --git a/Nynja/Modules/Replies/RepliesProtocols.swift b/Nynja/Modules/Replies/RepliesProtocols.swift index 8c4f3cfa1dc4acbb68144498e556c904bc0b61d0..183283204033137ec412bbd7ec4b877cbfc7f8e1 100644 --- a/Nynja/Modules/Replies/RepliesProtocols.swift +++ b/Nynja/Modules/Replies/RepliesProtocols.swift @@ -13,7 +13,7 @@ import CoreLocation protocol RepliesWireframeProtocol: class { var main: MainWireFrame? { get set } - func present(navigation: UINavigationController, main: MainWireFrame?, redirectAction: ((String)->Void)?) + func presentReplies(navigation: UINavigationController, main: MainWireFrame?, redirectAction: ((String)->Void)?) func hide(completion: (()->())?) } diff --git a/Nynja/Modules/Replies/WireFrame/RepliesWireFrame.swift b/Nynja/Modules/Replies/WireFrame/RepliesWireFrame.swift index b12b43e0cea12248b7a03918fcabf9589d684558..a608402521463230a6a3199ad80564220dab0f57 100644 --- a/Nynja/Modules/Replies/WireFrame/RepliesWireFrame.swift +++ b/Nynja/Modules/Replies/WireFrame/RepliesWireFrame.swift @@ -13,7 +13,7 @@ class RepliesWireFrame: RepliesWireframeProtocol { weak var navigation : UINavigationController? weak var main: MainWireFrame? - func present(navigation: UINavigationController, main: MainWireFrame?, redirectAction: ((String)->Void)?) { + func presentReplies(navigation: UINavigationController, main: MainWireFrame?, redirectAction: ((String)->Void)?) { guard let messageId = UserDefaults.standard.string(forKey: String(SharedParameters.messageId.rawValue)) else { return } diff --git a/Nynja/Modules/Settings/Security/SecurityProtocols.swift b/Nynja/Modules/Settings/ActiveSessions/ActiveSessionsProtocols.swift similarity index 61% rename from Nynja/Modules/Settings/Security/SecurityProtocols.swift rename to Nynja/Modules/Settings/ActiveSessions/ActiveSessionsProtocols.swift index d26d6ed52240b672ab7ad48e5cfdabc214be9a5e..aa89ef0a8b87e6227a2a8b45b1b4d3d763617d4b 100644 --- a/Nynja/Modules/Settings/Security/SecurityProtocols.swift +++ b/Nynja/Modules/Settings/ActiveSessions/ActiveSessionsProtocols.swift @@ -1,5 +1,5 @@ // -// SecuritySecurityProtocols.swift +// ActiveSessionsProtocols.swift // Nynja // // Created by Michael Katkov on 16/03/2018. @@ -8,9 +8,9 @@ import UIKit -protocol SecurityWireFrameProtocol: class { +protocol ActiveSessionsWireFrameProtocol: class { - func presentSecurity(navigation: UINavigationController, mainWireFrame: MainWireFrameProtocol) + func presentActiveSessions(navigation: UINavigationController, mainWireFrame: MainWireFrameProtocol) /** * Add here your methods for communication PRESENTER -> WIREFRAME @@ -19,9 +19,9 @@ protocol SecurityWireFrameProtocol: class { func hideNoInternetView() } -protocol SecurityViewProtocol: class { +protocol ActiveSessionsViewProtocol: class { - var presenter: SecurityPresenterProtocol! { get set } + var presenter: ActiveSessionsPresenterProtocol! { get set } /** * Add here your methods for communication PRESENTER -> VIEW @@ -29,11 +29,11 @@ protocol SecurityViewProtocol: class { func updateUI() } -protocol SecurityPresenterProtocol: BasePresenterProtocol { +protocol ActiveSessionsPresenterProtocol: BasePresenterProtocol { - var view: SecurityViewProtocol! { get set } - var interactor: SecurityInteractorInputProtocol! { get set } - var wireFrame: SecurityWireFrameProtocol! { get set } + var view: ActiveSessionsViewProtocol! { get set } + var interactor: ActiveSessionsInteractorInputProtocol! { get set } + var wireFrame: ActiveSessionsWireFrameProtocol! { get set } /** * Add here your methods for communication VIEW -> PRESENTER @@ -47,7 +47,7 @@ protocol SecurityPresenterProtocol: BasePresenterProtocol { func wasHidden() } -protocol SecurityInteractorOutputProtocol: class { +protocol ActiveSessionsInteractorOutputProtocol: class { /** * Add here your methods for communication INTERACTOR -> PRESENTER @@ -57,9 +57,9 @@ protocol SecurityInteractorOutputProtocol: class { } -protocol SecurityInteractorInputProtocol: class { +protocol ActiveSessionsInteractorInputProtocol: class { - var presenter: SecurityInteractorOutputProtocol! { get set } + var presenter: ActiveSessionsInteractorOutputProtocol! { get set } /** * Add here your methods for communication PRESENTER -> INTERACTOR diff --git a/Nynja/Modules/Settings/Security/Interactor/SecurityInteractor.swift b/Nynja/Modules/Settings/ActiveSessions/Interactor/ActiveSessionsInteractor.swift similarity index 93% rename from Nynja/Modules/Settings/Security/Interactor/SecurityInteractor.swift rename to Nynja/Modules/Settings/ActiveSessions/Interactor/ActiveSessionsInteractor.swift index a1b34aa39d156bc36fd69e466c5fff409f7c04d1..ad11b2d1b0c50592d028708374500c39192830e0 100644 --- a/Nynja/Modules/Settings/Security/Interactor/SecurityInteractor.swift +++ b/Nynja/Modules/Settings/ActiveSessions/Interactor/ActiveSessionsInteractor.swift @@ -1,14 +1,14 @@ // -// SecuritySecurityInteractor.swift +// ActiveSessionsInteractor.swift // Nynja // // Created by Michael Katkov on 16/03/2018. // Copyright © 2018 Michael Katkov. All rights reserved. // -class SecurityInteractor: SecurityInteractorInputProtocol, AuthHandlerDelegate, IoHandlerDelegate, ConnectionServiceDelegate { +final class ActiveSessionsInteractor: ActiveSessionsInteractorInputProtocol, AuthHandlerDelegate, IoHandlerDelegate, ConnectionServiceDelegate { - weak var presenter: SecurityInteractorOutputProtocol! + weak var presenter: ActiveSessionsInteractorOutputProtocol! private var items : [Auth] = [Auth]() private var current : Auth? diff --git a/Nynja/Modules/Settings/Security/Presenter/SecurityPresenter.swift b/Nynja/Modules/Settings/ActiveSessions/Presenter/ActiveSessionsPresenter.swift similarity index 77% rename from Nynja/Modules/Settings/Security/Presenter/SecurityPresenter.swift rename to Nynja/Modules/Settings/ActiveSessions/Presenter/ActiveSessionsPresenter.swift index a918dec5b986b98376ca5113477cb42421c86810..69784a8bb1c60146033b0af6059016a1e519a896 100644 --- a/Nynja/Modules/Settings/Security/Presenter/SecurityPresenter.swift +++ b/Nynja/Modules/Settings/ActiveSessions/Presenter/ActiveSessionsPresenter.swift @@ -1,20 +1,20 @@ // -// SecuritySecurityPresenter.swift +// ActiveSessionsPresenter.swift // Nynja // // Created by Michael Katkov on 16/03/2018. // Copyright © 2018 Michael Katkov. All rights reserved. // -class SecurityPresenter: BasePresenter, SecurityPresenterProtocol, SecurityInteractorOutputProtocol { +final class ActiveSessionsPresenter: BasePresenter, ActiveSessionsPresenterProtocol, ActiveSessionsInteractorOutputProtocol { override var itemsFactory: WCItemsFactory? { - return SecurityItemsFactory() + return ActiveSessionsItemsFactory() } - weak var view: SecurityViewProtocol! - var interactor: SecurityInteractorInputProtocol! - var wireFrame: SecurityWireFrameProtocol! + weak var view: ActiveSessionsViewProtocol! + var interactor: ActiveSessionsInteractorInputProtocol! + var wireFrame: ActiveSessionsWireFrameProtocol! //MARK: - SecurityPresenterProtocol func getAllSessions() { @@ -63,8 +63,8 @@ class SecurityPresenter: BasePresenter, SecurityPresenterProtocol, SecurityInter //MARK: - Private func askAndDeleteAllSessions() { - AlertManager.sharedInstance.showAlertWithTwoActions(title: "", message: String.localizable.securityYouSure, - firstActionTitle: String.localizable.securityNo, secondActionTitle: String.localizable.securityYes, + AlertManager.sharedInstance.showAlertWithTwoActions(title: "", message: String.localizable.activeSessionsYouSure, + firstActionTitle: String.localizable.activeSessionsNo, secondActionTitle: String.localizable.activeSessionsYes, firstAction: { () in }, secondAction: { () in self.interactor.deleteAllSessions() @@ -72,8 +72,8 @@ class SecurityPresenter: BasePresenter, SecurityPresenterProtocol, SecurityInter } func askAndDeleteSession(clientId: String) { - AlertManager.sharedInstance.showAlertWithTwoActions(title: "", message: String.localizable.securityTerminate, - firstActionTitle: String.localizable.securityNo, secondActionTitle: String.localizable.securityYes, + AlertManager.sharedInstance.showAlertWithTwoActions(title: "", message: String.localizable.activeSessionsTerminate, + firstActionTitle: String.localizable.activeSessionsNo, secondActionTitle: String.localizable.activeSessionsYes, firstAction: { () in }, secondAction: { () in self.interactor.deleteSession(clientId: clientId) @@ -82,7 +82,7 @@ class SecurityPresenter: BasePresenter, SecurityPresenterProtocol, SecurityInter //MARK: - Private private func showNoInternetAlert() { - AlertManager.sharedInstance.showAlertOk(message: String.localizable.securityNoInternetConnection) + AlertManager.sharedInstance.showAlertOk(message: String.localizable.activeSessionsNoInternetConnection) } private func makeRequireInternetAction(action: () -> ()) { diff --git a/Nynja/Modules/Settings/Security/View/SecurityViewController.swift b/Nynja/Modules/Settings/ActiveSessions/View/ActiveSessionsViewController.swift similarity index 91% rename from Nynja/Modules/Settings/Security/View/SecurityViewController.swift rename to Nynja/Modules/Settings/ActiveSessions/View/ActiveSessionsViewController.swift index dbae2a513dd3e4d7fda5ea12edb4ff91fd1ac5d3..911dadf640f7db67fc435528b973f4ed4cafc04e 100644 --- a/Nynja/Modules/Settings/Security/View/SecurityViewController.swift +++ b/Nynja/Modules/Settings/ActiveSessions/View/ActiveSessionsViewController.swift @@ -1,5 +1,5 @@ // -// SecuritySecurityViewController.swift +// ActiveSessionsViewController.swift // Nynja // // Created by Michael Katkov on 16/03/2018. @@ -8,9 +8,9 @@ import UIKit -class SecurityViewController: BaseVC, SecurityViewProtocol { +final class ActiveSessionsViewController: BaseVC, ActiveSessionsViewProtocol { - var presenter: SecurityPresenterProtocol! { + var presenter: ActiveSessionsPresenterProtocol! { didSet { _presenter = presenter } @@ -49,7 +49,7 @@ class SecurityViewController: BaseVC, SecurityViewProtocol { override func viewDidLoad() { super.viewDidLoad() presenter.wasShown() - self.screenTitle = String.localizable.securityTitle + self.screenTitle = String.localizable.activeSessionsTitle.uppercased() shouldShowSeparator = true } @@ -96,8 +96,10 @@ class SecurityViewController: BaseVC, SecurityViewProtocol { } } + // MARK: - Table View -extension SecurityViewController: UITableViewDataSource, UITableViewDelegate { + +extension ActiveSessionsViewController: UITableViewDataSource, UITableViewDelegate { func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { return presenter.getItems().count diff --git a/Nynja/Modules/Settings/Security/View/Cell/SessionItemCell.swift b/Nynja/Modules/Settings/ActiveSessions/View/Cell/SessionItemCell.swift similarity index 100% rename from Nynja/Modules/Settings/Security/View/Cell/SessionItemCell.swift rename to Nynja/Modules/Settings/ActiveSessions/View/Cell/SessionItemCell.swift diff --git a/Nynja/Modules/Settings/Security/View/View/SessionDescView.swift b/Nynja/Modules/Settings/ActiveSessions/View/View/SessionDescView.swift similarity index 100% rename from Nynja/Modules/Settings/Security/View/View/SessionDescView.swift rename to Nynja/Modules/Settings/ActiveSessions/View/View/SessionDescView.swift diff --git a/Nynja/Modules/Settings/Security/View/View/SessionFooterView.swift b/Nynja/Modules/Settings/ActiveSessions/View/View/SessionFooterView.swift similarity index 90% rename from Nynja/Modules/Settings/Security/View/View/SessionFooterView.swift rename to Nynja/Modules/Settings/ActiveSessions/View/View/SessionFooterView.swift index 9711c67fc41fcc1a7bb7d2303dbfaf1c77d70b73..d0a163e58ab6631e022dd64805991002430b168b 100644 --- a/Nynja/Modules/Settings/Security/View/View/SessionFooterView.swift +++ b/Nynja/Modules/Settings/ActiveSessions/View/View/SessionFooterView.swift @@ -27,6 +27,6 @@ class SessionFooterView : UIView { } func setUp() { - descView.descLabel.text = String.localizable.securityTapOnASession + descView.descLabel.text = String.localizable.activeSessionsTapOnASession } } diff --git a/Nynja/Modules/Settings/Security/View/View/SessionHeaderView.swift b/Nynja/Modules/Settings/ActiveSessions/View/View/SessionHeaderView.swift similarity index 91% rename from Nynja/Modules/Settings/Security/View/View/SessionHeaderView.swift rename to Nynja/Modules/Settings/ActiveSessions/View/View/SessionHeaderView.swift index f2c2582a077b800226752af4941b313274cfc594..b51280a7dff1e2f86008100226551711323ddb9d 100644 --- a/Nynja/Modules/Settings/Security/View/View/SessionHeaderView.swift +++ b/Nynja/Modules/Settings/ActiveSessions/View/View/SessionHeaderView.swift @@ -96,12 +96,12 @@ class SessionHeaderView : UIView { func setUp(auth: Auth, isCurrent: Bool) { topTitleView.backgroundColor = UIColor.nynja.black.withAlphaComponent(0.1) - topTitleView.titleLabel.text = String.localizable.securityCurrentSession + topTitleView.titleLabel.text = String.localizable.activeSessionsCurrentSession activeSessionView.setItem(item: auth, isCurrent: isCurrent) - terminateButton.text = String.localizable.securityTerminateAllOtherSessions + terminateButton.text = String.localizable.activeSessionsTerminateAllOtherSessions separatorView.backgroundColor = UIColor.nynja.backgroundGray - descView.descLabel.text = String.localizable.securityLogsOutAllDevices + descView.descLabel.text = String.localizable.activeSessionsLogsOutAllDevices bottomTitleView.backgroundColor = UIColor.nynja.black.withAlphaComponent(0.1) - bottomTitleView.titleLabel.text = String.localizable.securityActiveSessions + bottomTitleView.titleLabel.text = String.localizable.activeSessionsTitle } } diff --git a/Nynja/Modules/Settings/Security/View/View/SessionItemView.swift b/Nynja/Modules/Settings/ActiveSessions/View/View/SessionItemView.swift similarity index 95% rename from Nynja/Modules/Settings/Security/View/View/SessionItemView.swift rename to Nynja/Modules/Settings/ActiveSessions/View/View/SessionItemView.swift index 754869203bd41a1fbdaf12aecbea509c707cf893..dc93d3b0bd074cd439f42dcb828266d62c01f9ed 100644 --- a/Nynja/Modules/Settings/Security/View/View/SessionItemView.swift +++ b/Nynja/Modules/Settings/ActiveSessions/View/View/SessionItemView.swift @@ -77,14 +77,14 @@ class SessionItemView : UIView { setSubTitle(item: item) setDesc(item: item) if isCurrent { - dateLabel.text = String.localizable.securityActive + dateLabel.text = String.localizable.activeSessionsActive } else if let online = item.last_online { setDate(online) } } func setTitle(item: Auth) { - var title = String.localizable.securityNynja + var title = String.localizable.activeSessionsNynja if let osVersion = item.osValue, let os = osVersion.split(separator: " ").first { title = title + " " + os } @@ -102,7 +102,7 @@ class SessionItemView : UIView { if let osVersion = item.osValue { subTitle = subTitle + ", " + osVersion } - subTitleLabel.text = subTitle.isEmpty ? String.localizable.securityNoData : subTitle + subTitleLabel.text = subTitle.isEmpty ? String.localizable.activeSessionsNoData : subTitle } func setDesc(item: Auth) { @@ -116,7 +116,7 @@ class SessionItemView : UIView { if let country = item.country { desc = desc + ", " + country } - descLabel.text = desc.isEmpty ? String.localizable.securityNoData : desc + descLabel.text = desc.isEmpty ? String.localizable.activeSessionsNoData : desc } func setDate(_ lastOnline: Int64) { diff --git a/Nynja/Modules/Settings/Security/View/View/SessionLineView.swift b/Nynja/Modules/Settings/ActiveSessions/View/View/SessionLineView.swift similarity index 100% rename from Nynja/Modules/Settings/Security/View/View/SessionLineView.swift rename to Nynja/Modules/Settings/ActiveSessions/View/View/SessionLineView.swift diff --git a/Nynja/Modules/Settings/Security/WireFrame/SecurityWireframe.swift b/Nynja/Modules/Settings/ActiveSessions/WireFrame/ActiveSessionsWireframe.swift similarity index 69% rename from Nynja/Modules/Settings/Security/WireFrame/SecurityWireframe.swift rename to Nynja/Modules/Settings/ActiveSessions/WireFrame/ActiveSessionsWireframe.swift index 4d313e80ce9814589754be2232e4b0bc607f750a..2fc07c281cc104ae719f6a0becca98f76cd07f23 100644 --- a/Nynja/Modules/Settings/Security/WireFrame/SecurityWireframe.swift +++ b/Nynja/Modules/Settings/ActiveSessions/WireFrame/ActiveSessionsWireframe.swift @@ -1,5 +1,5 @@ // -// SecuritySecurityWireframe.swift +// ActiveSessionsWireframe.swift // Nynja // // Created by Michael Katkov on 16/03/2018. @@ -8,15 +8,15 @@ import UIKit -class SecurityWireFrame: SecurityWireFrameProtocol { +final class ActiveSessionsWireFrame: ActiveSessionsWireFrameProtocol { weak var navigation: UINavigationController? weak var mainWireFrame: MainWireFrameProtocol? - func presentSecurity(navigation: UINavigationController, mainWireFrame: MainWireFrameProtocol) { - let view = SecurityViewController() - let presenter = SecurityPresenter() - let interactor = SecurityInteractor() + func presentActiveSessions(navigation: UINavigationController, mainWireFrame: MainWireFrameProtocol) { + let view = ActiveSessionsViewController() + let presenter = ActiveSessionsPresenter() + let interactor = ActiveSessionsInteractor() self.navigation = navigation self.mainWireFrame = mainWireFrame diff --git a/Nynja/Modules/Settings/LanguageSettings/WireFrame/LanguageSettingsWireframe.swift b/Nynja/Modules/Settings/LanguageSettings/WireFrame/LanguageSettingsWireframe.swift index 101eb724f44a77ffc45ce512542f7d0d225285aa..b8ca23ba4549387823b5b10ca6074bebb8697f4c 100644 --- a/Nynja/Modules/Settings/LanguageSettings/WireFrame/LanguageSettingsWireframe.swift +++ b/Nynja/Modules/Settings/LanguageSettings/WireFrame/LanguageSettingsWireframe.swift @@ -33,7 +33,7 @@ class LanguageSettingsWireFrame: LanguageSettingsWireFrameProtocol { func restart() { let nav = UINavigationController() nav.isNavigationBarHidden = true - MainWireFrame().presentMain(navigation: nav, isRegistered: false, checkSession: true) + MainWireFrame().presentMain(navigation: nav, isRegistered: false) UIApplication.shared.windows[0].rootViewController = nav } } diff --git a/Nynja/Modules/SettingsGroup/WireFrame/SettingsGroupWireFrame.swift b/Nynja/Modules/SettingsGroup/WireFrame/SettingsGroupWireFrame.swift index 3ca3b8c215faf30af6ba12322b87a151f72ffa5a..df0b060bea5b88f8ea4693ac12ee809a5cd29784 100644 --- a/Nynja/Modules/SettingsGroup/WireFrame/SettingsGroupWireFrame.swift +++ b/Nynja/Modules/SettingsGroup/WireFrame/SettingsGroupWireFrame.swift @@ -69,12 +69,11 @@ class SettingsGroupWireFrame: SettingsGroupWireframeProtocol { } func changeGroupName(name: String) { - EditGroupNameWireFrame().presentEditGroupName(navigation: navigation!, currentName: name, delegate: external, mode: .update) - self.navigation?.view.layoutIfNeeded() + main?.showGroupName(name, delegate: external, mode: .update) } func changeAlias(alias: String) { - MyGroupAliasWireFrame().presentMyGroupAlias(navigation: navigation!, currentAlias: alias, delegate: external, mode: .update) + main?.showGroupAlias(alias, delegate: external, mode: .update) } func showRules(room: Room?) { diff --git a/Nynja/Modules/Splash/Interactor/SplashInteractor.swift b/Nynja/Modules/Splash/Interactor/SplashInteractor.swift index f683f5febe573d05aaf2002f5109fa30a1ca6b5f..7a740f09462182b60531de1e36cd5febd81072ef 100644 --- a/Nynja/Modules/Splash/Interactor/SplashInteractor.swift +++ b/Nynja/Modules/Splash/Interactor/SplashInteractor.swift @@ -85,11 +85,7 @@ class SplashInteractor: SplashInteractorInputProtocol { private func prepareToShowAuth() { LogService.log(topic: .db) { return "Clear storage: Splash" } - storageService.clearStorage() - mqttService.reconnect() - presenter.showAuth() } - } diff --git a/Nynja/Modules/Splash/Presenter/SplashPresenter.swift b/Nynja/Modules/Splash/Presenter/SplashPresenter.swift index f001fed03c86c84548e7b3b774b7258d4ea5a274..8a75ead4a6132517bafb3020153b47e091b950c0 100644 --- a/Nynja/Modules/Splash/Presenter/SplashPresenter.swift +++ b/Nynja/Modules/Splash/Presenter/SplashPresenter.swift @@ -7,10 +7,6 @@ // class SplashPresenter: BasePresenter, SplashPresenterProtocol, SplashInteractorOutputProtocol { - - override var itemsFactory: WCItemsFactory? { - return AboutItemsFactory() - } weak var view: SplashViewProtocol! var interactor: SplashInteractorInputProtocol! diff --git a/Nynja/Modules/Splash/View/SplashViewController.swift b/Nynja/Modules/Splash/View/SplashViewController.swift index 43a74e7c4d9f7dd4ab61bb029abd3b671f12db33..8bd60fbdad351add87fa5368bb443a13dd365a5d 100644 --- a/Nynja/Modules/Splash/View/SplashViewController.swift +++ b/Nynja/Modules/Splash/View/SplashViewController.swift @@ -38,20 +38,6 @@ class SplashViewController: BaseVC, SplashViewProtocol { return UIView() }() - lazy var info: UILabel = { - let lbl = UILabel() - lbl.font = UIFont(name: FontFamily.NotoSans.bold.name, size: 16)! - lbl.numberOfLines = 0 - lbl.textColor = UIColor.nynja.manatee - self.view.addSubview(lbl) - - lbl.snp.makeConstraints({ (make) in - make.left.equalTo(self.view).offset(30) - self.adjustVerticalInset(.top, make: make, offset: 30) - }) - return lbl - }() - // MARK: - View lifecycle @@ -59,9 +45,6 @@ class SplashViewController: BaseVC, SplashViewProtocol { super.viewDidLoad() self.view.frame = UIScreen.main.bounds splash.isHidden = false - if let buildVersion = Bundle.main.buildVersion { - info.text = "Build: \(buildVersion)" - } } override func viewDidAppear(_ animated: Bool) { diff --git a/Nynja/Modules/Splash/WireFrame/SplashWireframe.swift b/Nynja/Modules/Splash/WireFrame/SplashWireframe.swift index 949955c740463634f2c0eae9538bbb637a592731..84636f7d966617fe86b38ce7c9b469b63ceb6806 100644 --- a/Nynja/Modules/Splash/WireFrame/SplashWireframe.swift +++ b/Nynja/Modules/Splash/WireFrame/SplashWireframe.swift @@ -38,7 +38,7 @@ class SplashWireFrame: SplashWireFrameProtocol { } func showMain() { - MainWireFrame().presentMain(navigation: navigation!, isRegistered: false, checkSession: true) + MainWireFrame().presentMain(navigation: navigation!, isRegistered: false) } func showEditProfile() { diff --git a/Nynja/MySelfItemsFactory.swift b/Nynja/MySelfItemsFactory.swift index 0b22bb6d30779de4555101f8842e8cab88e9b700..accd5988865f941eeb8cffd101e2c2f04002dce4 100644 --- a/Nynja/MySelfItemsFactory.swift +++ b/Nynja/MySelfItemsFactory.swift @@ -12,7 +12,6 @@ class MySelfItemsFactory: ChatBaseFactory { override var mySelf: ImageActionItemModel { let item = super.mySelf - // TODO: state item.isUserInteractionEnabled = false item.state = .highlighted return item diff --git a/Nynja/Notifications/AppNotificationsProviding/AppNotificationsProvider.swift b/Nynja/Notifications/AppNotificationsProviding/AppNotificationsProvider.swift index 02f17cc707931b7a8fe198d542d693912b679cd7..57dc2096e6d7e74d342f945c42177c37fef73438 100644 --- a/Nynja/Notifications/AppNotificationsProviding/AppNotificationsProvider.swift +++ b/Nynja/Notifications/AppNotificationsProviding/AppNotificationsProvider.swift @@ -6,12 +6,15 @@ // Copyright © 2018 TecSynt Solutions. All rights reserved. // -class AppNotificationsProvider: AppNotificationsProviding { +import UIKit + +final class AppNotificationsProvider: AppNotificationsProviding { private let notificationCenter = NotificationCenter.default var didEnterBackgroundHandler: AppNotificationsHandler? var willEnterForegroundHandler: AppNotificationsHandler? + var willTerminateHandler: AppNotificationsHandler? // MARK: - Init @@ -27,6 +30,11 @@ class AppNotificationsProvider: AppNotificationsProviding { selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil) + notificationCenter.addObserver( + self, + selector: #selector(willTerminate), + name: UIApplication.willTerminateNotification, + object: nil) } deinit { @@ -44,4 +52,7 @@ class AppNotificationsProvider: AppNotificationsProviding { willEnterForegroundHandler?() } + @objc private func willTerminate() { + willTerminateHandler?() + } } diff --git a/Nynja/Notifications/AppNotificationsProviding/AppNotificationsProviding.swift b/Nynja/Notifications/AppNotificationsProviding/AppNotificationsProviding.swift index 4429c09a7422fa90a438e284e27c1274ea8f5fca..51509dea5861c430aabc6e3a118673d8bc21d9fd 100644 --- a/Nynja/Notifications/AppNotificationsProviding/AppNotificationsProviding.swift +++ b/Nynja/Notifications/AppNotificationsProviding/AppNotificationsProviding.swift @@ -11,4 +11,5 @@ typealias AppNotificationsHandler = () -> Void protocol AppNotificationsProviding { var didEnterBackgroundHandler: AppNotificationsHandler? { get set } var willEnterForegroundHandler: AppNotificationsHandler? { get set } + var willTerminateHandler: AppNotificationsHandler? { get set } } diff --git a/Nynja/OptionsItemsFactory.swift b/Nynja/OptionsItemsFactory.swift index ca864d3d2177b136eed6e51900aea9cb43e9b077..31c56be5509dd12b6663eb5d6fd2c31c43b471f1 100644 --- a/Nynja/OptionsItemsFactory.swift +++ b/Nynja/OptionsItemsFactory.swift @@ -19,7 +19,7 @@ class OptionsItemsFactory: WCBaseItemsFactory { override var secondLevelItems: ItemModels { var items = [ logout, notifications, changeNumber, wheelPosition, buildNumber, - support, languageSettings, theme, dataAndStorage, security, privacy + support, languageSettings, theme, dataAndStorage, activeSessions, privacy ] #if DEBUG @@ -45,11 +45,9 @@ class OptionsItemsFactory: WCBaseItemsFactory { } var wheelPosition: ImageActionItemModel { - let item = ImageActionItemModel(navItem: .wheelPosition, isSelectable: false, action: { [weak navigateDelegate] (item, indexPath) in -// navigateDelegate?.showWheelPositionPicker(indexPath: indexPath) - navigateDelegate?.unavailableFunctionality() - }) - return item + return ImageActionItemModel(navItem: .wheelPosition) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showWheelPositionPicker(indexPath: indexPath) + }.asCommingSoon(navigateDelegate: navigateDelegate) } var buildNumber: ImageActionItemModel { @@ -67,11 +65,9 @@ class OptionsItemsFactory: WCBaseItemsFactory { } var theme: ImageActionItemModel { - let item = ImageActionItemModel(navItem: .theme, isSelectable: false, action: { [weak navigateDelegate] (item, indexPath) in -// navigateDelegate?.showThemePicker(indexPath: indexPath) - navigateDelegate?.unavailableFunctionality() - }) - return item + return ImageActionItemModel(navItem: .theme) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showThemePicker(indexPath: indexPath) + }.asCommingSoon(navigateDelegate: navigateDelegate) } var privacy: ImageActionItemModel { @@ -81,14 +77,6 @@ class OptionsItemsFactory: WCBaseItemsFactory { return item } - var about: ImageActionItemModel { - let item = ImageActionItemModel(navItem: .about, isSelectable: false, action: { [weak navigateDelegate] (item, indexPath) in -// navigateDelegate?.showAbout(indexPath: indexPath) - navigateDelegate?.unavailableFunctionality() - }) - return item - } - var deleteAccount: ImageActionItemModel { let item = ImageActionItemModel(navItem: .deleteAccount, action: { [weak navigateDelegate] (item, indexPath) in #if DEBUG @@ -104,11 +92,9 @@ class OptionsItemsFactory: WCBaseItemsFactory { } var changeNumber: ImageActionItemModel { - let item = ImageActionItemModel(navItem: .phoneNumber, isSelectable: false, action: { [weak navigateDelegate] (item, indexPath) in -// navigateDelegate?.showChangeNumber(indexPath: indexPath) - navigateDelegate?.unavailableFunctionality() - }) - return item + return ImageActionItemModel(navItem: .phoneNumber) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showChangeNumber(indexPath: indexPath) + }.asCommingSoon(navigateDelegate: navigateDelegate) } var dataAndStorage: ImageActionItemModel { @@ -118,19 +104,16 @@ class OptionsItemsFactory: WCBaseItemsFactory { return item } - var security: ImageActionItemModel { - let item = ImageActionItemModel(navItem: .security, action: { [weak navigateDelegate] (item, indexPath) in - navigateDelegate?.showSecuritySettings(indexPath: indexPath) + var activeSessions: ImageActionItemModel { + let item = ImageActionItemModel(navItem: .activeSessions, action: { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showActiveSessions(indexPath: indexPath) }) return item } var languageSettings: ImageActionItemModel { - let item = ImageActionItemModel(navItem: .language, isSelectable: false, action: { [weak navigateDelegate] (item, indexPath) in -// navigateDelegate?.showLanguageSettings(indexPath: indexPath) - navigateDelegate?.unavailableFunctionality() - }) - return item + return ImageActionItemModel(navItem: .language) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showLanguageSettings(indexPath: indexPath) + }.asCommingSoon(navigateDelegate: navigateDelegate) } - } diff --git a/Nynja/P2pChatItemsFactory.swift b/Nynja/P2pChatItemsFactory.swift index 94b96472794228ddf5590ba7a23547e53514ac89..88443b8de9cc6517b1ce4b01a644dfd414e32d4a 100644 --- a/Nynja/P2pChatItemsFactory.swift +++ b/Nynja/P2pChatItemsFactory.swift @@ -32,14 +32,24 @@ class P2pChatItemsFactory: ChatBaseFactory { // MARK: - Second lvl - override var payment: ImageActionItemModel { - let item = super.payment + var payment: ImageActionItemModel { + let item = ImageActionItemModel( + nameImage: "ic_pay", + navItem: .payment, + action: { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showPayment(indexPath: indexPath) + }) item.state = isPaymentEnabled ? .normal : .disabled return item } override var secondLevelItems: ItemModels { - let items = [chatOptions, payment, location, contact, call, media, camera] + let items: ItemModels + if FeatureFlags.isTransferActionEnabled.value { + items = [chatOptions, payment, location, contact, call, media, camera] + } else { + items = [chatOptions, location, contact, call, media, camera] + } items.forEach { item in let action = item.action diff --git a/Nynja/P2pChatsItemsFactory.swift b/Nynja/P2pChatsItemsFactory.swift index 0a9d43d9f166338bd40ff47ecd00e2a9db53fcf0..3820af5656bf797006ea696caf0f3354b557f60e 100644 --- a/Nynja/P2pChatsItemsFactory.swift +++ b/Nynja/P2pChatsItemsFactory.swift @@ -18,26 +18,38 @@ class P2pChatsItemsFactory: ChatsItemsFactory { // MARK: - Items - + override var all : ImageActionItemModel { - let item = ImageActionItemModel(nameImage: "ic_list", navItem: .all, action: { [weak navigateDelegate] (item, indexPath) in - navigateDelegate?.showP2PList(indexPath: indexPath) - }) + let item = ImageActionItemModel( + nameImage: UIImage.nynja.Wheel.WheelItems.icList.name, + navItem: .all) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showP2PList(indexPath: indexPath) + } item.state = .highlighted return item } override var recent : ImageActionItemModel { - let item = ImageActionItemModel(nameImage: "ic_recents", navItem: .recents, action: { [weak navigateDelegate] (item, indexPath) in - navigateDelegate?.showRecentP2PChats(indexPath: indexPath) - }) - return item + return ImageActionItemModel( + nameImage: UIImage.nynja.Wheel.WheelItems.icRecents.name, + navItem: .recents) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showRecentP2PChats(indexPath: indexPath) + } } - override var new: WheelItemModel { - return ImageActionItemModel(nameImage: "ic_new_chat", navItem: .newChat, action: { [weak navigateDelegate] (item, indexPath) in - navigateDelegate?.showByContacts(indexPath: indexPath) - }) + override var starred: ImageActionItemModel { + return ImageActionItemModel( + nameImage: UIImage.nynja.Wheel.WheelItems.icStarred.name, + navItem: .starred) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showFavorites(indexPath: indexPath, mode: .chats) + } } + override var new: WheelItemModel { + return ImageActionItemModel( + nameImage: UIImage.nynja.Wheel.WheelItems.icNewChat.name, + navItem: .newChat) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showByContacts(indexPath: indexPath) + } + } } diff --git a/Nynja/Resources/Assets.xcassets/Messages/ContextMenu/ic_another_language_transcribe_context_menu.imageset/ic_another_language_transcribe_context_menu.pdf b/Nynja/Resources/Assets.xcassets/Messages/ContextMenu/ic_another_language_transcribe_context_menu.imageset/ic_another_language_transcribe_context_menu.pdf index 65793145db7d5f5f668b103b50d50ae1648a2120..9bafb2a1629a25d3f45d7047f0fe5efaa55f1433 100644 Binary files a/Nynja/Resources/Assets.xcassets/Messages/ContextMenu/ic_another_language_transcribe_context_menu.imageset/ic_another_language_transcribe_context_menu.pdf and b/Nynja/Resources/Assets.xcassets/Messages/ContextMenu/ic_another_language_transcribe_context_menu.imageset/ic_another_language_transcribe_context_menu.pdf differ diff --git a/Nynja/Resources/Assets.xcassets/Messages/ContextMenu/ic_another_language_translate_context_menu.imageset/ic_another_language_translate_context_menu.pdf b/Nynja/Resources/Assets.xcassets/Messages/ContextMenu/ic_another_language_translate_context_menu.imageset/ic_another_language_translate_context_menu.pdf index dd2b796d3bc9a10e969888799e13c0ef5df07767..d0a053dd70e0bc3092f2b43b6badcc986200d1b0 100644 Binary files a/Nynja/Resources/Assets.xcassets/Messages/ContextMenu/ic_another_language_translate_context_menu.imageset/ic_another_language_translate_context_menu.pdf and b/Nynja/Resources/Assets.xcassets/Messages/ContextMenu/ic_another_language_translate_context_menu.imageset/ic_another_language_translate_context_menu.pdf differ diff --git a/Nynja/Resources/Colors.json b/Nynja/Resources/Colors.json index 050637876e93e7f659b780d963e7294aa700e3cb..6f8e098e93afc170a3ac0d011acee8ed9b29d027 100644 --- a/Nynja/Resources/Colors.json +++ b/Nynja/Resources/Colors.json @@ -2,6 +2,7 @@ "mainRed": "#c90010", "wheelBackHighlitedGray": "#45484D", "contentDisabledGray": "#505255", + "wheelItemDisabledColor": "#ffffff80", "backgroundColor": "#272a30", "gray": "#666666", "manatee": "#959699", diff --git a/Nynja/Resources/Info.plist b/Nynja/Resources/Info.plist index 9c128eb7ee3cf56dd38d56245c85b46902e7e727..e548e46a6329371ceb5d431c3904b33db3b77076 100644 --- a/Nynja/Resources/Info.plist +++ b/Nynja/Resources/Info.plist @@ -21,9 +21,9 @@ CFBundlePackageType APPL CFBundleShortVersionString - 1.0 + 0.8.0 CFBundleVersion - 0.5.5 + 0.8.3 ConfServerAddress $(ConfServerAddress) ConfServerPort diff --git a/Nynja/Resources/ReleaseConfig.xcconfig b/Nynja/Resources/ReleaseConfig.xcconfig index f65b25f2e8785121a37b607380cc213fcad8e8e6..1c5970aa361ac165cc1b574c40372b3a1ff9eec7 100644 --- a/Nynja/Resources/ReleaseConfig.xcconfig +++ b/Nynja/Resources/ReleaseConfig.xcconfig @@ -9,9 +9,9 @@ BundleIdentifier = com.nynja.mobile.communicator ExtensionBundleIdentifier = com.nynja.mobile.communicator.Nynja-Share -ServerURL = im-fallback.nynja.net +ServerURL = im.nynja.net AppName = NYNJA -ServerPort = 8443 +ServerPort = 443 Config = release AppGroup = group.com.nynja.mobile.communicator ModelsVersion = 10 diff --git a/Nynja/Resources/countries.txt b/Nynja/Resources/countries.txt index e2a2b8d1df8aa1470dca41c455a0edbbeb954639..19c54c4afc7d77e0dd5c3f6ed2a9db34db3e6426 100644 --- a/Nynja/Resources/countries.txt +++ b/Nynja/Resources/countries.txt @@ -40,17 +40,14 @@ 964;IQ;Iraq;XXX XXX XXXX 963;SY;Syria;XXX XXX XXX 962;JO;Jordan;X XXXX XXXX -961;LB;Lebanon +961;LB;Lebanon; XX XXXXXX 960;MV;Maldives;XXX XXXX 886;TW;Taiwan;XXX XXX XXX -883;GO;International Networks -882;GO;International Networks -881;GO;Global Mobile Satellite 880;BD;Bangladesh 856;LA;Laos;XX XX XXX XXX 855;KH;Cambodia 853;MO;Macau;XXXX XXXX -852;HK;Hong Kong;X XXX XXXX +852;HK;Hong Kong;XXXX XXXX 850;KP;North Korea 692;MH;Marshall Islands 691;FM;Micronesia @@ -101,7 +98,6 @@ 387;BA;Bosnia & Herzegovina;XX XXX XXX 386;SI;Slovenia;XX XXX XXX 385;HR;Croatia -383;XK;Kosovo;XXXX XXXX 382;ME;Montenegro 381;RS;Serbia;XX XXX XXXX 380;UA;Ukraine;XX XXX XX XX @@ -226,7 +222,7 @@ 32;BE;Belgium;XXX XX XX XX 31;NL;Netherlands;X XX XX XX XX 30;GR;Greece;XXX XXX XXXX -27;ZA;South Africa;XX XXX XXXX +27;ZA;South Africa;XXX XXXX 20;EG;Egypt;XX XXXX XXXX 7;KZ;Kazakhstan;XXX XXX XX XX 7;RU;Russian Federation;XXX XXX XXXX diff --git a/Nynja/Resources/en.lproj/Localizable.strings b/Nynja/Resources/en.lproj/Localizable.strings index 16152023fea03f9aa30249dceeaf383db6cfc664..7a70d914ee4866bd3767f523fc409d3c73c8be52 100644 --- a/Nynja/Resources/en.lproj/Localizable.strings +++ b/Nynja/Resources/en.lproj/Localizable.strings @@ -587,7 +587,6 @@ "wheel_item_byContacts"="By Contacts"; "wheel_item_options"="Settings"; "wheel_item_logOut"="Log Out"; -"wheel_item_about"="About"; "wheel_item_deleteAccount"="Delete Account"; "wheel_item_send"="Send Location"; "wheel_item_language"="Language"; @@ -596,11 +595,14 @@ "wheel_support"="Support"; "wheel_theme"="Theme"; "wheel_data_and_storage" = "Data and Storage"; -"wheel_security" = "Security"; +"wheel_active_sessions" = "Active sessions"; "wheel_privacy"="Privacy"; "wheel_invite_friends"="Invite Friends"; "wheel_item_transfer" = "Transfer"; "wheel_item_help" = "Help & Feedback"; +"wheel_item_call_contact" = "Call Сontact"; +"wheel_item_dial_number" = "Dial Number"; +"wheel_item_call_history" = "Call History"; // MARK: Main "main_undefined"="Undefined"; @@ -693,26 +695,25 @@ "invite_to_nynja" = "INVITE TO NYNJA"; "no_contacts_selected" = "No contacts selected"; "contacts_were_not_fetched" = "Contacts were not fetched"; -"nynja_share_string" = "I'm using the new SuperApp! called NYNJA! It is an amazing productivity and communications app for everyone like you've never seen before https://beta.nynja.net/"; +"nynja_share_string" = "I'm using the new SuperApp! called NYNJA! It is an amazing productivity and communications app for everyone like you've never seen before https://www.nynja.io/"; "sms_functionality_is_not_available" = "send sms functionality is not available on your phone"; //MARK: Security -"security_title" = "SECURITY"; -"security_current_session" = "Current session"; -"security_active_sessions" = "Active sessions"; -"security_terminate_all_other_sessions" = "Terminate All Other Sessions"; -"security_logs_out_all_devices" = "Logs out all devices except for this one."; -"security_tap_on_a_session" = "Tap on a session to terminate."; -"security_terminate" = "Terminate this session?"; -"security_you_sure" = "Are you sure you want to terminate all other sessions?"; -"security_waiting_for_network" = "Waiting for Network..."; -"security_no_internet_connection" = "Please check Internet connection and try again."; -"security_nynja" = "NYNJA"; -"security_undefined" = "Undefined"; -"security_no" = "No"; -"security_yes" = "Yes"; -"security_active" = "active"; -"security_no_data" = "No Data"; +"active_sessions_title" = "Active sessions"; +"active_sessions_current_session" = "Current session"; +"active_sessions_terminate_all_other_sessions" = "Terminate All Other Sessions"; +"active_sessions_logs_out_all_devices" = "Logs out all devices except for this one."; +"active_sessions_tap_on_a_session" = "Tap on a session to terminate."; +"active_sessions_terminate" = "Terminate this session?"; +"active_sessions_you_sure" = "Are you sure you want to terminate all other sessions?"; +"active_sessions_waiting_for_network" = "Waiting for Network..."; +"active_sessions_no_internet_connection" = "Please check Internet connection and try again."; +"active_sessions_nynja" = "NYNJA"; +"active_sessions_undefined" = "Undefined"; +"active_sessions_no" = "No"; +"active_sessions_yes" = "Yes"; +"active_sessions_active" = "active"; +"active_sessions_no_data" = "No Data"; //MARK: Privacy "privacy screen title" = "PRIVACY"; diff --git a/Nynja/Services/Amazon+FileSync.swift b/Nynja/Services/Amazon+FileSync.swift index c76edb8c5202796ff4a6956118ef32f76e365374..73afda4949514b02a8f2708c26850e10bc5912e7 100644 --- a/Nynja/Services/Amazon+FileSync.swift +++ b/Nynja/Services/Amazon+FileSync.swift @@ -20,7 +20,8 @@ extension AmazonManager: FileDownloader { let downloadRequest = AWSS3TransferManagerDownloadRequest() downloadRequest?.bucket = destination.bucket - downloadRequest?.key = destination.bucketContentPrefix.map { "\($0)/\(encodedFileName)" } ?? encodedFileName + let key = destination.bucketContentPrefix.map { "\($0)/\(encodedFileName)" } ?? encodedFileName + downloadRequest?.key = key.removingPercentEncoding downloadRequest?.downloadingFileURL = downloadingFileURL let requestStartTime = CFAbsoluteTimeGetCurrent() diff --git a/Nynja/Services/CameraSettingsService/CameraSettingsService.swift b/Nynja/Services/CameraSettingsService/CameraSettingsService.swift index 2b8ab4b4b9046d04c2e2b540e0e7c8cdfc70fecf..2db7c03002f934cf517bf7881b6c0dc93dc35a2e 100644 --- a/Nynja/Services/CameraSettingsService/CameraSettingsService.swift +++ b/Nynja/Services/CameraSettingsService/CameraSettingsService.swift @@ -90,7 +90,7 @@ extension CameraSettingsService { @discardableResult func makeDefaultSettings() -> CameraSettings { let settings = CameraSettings( - isScanQRCodes: .qrCodes(value: false), + isScanQRCodes: .qrCodes(value: true), isDrawGrid: .grid(value: false), isGeotaggingEnabled: .geotagging(value: false), photoQuality: .photoQuality(value: .high), diff --git a/Nynja/Services/ConnectionService.swift b/Nynja/Services/ConnectionService.swift index 8e63753bd0ded80bf10b753e459403c03b3d5530..03f4e3f29a14d5a351b446c8cc21f3ff7fe4318c 100644 --- a/Nynja/Services/ConnectionService.swift +++ b/Nynja/Services/ConnectionService.swift @@ -53,7 +53,6 @@ class ConnectionService { LogService.log(topic: .connectionState) { let result = "service: \(service) changed value from \(oldValue) to \(state), so connection state is: \n" return result + self.stateString() - } } diff --git a/Nynja/Services/MQTT/ConnectionHandlers/AppGroupConnectionHandler.swift b/Nynja/Services/MQTT/ConnectionHandlers/AppGroupConnectionHandler.swift new file mode 100644 index 0000000000000000000000000000000000000000..c7109300cb87fa568466f2e7b361b0ee3e9c5297 --- /dev/null +++ b/Nynja/Services/MQTT/ConnectionHandlers/AppGroupConnectionHandler.swift @@ -0,0 +1,41 @@ +// +// AppGroupConnectionHandler.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 12/10/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +final class AppGroupConnectionHandler: MQTTConnectionHandler { + + private let appGroupObserver = AppGroupFlagObserver(fileManager: .default, appGroup: Bundle.main.appGroupName) + + private(set) var connectionState: State = .connected + + func configure(with mqttService: MQTTService) { + do { + try appGroupObserver?.prepare() + try appGroupObserver?.removeFlagIfExists(.shareExtension) + try appGroupObserver?.observe { [weak mqttService, weak self] flags in + if flags.contains(.shareExtension) { + mqttService?.disconnect() + self?.connectionState = .disconnected + } else { + mqttService?.connect() + self?.connectionState = .connected + } + } + } catch { + LogService.log(topic: .fileSystem) { error.localizedDescription } + } + } +} + + +extension AppGroupConnectionHandler { + + enum State { + case connected + case disconnected + } +} diff --git a/Nynja/Services/MQTT/ConnectionHandlers/AppLifecycleConnectionHandler.swift b/Nynja/Services/MQTT/ConnectionHandlers/AppLifecycleConnectionHandler.swift new file mode 100644 index 0000000000000000000000000000000000000000..83a1a43c4580fb74a321f7f77314bacfd06e192a --- /dev/null +++ b/Nynja/Services/MQTT/ConnectionHandlers/AppLifecycleConnectionHandler.swift @@ -0,0 +1,26 @@ +// +// AppLifecycleConnectionHandler.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 12/10/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +final class AppLifecycleConnectionHandler: MQTTConnectionHandler { + + private let appNotificationProvider = AppNotificationsProvider() + + func configure(with mqttService: MQTTService) { + let disconnectClosure: AppNotificationsHandler = { [weak mqttService] in + mqttService?.disconnect() + } + + appNotificationProvider.didEnterBackgroundHandler = disconnectClosure + + appNotificationProvider.willEnterForegroundHandler = { [weak mqttService] in + mqttService?.connect() + } + + appNotificationProvider.willTerminateHandler = disconnectClosure + } +} diff --git a/Nynja/Services/MQTT/ConnectionHandlers/AutoReconnectConnectionHandler.swift b/Nynja/Services/MQTT/ConnectionHandlers/AutoReconnectConnectionHandler.swift new file mode 100644 index 0000000000000000000000000000000000000000..2570423799fd5c56be510b3130f03e1675e24e7f --- /dev/null +++ b/Nynja/Services/MQTT/ConnectionHandlers/AutoReconnectConnectionHandler.swift @@ -0,0 +1,43 @@ +// +// AutoReconnectConnectionHandler.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 12/10/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation +import UIKit + +final class AutoReconnectConnectionHandler: MQTTConnectionHandler { + + private var timerHandler: TimerHandler? + private let timeInterval: TimeInterval + + var shouldPerformReconnect: (() -> Bool)? + + init(timeInterval: TimeInterval) { + self.timeInterval = timeInterval + } + + func configure(with mqttService: MQTTService) { + mqttService.addSubscriber(self) + + timerHandler = TimerHandler(interval: timeInterval, repeats: true) { [weak mqttService, weak self] _ in + guard let shouldPerformReconnect = self?.shouldPerformReconnect, + shouldPerformReconnect() else { + return + } + mqttService?.connect() + } + } +} + + +extension AutoReconnectConnectionHandler: MQTTServiceDelegate { + + func mqttServiceDidReceiveWrongServerVersion() { + timerHandler?.invalidate() + timerHandler = nil + } +} diff --git a/Nynja/Services/MQTT/ConnectionHandlers/ReachabilityConnectionHandler.swift b/Nynja/Services/MQTT/ConnectionHandlers/ReachabilityConnectionHandler.swift new file mode 100644 index 0000000000000000000000000000000000000000..fccbcb7170373e9c8041c3fcc7585afb33e3b80b --- /dev/null +++ b/Nynja/Services/MQTT/ConnectionHandlers/ReachabilityConnectionHandler.swift @@ -0,0 +1,40 @@ +// +// ReachabilityConnectionHandler.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 12/10/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +final class ReachabilityConnectionHandler: MQTTConnectionHandler { + + private var mqttService: MQTTService? + + func configure(with mqttService: MQTTService) { + self.mqttService = mqttService + ConnectionService.shared.addSubscriber(self) + } +} + + +extension ReachabilityConnectionHandler: ConnectionServiceDelegate { + + func connectionStatusChanged(_ sender: ConnectionService, + service: ConnectionService.Service, + oldValue: ConnectionService.ConnectionServiceState) { + + if service == .networking { + guard let networkStatus = sender.state[.networking] else { return } + switch networkStatus { + case .connected: + mqttService?.connect() + case .disconnected: + mqttService?.disconnect() + case .switched: + mqttService?.reconnect() + default: + break + } + } + } +} diff --git a/Nynja/Services/MQTT/ConnectionHandlers/TokenConnectionHandler.swift b/Nynja/Services/MQTT/ConnectionHandlers/TokenConnectionHandler.swift new file mode 100644 index 0000000000000000000000000000000000000000..e26cd419b491b4186e3a7ca7fdc2435e8256b4ca --- /dev/null +++ b/Nynja/Services/MQTT/ConnectionHandlers/TokenConnectionHandler.swift @@ -0,0 +1,24 @@ +// +// TokenConnectionHandler.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 12/10/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +final class TokenConnectionHandler: MQTTConnectionHandler { + + private var mqttService: MQTTService? + private let userInfo: UserInfo + + init(userInfo: UserInfo) { + self.userInfo = userInfo + } + + func configure(with mqttService: MQTTService) { + self.mqttService = mqttService + userInfo.tokenChanged = { [weak mqttService] _ in + mqttService?.reconnect() + } + } +} diff --git a/Nynja/Services/MQTT/Extensions/MQTTService+Helper.swift b/Nynja/Services/MQTT/Extensions/MQTTService+Helper.swift index 9480c929de4e9bef43b1876ed2f8ebcd3290b836..5c75532f053af886b367e31d932f6a038f58b87f 100644 --- a/Nynja/Services/MQTT/Extensions/MQTTService+Helper.swift +++ b/Nynja/Services/MQTT/Extensions/MQTTService+Helper.swift @@ -10,7 +10,7 @@ import Foundation extension MQTTService { - enum Error: Swift.Error { + enum LogMessagePreparingError: Swift.Error { case messageWithoutPayload } @@ -42,7 +42,7 @@ extension MQTTService { private func prepareOutputMessage(msg: MQTTMessage, isSent: Bool) throws -> (String, BertObject) { guard let payload = msg.payload else { - throw Error.messageWithoutPayload + throw LogMessagePreparingError.messageWithoutPayload } let array = [UInt8](payload) diff --git a/Nynja/Services/MQTT/MQTTConnectionHandler.swift b/Nynja/Services/MQTT/MQTTConnectionHandler.swift new file mode 100644 index 0000000000000000000000000000000000000000..dbf573c988f9912bc18790fe8bc960f592b0c924 --- /dev/null +++ b/Nynja/Services/MQTT/MQTTConnectionHandler.swift @@ -0,0 +1,11 @@ +// +// MQTTConnectionHandler.swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 12/10/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +protocol MQTTConnectionHandler { + func configure(with mqttService: MQTTService) +} diff --git a/Nynja/Services/MQTT/MQTTService.swift b/Nynja/Services/MQTT/MQTTService.swift index b77c4d60a02c4ca7889a05d7381a125599a68d99..6d1f2bc33613a344e2fab8268b8ebb04ed4c7167 100644 --- a/Nynja/Services/MQTT/MQTTService.swift +++ b/Nynja/Services/MQTT/MQTTService.swift @@ -10,15 +10,13 @@ import Foundation import MQTTClient /// Performs works in the several serial background queues -final class MQTTService: NSObject, MQTTServiceProtocol, ConnectionServiceDelegate, MQTTSessionDelegate { +final class MQTTService: NSObject, MQTTServiceProtocol, MQTTSessionDelegate { private var mqtt: MQTTSession! let queuePool = QueuePool() let showHandlers: Set = [] - private var timerHandler: TimerHandler? - var deviceId: String { return UIDevice.current.persistentIdentifier } @@ -27,25 +25,6 @@ final class MQTTService: NSObject, MQTTServiceProtocol, ConnectionServiceDelegat return .sharedInstance } - private var autoReconnectTimeInterval: TimeInterval? { - willSet { - timerHandler?.invalidate() - timerHandler = nil - if let newValue = newValue { - timerHandler = TimerHandler(interval: newValue, repeats: true) { [weak self] _ in - self?.tryReconnect() - } - } - } - } - private(set) var isBadProtocolVersion: Bool = false { - willSet { - if newValue { - autoReconnectTimeInterval = nil - } - } - } - private(set) var isConnectedSuccess: Bool = false { didSet { guard oldValue != isConnectedSuccess else { @@ -64,6 +43,32 @@ final class MQTTService: NSObject, MQTTServiceProtocol, ConnectionServiceDelegat } } + private let connectionHandlers: [MQTTConnectionHandler] = { + let autoReconnectConnectionHandler = AutoReconnectConnectionHandler(timeInterval: 15) + + var handlers: [MQTTConnectionHandler] = [ + AppLifecycleConnectionHandler(), + autoReconnectConnectionHandler, + ReachabilityConnectionHandler(), + TokenConnectionHandler(userInfo: ServiceFactory().makeUserInfo()) + ] + + #if !SHARE_EXTENSION + let appGroupConnectionHandler = AppGroupConnectionHandler() + handlers.append(appGroupConnectionHandler) + + autoReconnectConnectionHandler.shouldPerformReconnect = { + [weak appGroupConnectionHandler] in + let connectionState = appGroupConnectionHandler?.connectionState ?? .connected + let isConnected = connectionState == .connected + let isAppActive = UIApplication.shared.applicationState == .active + return isConnected && isAppActive + } + #endif + + return handlers + }() + // MARK: - Subscribers @@ -78,6 +83,13 @@ final class MQTTService: NSObject, MQTTServiceProtocol, ConnectionServiceDelegat private override init() { MQTTLog.setLogLevel(DDLogLevel.off) mqtt = MQTTSession() + + super.init() + + mqtt.transport = makeTransport() + mqtt.delegate = self + + connectionHandlers.forEach { $0.configure(with: self) } } @@ -85,6 +97,11 @@ final class MQTTService: NSObject, MQTTServiceProtocol, ConnectionServiceDelegat func connect() { queuePool.processingQueue.async { [unowned self] in + let statuses: [MQTTSessionStatus] = [.connected, .connecting] + guard let mqtt = self.mqtt, !statuses.contains(mqtt.status) else { + return + } + self.setup() self.mqtt?.connect() } @@ -101,14 +118,11 @@ final class MQTTService: NSObject, MQTTServiceProtocol, ConnectionServiceDelegat mqtt.password = "" mqtt.cleanSessionFlag = false } - autoReconnectTimeInterval = 15 + logState() } private func commonSetup() { - mqtt.delegate = nil - mqtt = MQTTSession() mqtt.delegate = self - mqtt.transport = makeTransport() mqtt.userName = "api" mqtt.keepAliveInterval = 0 mqtt.willMsg = Data() @@ -135,21 +149,17 @@ final class MQTTService: NSObject, MQTTServiceProtocol, ConnectionServiceDelegat return transport } - func tryReconnect() { + func reconnect() { queuePool.processingQueue.async { [unowned self] in - let states: [MQTTSessionStatus] = [.created, .closed] - if let connState = self.mqtt?.status, states.contains(connState) { - self.reconnect() + if self.mqtt.status == .connected { + self.disconnect() } + self.connect() } } - func reconnect() { - disconnect() - connect() - } - func disconnect() { + logState() queuePool.processingQueue.async { [unowned self] in self.mqtt?.disconnect() } @@ -160,7 +170,10 @@ final class MQTTService: NSObject, MQTTServiceProtocol, ConnectionServiceDelegat func publish(model: BaseMQTTModel) { queuePool.processingQueue.async { [weak mqtt] in - guard let mqtt = mqtt, mqtt.status == .connected else { return } + guard let mqtt = mqtt, mqtt.status == .connected else { + return + } + let finalModel: MQTTMessage = model.getMessage() mqtt.publishData(finalModel.payload, onTopic: finalModel.topic, retain: false, qos: finalModel.qos) } @@ -181,13 +194,26 @@ final class MQTTService: NSObject, MQTTServiceProtocol, ConnectionServiceDelegat let msg = MQTTMessage(payload: data, topic: topic) printMessage(msg: msg, isSent: true) } + - func connected(_ session: MQTTSession!) { + + func handleEvent(_ session: MQTTSession!, event eventCode: MQTTSessionEvent, error: Error!) { queuePool.processingQueue.async { [unowned self] in - self.handleAccept() + switch eventCode { + case .connected: + self.handleAccept() + case .connectionClosed: + self.isConnectedSuccess = false + case .connectionRefused: + let mqttError = MQTTSessionError(rawValue: (error as NSError).code) + if mqttError == MQTTSessionError.connackBadUsernameOrPassword { + self.handleBadUsernameOrPassword() + } + case .protocolError, .connectionClosedByBroker, .connectionError: break + } } } - + private func handleAccept() { isConnectedSuccess = true @@ -198,21 +224,6 @@ final class MQTTService: NSObject, MQTTServiceProtocol, ConnectionServiceDelegat #endif } - func connectionClosed(_ session: MQTTSession!) { - queuePool.processingQueue.async { [unowned self] in - self.isConnectedSuccess = false - } - } - - private func connectionRefused(_ session: MQTTSession!, error: Error!) { - queuePool.processingQueue.async { [unowned self] in - let mqttError = MQTTSessionError(rawValue: (error as NSError).code) - if mqttError == MQTTSessionError.connackBadUsernameOrPassword { - self.handleBadUsernameOrPassword() - } - } - } - private func handleBadUsernameOrPassword() { if let actualToken = storageService.token, actualToken == mqtt.password { handleInvalidToken() @@ -231,19 +242,16 @@ final class MQTTService: NSObject, MQTTServiceProtocol, ConnectionServiceDelegat notifySubscribers { (delegate) in delegate.mqttServiceDidReceiveAuthenticationFailure(self) } - self.reconnect() #endif } private func handleBadProtocolVersion() { LogService.log(topic: .MQTT) { return "Bad protocol version" } - isBadProtocolVersion = true notifySubscribers { (delegate) in delegate.mqttServiceDidReceiveWrongServerVersion() } } - // MARK: Subscribers func addSubscriber(_ subscriber: MQTTServiceDelegate) { @@ -280,23 +288,9 @@ final class MQTTService: NSObject, MQTTServiceProtocol, ConnectionServiceDelegat } } - - // MARK: - ConnectionServiceDelegate - - func connectionStatusChanged( - _ sender: ConnectionService, - service: ConnectionService.Service, oldValue: ConnectionService.ConnectionServiceState) { - - queuePool.processingQueue.async { [unowned self] in - if service == .networking { - guard let networkStatus = sender.state[.networking] else { return } - switch networkStatus { - case .connected: self.mqtt?.connect() - case .disconnected: self.disconnect() - case .switched: self.reconnect() - default: break - } - } + private func logState() { + LogService.log(topic: .MQTT) { () -> String in + return "\n----- MQTT ----- \n ClientID: \(self.mqtt.clientId ?? "") \n Password: \(self.mqtt.password ?? "") \n CleanSession: \(self.mqtt.cleanSessionFlag) \n State: \(self.mqtt.status.descript) \n----- MQTT ----- \n" } } } @@ -314,3 +308,72 @@ struct MQTTMessage { if qos == nil { self.qos = .exactlyOnce } } } + +extension MQTTSessionStatus { + var descript: String { + switch self { + case .closed: + return "Closed" + case .connected: + return "Connected" + case .connecting: + return "Connecting" + case .created: + return "Created" + case .disconnecting: + return "Disconnecting" + case .error: + return "Error" + } + } +} + +extension MQTTSessionError { + var descript: String { + switch self { + case .connackBadUsernameOrPassword: + return "connackBadUsernameOrPassword" + case .connackIdentifierRejected: + return "connackIdentifierRejected" + case .connackNotAuthorized: + return "connackNotAuthorized" + case .connackReserved: + return "connackReserved" + case .connackServeUnavailable: + return "connackServeUnavailable" + case .connackUnacceptableProtocolVersion: + return "connackUnacceptableProtocolVersion" + case .connectionRefused: + return "connectionRefused" + case .droppingOutgoingMessage: + return "droppingOutgoingMessage" + case .encoderNotReady: + return "encoderNotReady" + case .illegalMessageReceived: + return "illegalMessageReceived" + case .invalidConnackReceived: + return "invalidConnackReceived" + case .noConnackReceived: + return "noConnackReceived" + } + } +} + +extension MQTTSessionEvent { + var descript: String { + switch self { + case .connected: + return "connected" + case .connectionClosed: + return "connectionClosed" + case .connectionClosedByBroker: + return "connectionClosedByBroker" + case .connectionError: + return "connectionError" + case .connectionRefused: + return "connectionRefused" + case .protocolError: + return "protocolError" + } + } +} diff --git a/Nynja/Services/MQTT/MQTTServiceProtocol.swift b/Nynja/Services/MQTT/MQTTServiceProtocol.swift index a58000f493c6ddca7d37e6e967381b32d3e7c6e5..6f9aa25f19759bc076eaee33e88fc8c180ac1465 100644 --- a/Nynja/Services/MQTT/MQTTServiceProtocol.swift +++ b/Nynja/Services/MQTT/MQTTServiceProtocol.swift @@ -10,11 +10,9 @@ protocol MQTTServiceProtocol { - var isBadProtocolVersion: Bool { get } var isConnectedSuccess: Bool { get } func connect() - func tryReconnect() func reconnect() func disconnect() diff --git a/Nynja/Services/MessageSendingService/MessageSendingService.swift b/Nynja/Services/MessageSendingService/MessageSendingService.swift index ffa6ba1174132314df027272dba25a78bac7d088..efda5a0438f06593ce6d5f031a1647e11021cf43 100644 --- a/Nynja/Services/MessageSendingService/MessageSendingService.swift +++ b/Nynja/Services/MessageSendingService/MessageSendingService.swift @@ -53,6 +53,7 @@ final class MessageSendingService: MessageSendingServiceProtocol, InitializeInje func sendMessage(_ message: Message) { try? storageService.perform(action: .save, with: message) + ChatService.updateLastMessage(message) processingManager.uploadMessage(message) } diff --git a/Nynja/Services/Models/SendModel.swift b/Nynja/Services/Models/SendModel.swift index ea1a85b68e67d97fc2a1750f3907d631cd7af82b..7b5956a1f14d433c5ccdad204d94408a459692ad 100644 --- a/Nynja/Services/Models/SendModel.swift +++ b/Nynja/Services/Models/SendModel.swift @@ -61,6 +61,11 @@ enum SendMessageType: String { .place: UIImage.nynja.LastMessageType.icLastLocation.image, .audioCall: UIImage.nynja.MainWheel.Actions.voiceCall.image ] + + var isDownloadable: Bool { + let types: [SendMessageType] = [.audio, .image, .file, .video] + return types.contains(self) + } } class SendMessageModel:BaseMQTTModel { diff --git a/Nynja/Services/NynjaCalls/NynjaCommunicatorService.swift b/Nynja/Services/NynjaCalls/NynjaCommunicatorService.swift index 526cd7e54b131159ba603208a08be1f776c47146..12ae7e6e5495dca7a1fb2999744244c5cff49217 100644 --- a/Nynja/Services/NynjaCalls/NynjaCommunicatorService.swift +++ b/Nynja/Services/NynjaCalls/NynjaCommunicatorService.swift @@ -79,8 +79,10 @@ class NynjaCommunicatorService: NSObject, NynjaCommunicatorDelegate, NYNCallDele override init() { var logDir:String? - let searchPaths = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true) + #if !RELEASE + let searchPaths = NSSearchPathForDirectoriesInDomains(.applicationSupportDirectory, .userDomainMask, true) + if searchPaths.count > 0 { var path:String = searchPaths[0] @@ -103,7 +105,8 @@ class NynjaCommunicatorService: NSObject, NynjaCommunicatorDelegate, NYNCallDele } } - + #endif + if let lgDir = logDir { self.nynComm = NynjaCommunicator.start(withLogDir: lgDir, andLogLevel: NYN_LOG_LEVEL.VERBOSE) } else { diff --git a/Nynja/Services/ServiceFactory/ServiceFactory.swift b/Nynja/Services/ServiceFactory/ServiceFactory.swift index ee390aef552b8ce4340378bd9c68b9ee5a887a16..a0b56ce22d0463392e60191d669622bf6954e4af 100644 --- a/Nynja/Services/ServiceFactory/ServiceFactory.swift +++ b/Nynja/Services/ServiceFactory/ServiceFactory.swift @@ -63,7 +63,6 @@ protocol ServiceFactoryProtocol: SharedServiceFactoryProtocol { func makeReachabilityService() -> ReachabilityService - func makeUserInfo() -> UserInfo func makeDatabaseManager() -> DBManagerProtocol func makeValidatorFactory() -> ValidatorFactory @@ -234,10 +233,6 @@ final class ServiceFactory: SharedServiceFactory, ServiceFactoryProtocol { return .sharedInstance } - func makeUserInfo() -> UserInfo { - return makeStorageService() - } - func makeDatabaseManager() -> DBManagerProtocol { return makeStorageService() } diff --git a/Nynja/Services/StorageService.swift b/Nynja/Services/StorageService.swift index 4bde6971eef2767a13af91d9c112d574be153dfa..a4188df4648c21fb845340759c5f8a800f8d38e3 100644 --- a/Nynja/Services/StorageService.swift +++ b/Nynja/Services/StorageService.swift @@ -124,6 +124,12 @@ class StorageService { } dropUserInfo() } + + func wipeKeychain() { + isolationQueue.sync { [weak self] in + self?.keychain.clear() + } + } } #if !SHARE_EXTENSION @@ -176,6 +182,11 @@ extension StorageService: UserInfo { var tokenData: Data? { get { return userInfo.tokenData } } + + var tokenChanged: ((String?) -> Void)? { + get { return userInfo.tokenChanged } + set { userInfo.tokenChanged = newValue } + } var pushToken: String? { get { return userInfo.pushToken } diff --git a/Nynja/UserIdentifiers.swift b/Nynja/UserIdentifiers.swift new file mode 100644 index 0000000000000000000000000000000000000000..76d175cf00d753a01820125f684d0da54bc31185 --- /dev/null +++ b/Nynja/UserIdentifiers.swift @@ -0,0 +1,21 @@ +// +// UserIdentifiers .swift +// Nynja +// +// Created by Volodymyr Hryhoriev on 12/10/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation + +enum UserIdentifiers: String { + case token + case pushToken + + case phone + case rosterId + case clientId = "clientID" + + case wasLogined + case wasRun +} diff --git a/Nynja/UserInfo.swift b/Nynja/UserInfo.swift index c04b6179c28ad7d5dda587fa0f97ff862c504a3d..59c7862f0bc59d9e9ede50cc52171bd21d143366 100644 --- a/Nynja/UserInfo.swift +++ b/Nynja/UserInfo.swift @@ -8,21 +8,10 @@ import Foundation -enum UserIdentifiers: String { - case token - case pushToken - - case phone - case rosterId - case clientId = "clientID" - - case wasLogined - case wasRun -} - protocol UserInfo: class { var token: String? { get set } var tokenData: Data? { get } + var tokenChanged: ((String?) -> Void)? { get set } var pushToken: String? { get set } diff --git a/Nynja/UserInfoImpl.swift b/Nynja/UserInfoImpl.swift index 6f81d898d6b05ffa0cfc7f92608b69b33b386586..529aa8c0737aa9e9e442b14829bd1903ccff8244 100644 --- a/Nynja/UserInfoImpl.swift +++ b/Nynja/UserInfoImpl.swift @@ -39,6 +39,8 @@ class UserInfoImpl: UserInfo, InitializeInjectable { return token } set { + tokenChanged?(token) + guard let token = newValue, let data = token.data(using: self.encoding) else { userDefaults?.removeObject(forKey: UserIdentifiers.token.rawValue) userDefaults?.synchronize() @@ -47,10 +49,11 @@ class UserInfoImpl: UserInfo, InitializeInjectable { set(data as NSData, forId: .token) LogService.log(topic: .userDefaults) { return "Save token: \(token)" } - MQTTService.sharedInstance.reconnect() // FIXME: I don't think it is proper place to do such thing } } + var tokenChanged: ((String?) -> Void)? + var pushToken: String? { get { return value(forId: .pushToken) } set { set(newValue, forId: .pushToken) } diff --git a/Nynja/ValidatorFactory/ValidatorFactoryImpl.swift b/Nynja/ValidatorFactory/ValidatorFactoryImpl.swift index e23ec5356bb2c496b60639d4da5971c5db118026..2a22b9b40d282bd1993e15edbaf7d89ddc87b399 100644 --- a/Nynja/ValidatorFactory/ValidatorFactoryImpl.swift +++ b/Nynja/ValidatorFactory/ValidatorFactoryImpl.swift @@ -13,6 +13,7 @@ class ValidatorFactoryImpl: ValidatorFactory { return [ LengthValidator(length: .max(maxLength, String.localizable.channelMaxLengthWarning)), ClosureValidator { text in + let text = text.trimmed() if text == "" { return InputInfo(text: message, kind: .warning) } diff --git a/Nynja/WCBaseItemsFactory.swift b/Nynja/WCBaseItemsFactory.swift index 4d77d14ecf259d4f2bd8fc50093505277aebf081..fdb1e97f26c0fbc3825d6845b287d4ab26b1007d 100644 --- a/Nynja/WCBaseItemsFactory.swift +++ b/Nynja/WCBaseItemsFactory.swift @@ -21,7 +21,11 @@ class WCBaseItemsFactory: WCItemsFactory { } var firstLevelItems: ItemModels { - return [marketplace, calls, options, home, search, mySelf, actions, chats, groups, contacts, channels] + if FeatureFlags.isMarketplaceEnabled.value { + return [marketplace, calls, options, home, search, mySelf, actions, chats, groups, contacts, channels] + } else { + return [calls, options, home, search, mySelf, actions, chats, groups, contacts, channels] + } } var secondLevelItems: ItemModels { @@ -53,11 +57,9 @@ class WCBaseItemsFactory: WCItemsFactory { var search: ImageActionItemModel { return ImageActionItemModel( nameImage: UIImage.nynja.Wheel.WheelItems.icSearch.name, - navItem: .search, - state: .disabled, - action: { [weak navigateDelegate] (item, indexPath) in + navItem: .search) { [weak navigateDelegate] (item, indexPath) in navigateDelegate?.showSearch(indexPath: indexPath) - }) + }.asCommingSoon(navigateDelegate: navigateDelegate) } var chats: ImageActionItemModel { @@ -108,11 +110,9 @@ class WCBaseItemsFactory: WCItemsFactory { var calls: ImageActionItemModel { return ImageActionItemModel( nameImage: UIImage.nynja.Wheel.WheelItems.icCalls.name, - navItem: .calls, - state: .normal, - action: { [weak navigateDelegate] (item, indexPath) in + navItem: .calls) { [weak navigateDelegate] (item, indexPath) in navigateDelegate?.showCalls(indexPath: indexPath) - }) + }.asCommingSoon(navigateDelegate: navigateDelegate) } var marketplace: ImageActionItemModel { @@ -126,10 +126,8 @@ class WCBaseItemsFactory: WCItemsFactory { var channels: ImageActionItemModel { return ImageActionItemModel( nameImage: UIImage.nynja.Wheel.WheelItems.icChannelInactive.name, - navItem: .channels, isSelectable: false) { [weak navigateDelegate] (item, indexPath) in - // navigateDelegate?.showChannels(indexPath: indexPath) - navigateDelegate?.unavailableFunctionality() - } + navItem: .channels) { [weak navigateDelegate] (item, indexPath) in + navigateDelegate?.showChannels(indexPath: indexPath) + }.asCommingSoon(navigateDelegate: navigateDelegate) } - } diff --git a/NynjaUnitTests/Services/UserInfo/UserInfoTest.swift b/NynjaUnitTests/Services/UserInfo/UserInfoTest.swift index 33f8f8054f868343c1a409bb110bbb3ea5a4ecfa..23b0bf82383b7e5c477412b799a1cc4f80809668 100644 --- a/NynjaUnitTests/Services/UserInfo/UserInfoTest.swift +++ b/NynjaUnitTests/Services/UserInfo/UserInfoTest.swift @@ -111,6 +111,7 @@ private extension UserInfoTest { class UserInfoMock: UserInfo { var token: String? var tokenData: Data? + var tokenChanged: ((String?) -> Void)? var pushToken: String? var phone: String? var rosterId: Int64? diff --git a/Podfile b/Podfile index a70f91f1c071a5b0c20c37b7751facc661b1369a..ccb23b6234373cfffa964771734eb10369751357 100644 --- a/Podfile +++ b/Podfile @@ -39,7 +39,7 @@ def commonPodsForNynja pod 'MaterialComponents/FlexibleHeader', '= 55.3.0' pod 'JTAppleCalendar', '= 7.1.6' - pod 'NynjaSDK', '= 1.8' + pod 'NynjaSDK', '= 1.8.1' pod 'CryptoSwift', '= 0.13.0' diff --git a/Podfile.lock b/Podfile.lock index 1d2aad740c4507a1f56a5f7a107986717990e964..d6dfcf8448a86e007986cfc6df445c38e2a200b6 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -62,7 +62,7 @@ PODS: - MQTTClient/Min - SocketRocket - MulticastDelegateSwift (2.1.1) - - NynjaSDK (1.8) + - NynjaSDK (1.8.1) - QRCode (2.0) - SDWebImage (4.4.2): - SDWebImage/Core (= 4.4.2) @@ -95,7 +95,7 @@ DEPENDENCIES: - MaterialComponents/FlexibleHeader (= 55.3.0) - MQTTClient/Websocket (= 0.15.2) - MulticastDelegateSwift (= 2.1.1) - - NynjaSDK (= 1.8) + - NynjaSDK (= 1.8.1) - QRCode (= 2.0) - SDWebImage (= 4.4.2) - SnapKit (= 4.2.0) @@ -172,7 +172,7 @@ SPEC CHECKSUMS: MDFTextAccessibility: 94098925e0853551c5a311ce7c1ecefbe297cdb6 MQTTClient: 902c7bcac1501595f3d0b15178c7205b40331fb0 MulticastDelegateSwift: 93eb077c24f50574b3f8a3f23bf71be6de6e3b41 - NynjaSDK: 3c245c3a1b1e5e650012d2f367260ecf4860e748 + NynjaSDK: 5fdd248089a3bbd8eee950efb84124628344bda8 QRCode: f98a1886c8f37523704a7512a4c0cd45b34c18a4 SDWebImage: 624d6e296c69b244bcede364c72ae0430ac14681 SnapKit: fe8a619752f3f27075cc9a90244d75c6c3f27e2a @@ -181,6 +181,6 @@ SPEC CHECKSUMS: SwiftyJSON: c4bcba26dd9ec7a027fc8eade48e2c911f229e96 TestFairy: 842f8ddc45477b208eb85326b0418047b40f7137 -PODFILE CHECKSUM: 955505f5c9ab80c1ec2042a2c5d6825a0ac12771 +PODFILE CHECKSUM: a26709f4f5bfd33de084ef65033a3017a3958d16 COCOAPODS: 1.5.3 diff --git a/Shared/Library/Extensions/Models/Message/Message+Files.swift b/Shared/Library/Extensions/Models/Message/Message+Files.swift index a2199d06af64536b4eade9abadd986811d2d70ab..148959fa15f0425b32684ea133e8a366fb1fdce9 100644 --- a/Shared/Library/Extensions/Models/Message/Message+Files.swift +++ b/Shared/Library/Extensions/Models/Message/Message+Files.swift @@ -66,7 +66,7 @@ extension Message { } var isDownloadable: Bool { - return sendType.flatMap { [.audio, .image, .file, .video].contains($0) } ?? false + return sendType?.isDownloadable ?? false } func isExistFile(for type: SendMessageType) -> Bool { diff --git a/Shared/Services/Handlers/AuthHandler/AuthHandler.swift b/Shared/Services/Handlers/AuthHandler/AuthHandler.swift index ef1dd76f4744da0c549c305fbdc4cdafb5678b78..02c74e852fd88cd656896b2dda53af878cd336c6 100644 --- a/Shared/Services/Handlers/AuthHandler/AuthHandler.swift +++ b/Shared/Services/Handlers/AuthHandler/AuthHandler.swift @@ -10,6 +10,10 @@ import Foundation final class AuthHandler: BaseHandler, StaticDelegating { + private static var storageService: StorageService { + return .sharedInstance + } + static weak var delegate: AuthHandlerDelegate? static func executeHandle(data: BertTuple) { @@ -25,7 +29,7 @@ final class AuthHandler: BaseHandler, StaticDelegating { if auth.type?.string == "update" { LogService.log(topic: .MQTT) { return "Recived new token: \(auth.token ?? "")" } if let token = auth.token { - StorageService.sharedInstance.token = token + storageService.token = token } } } diff --git a/Shared/Services/SharedServiceFactory/SharedServiceFactory.swift b/Shared/Services/SharedServiceFactory/SharedServiceFactory.swift index 40e54e9d20b5834f88b005881abd0a05c0661bd6..356d44dc564761c6a9b6a17bccacabfc0e622462 100644 --- a/Shared/Services/SharedServiceFactory/SharedServiceFactory.swift +++ b/Shared/Services/SharedServiceFactory/SharedServiceFactory.swift @@ -9,6 +9,7 @@ protocol SharedServiceFactoryProtocol: class { func makeMQTTService() -> MQTTService func makeStorageService() -> StorageService + func makeUserInfo() -> UserInfo func makeAmazonManager() -> AmazonManager func makeAmazonInitializer() -> AmazonInitializer func makeTypingSenderService() -> TypingSenderServiceProtocol @@ -25,6 +26,10 @@ class SharedServiceFactory: SharedServiceFactoryProtocol { return StorageService.sharedInstance } + func makeUserInfo() -> UserInfo { + return makeStorageService() + } + func makeAmazonManager() -> AmazonManager { return AmazonManager.shared }