diff --git a/.gitignore b/.gitignore index 7150d5f51c78c170f946c6d459dfd675c3cb3182..4bbaf767e833b0971dac648d17c267716498b793 100644 --- a/.gitignore +++ b/.gitignore @@ -56,7 +56,6 @@ Rambafile # # Add this line if you want to avoid checking in source code from Carthage dependencies. # Carthage/Checkouts -Podfile.lock Carthage/Build # fastlane diff --git a/Nynja-Share/Resources/Info.plist b/Nynja-Share/Resources/Info.plist index 1976d3b6c5e9baf83f0655ffd193ddaef0af733c..9632b42164bb8be81c033a377ab3fa0e664ff30e 100644 --- a/Nynja-Share/Resources/Info.plist +++ b/Nynja-Share/Resources/Info.plist @@ -21,7 +21,7 @@ CFBundleShortVersionString 1.0 CFBundleVersion - 0.2.158 + 0.2.163 Config $(Config) ModelsVersion diff --git a/Nynja-Share/UI/ForwardSelectorInteractor.swift b/Nynja-Share/UI/ForwardSelectorInteractor.swift index 0e9293cf67b59bf38541e61285f5cb211ee7a871..feabd988ef8bd913a4d1d033f09b53a54f611d60 100644 --- a/Nynja-Share/UI/ForwardSelectorInteractor.swift +++ b/Nynja-Share/UI/ForwardSelectorInteractor.swift @@ -46,6 +46,8 @@ final class ForwardSelectorInteractor: ForwardSelectorInteractorInputProtocol, P weak var presenter: ForwardSelectorInteractorOutputProtocol! + private let appGroupContainer = AppGroupFlagContainer(fileManager: .default, appGroup: Bundle.main.appGroupName) + private(set) var mode: ForwardSelectorMode var handlerServerSignals: ((ServerSignal)->())? @@ -74,15 +76,39 @@ final class ForwardSelectorInteractor: ForwardSelectorInteractorInputProtocol, P private var groups: [ForwardTarget]? + required init(mode: ForwardSelectorMode) { self.mode = mode ProfileHandler.delegate = self MessageHandler.delegate = self ContactHandler.delegate = self IoHandler.delegate = self - setupAmazon() + setupAmazon() + notifyHostApplication() + } + + deinit { + notifyHostApplicationAboutClose() + } + + func notifyHostApplication() { + do { + try appGroupContainer?.prepare() + try appGroupContainer?.setFlag(.shareExtension) + } catch { + LogService.log(topic: .fileSystem) { error.localizedDescription } + } } + func notifyHostApplicationAboutClose() { + do { + try appGroupContainer?.removeFlagIfExists(.shareExtension) + } catch { + LogService.log(topic: .fileSystem) { error.localizedDescription } + } + } + + func connectToServer() { if let token = StorageService.sharedInstance.token { LogService.log(topic: .MQTT) { return "token: \(token)" } @@ -225,7 +251,7 @@ final class ForwardSelectorInteractor: ForwardSelectorInteractorInputProtocol, P self.sendStatus(to: targets, type: t) } }) { (fileUrl, fileName, size) in - + var info: String? if type == .image, let resolution = UIImage(fileUrl: url)?.scaledSize { info = resolution.resolutionString @@ -237,6 +263,8 @@ final class ForwardSelectorInteractor: ForwardSelectorInteractorInputProtocol, P let messages = targets.messages(from: message, phoneId: phoneId) + try? FileManager.default.removeItem(at: url) + self.sendStatus(to: targets, type: .done) MQTTService.sharedInstance.forwardMessage(phoneId: phoneId, messages: messages) } diff --git a/Nynja-Share/UI/ForwardSelectorViewController.swift b/Nynja-Share/UI/ForwardSelectorViewController.swift index 5a85c781de80006e426defe816108f05bebb128a..ebc0def98e839e76561d31994102e646430051a0 100644 --- a/Nynja-Share/UI/ForwardSelectorViewController.swift +++ b/Nynja-Share/UI/ForwardSelectorViewController.swift @@ -290,6 +290,7 @@ final class ForwardSelectorViewController: UIViewController, ForwardSelectorView override func viewDidLoad() { super.viewDidLoad() + getAttachmentContent() presenter.view = self presenter.interactor.handlerServerSignals = { [weak self] signal in @@ -445,11 +446,19 @@ final class ForwardSelectorViewController: UIViewController, ForwardSelectorView if attachment.hasItemConformingToTypeIdentifier("public.image") { attachment.loadItem(forTypeIdentifier: "public.image", options: nil, completionHandler: { (coding, error) in - if coding is URL { + if let url = coding as? URL { model.type = .image - model.contentURL = coding as? URL + model.contentURL = url self.attachment = model return + } else if let image = coding as? UIImage { + model.type = .image + let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as String + let filePath = "\(documentDirectory)/\(IdBuilder(format: .resourceId).build()).jpg" + let url = URL(fileURLWithPath: filePath) + try? UIImageJPEGRepresentation(image, 1)?.write(to: url) + model.contentURL = url + self.attachment = model } }) } else if attachment.hasItemConformingToTypeIdentifier("public.audio") { diff --git a/Nynja.xcodeproj/project.pbxproj b/Nynja.xcodeproj/project.pbxproj index 179cef84f2b6c94ab420ddfb0319f678eaf8fdf0..5acd5dc33ff630281b70e09a8195da16cddd4867 100644 --- a/Nynja.xcodeproj/project.pbxproj +++ b/Nynja.xcodeproj/project.pbxproj @@ -146,6 +146,9 @@ 2606F3BC20BFE20500CF7F15 /* MessageInteractor+Translation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2606F3BB20BFE20400CF7F15 /* MessageInteractor+Translation.swift */; }; 260D67D92124616A0072F11F /* LogWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260D67D82124616A0072F11F /* LogWriter.swift */; }; 260D67DF2125A2FE0072F11F /* LogWriter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260D67D82124616A0072F11F /* LogWriter.swift */; }; + 260E77D9215D3C5000D18789 /* ComingSoonExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260E77D8215D3C5000D18789 /* ComingSoonExtension.swift */; }; + 260E77DB215D3C7700D18789 /* ComingSoonProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260E77DA215D3C7700D18789 /* ComingSoonProtocol.swift */; }; + 260E77DC215D3CCD00D18789 /* ComingSoonProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 260E77DA215D3C7700D18789 /* ComingSoonProtocol.swift */; }; 2610D4642076516900E6E2B2 /* Array+Feature.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26DCB25320692237001EF0AB /* Array+Feature.swift */; }; 26131E02210399BA00BE94F9 /* TranscribeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26131E01210399BA00BE94F9 /* TranscribeService.swift */; }; 26142B1120472ECD004E5FE4 /* MessageLinkTable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26142B1020472ECD004E5FE4 /* MessageLinkTable.swift */; }; @@ -305,6 +308,8 @@ 268C341C21075B4700F1472A /* Cancelable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 268C341B21075B4700F1472A /* Cancelable.swift */; }; 268C62E32008DA0900433705 /* UIImageExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3A1DFD7D1F5370A600F3A3D8 /* UIImageExtensions.swift */; }; 2691B76D2075504A00FB207C /* MQTTServiceSchedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0008E9122032D5AC003E316E /* MQTTServiceSchedule.swift */; }; + 2695F1FF21625B800095A0FA /* ChangableProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2695F1FE21625B800095A0FA /* ChangableProgress.swift */; }; + 2695F20121625CAB0095A0FA /* DisplayableProgress.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2695F20021625CAB0095A0FA /* DisplayableProgress.swift */; }; 269666181FB57963009E41C1 /* RoomHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269666171FB57963009E41C1 /* RoomHandler.swift */; }; 269848C8200E9D0400590D6F /* StarExtension+BERT.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269848C7200E9D0400590D6F /* StarExtension+BERT.swift */; }; 269848CA200E9F1300590D6F /* StarModels.swift in Sources */ = {isa = PBXBuildFile; fileRef = 269848C9200E9F1300590D6F /* StarModels.swift */; }; @@ -723,6 +728,10 @@ 850833DB2037171600587EEF /* FileExtensionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850833DA2037171600587EEF /* FileExtensionView.swift */; }; 8509452B206E684300B43C1C /* AddParticipantsContactCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8509452A206E684300B43C1C /* AddParticipantsContactCell.swift */; }; 8509AC62206A54420089089B /* ResponseResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8509AC61206A54420089089B /* ResponseResult.swift */; }; + 8509FC852158F7D100734D93 /* AppGroupFlagContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8509FC842158F7D100734D93 /* AppGroupFlagContainer.swift */; }; + 8509FC872158F7FC00734D93 /* DirectoryWatcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8509FC862158F7FC00734D93 /* DirectoryWatcher.swift */; }; + 8509FC89215908B300734D93 /* AppGroupFlagObserver.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8509FC88215908B300734D93 /* AppGroupFlagObserver.swift */; }; + 8509FC8A2159095900734D93 /* AppGroupFlagContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8509FC842158F7D100734D93 /* AppGroupFlagContainer.swift */; }; 850A0C6520469AED004F79AD /* UserSettingsRespondable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850A0C6420469AED004F79AD /* UserSettingsRespondable.swift */; }; 850A0C672046B65D004F79AD /* WCItemsFactoryDecorator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850A0C662046B65D004F79AD /* WCItemsFactoryDecorator.swift */; }; 850A2BB0203584B000D68FDF /* SearchActionsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 850A2BAF203584B000D68FDF /* SearchActionsView.swift */; }; @@ -1750,7 +1759,6 @@ D3A30AF05BD7C46A9A8C1FC1 /* GroupStorageProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = A9537952568A7532147DE548 /* GroupStorageProtocols.swift */; }; D6DA5ECD070E781A74699FF5 /* MainViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1457809A715A3526EBF39205 /* MainViewController.swift */; }; D764CA9732E3D09DE3DD8EDB /* QRCodeGeneratorProtocols.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8B2389EFD3432F86296722BE /* QRCodeGeneratorProtocols.swift */; }; - D839883F9B7A8CD245A85701 /* MyGroupAliasInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1AAE2417131A6C8ED32A44D2 /* MyGroupAliasInteractor.swift */; }; D883A2CBD629A340B27997EF /* SplashViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 553988DBF434D09AB77837DF /* SplashViewController.swift */; }; DAE89B7EFAB308A6B48AF5EC /* AuthInteractor.swift in Sources */ = {isa = PBXBuildFile; fileRef = B15F3B55EC2BF6FB5D7A2FAF /* AuthInteractor.swift */; }; DDDA12EC6C743547BC91276F /* ImagePreviewWireframe.swift in Sources */ = {isa = PBXBuildFile; fileRef = 515FBE9F86586E4AEF89AACD /* ImagePreviewWireframe.swift */; }; @@ -2261,7 +2269,6 @@ 1746BDC1030434814FE63E0A /* DateTimePickerPresenter.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = DateTimePickerPresenter.swift; sourceTree = ""; }; 17B34E74A0246B17348E9597 /* Pods-Nynja.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Nynja.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Nynja/Pods-Nynja.debug.xcconfig"; sourceTree = ""; }; 17D567D263E2C21DB762E40C /* MapWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MapWireframe.swift; sourceTree = ""; }; - 1AAE2417131A6C8ED32A44D2 /* MyGroupAliasInteractor.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MyGroupAliasInteractor.swift; sourceTree = ""; }; 1BA66D21FFC1A74CFD2F63C4 /* ProfileWireframe.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ProfileWireframe.swift; sourceTree = ""; }; 1E65D98C2F04244854E93EAE /* Pods-Nynja-Share.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Nynja-Share.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Nynja-Share/Pods-Nynja-Share.debug.xcconfig"; sourceTree = ""; }; 1F8247671F2779AD00E5B749 /* iCarousel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = iCarousel.h; path = iCarousel/iCarousel.h; sourceTree = ""; }; @@ -2318,6 +2325,8 @@ 260629702056EF2800CB8F65 /* LinksCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinksCell.swift; sourceTree = ""; }; 2606F3BB20BFE20400CF7F15 /* MessageInteractor+Translation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "MessageInteractor+Translation.swift"; sourceTree = ""; }; 260D67D82124616A0072F11F /* LogWriter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogWriter.swift; sourceTree = ""; }; + 260E77D8215D3C5000D18789 /* ComingSoonExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComingSoonExtension.swift; sourceTree = ""; }; + 260E77DA215D3C7700D18789 /* ComingSoonProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComingSoonProtocol.swift; sourceTree = ""; }; 26131E01210399BA00BE94F9 /* TranscribeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranscribeService.swift; sourceTree = ""; }; 26142B1020472ECD004E5FE4 /* MessageLinkTable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageLinkTable.swift; sourceTree = ""; }; 26142B1220473BFD004E5FE4 /* DBMessageLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DBMessageLink.swift; sourceTree = ""; }; @@ -2445,6 +2454,8 @@ 268C341621074AD000F1472A /* AudioLongTranscribeProccessingOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioLongTranscribeProccessingOperation.swift; sourceTree = ""; }; 268C341821074D6C00F1472A /* TranscribeLongOperationResponseData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TranscribeLongOperationResponseData.swift; sourceTree = ""; }; 268C341B21075B4700F1472A /* Cancelable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Cancelable.swift; sourceTree = ""; }; + 2695F1FE21625B800095A0FA /* ChangableProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChangableProgress.swift; sourceTree = ""; }; + 2695F20021625CAB0095A0FA /* DisplayableProgress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplayableProgress.swift; sourceTree = ""; }; 269666171FB57963009E41C1 /* RoomHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = RoomHandler.swift; path = Services/HandleServices/RoomHandler.swift; sourceTree = ""; }; 269848C7200E9D0400590D6F /* StarExtension+BERT.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = "StarExtension+BERT.swift"; path = "Nynja/Services/MQTT/StarExtension+BERT.swift"; sourceTree = SOURCE_ROOT; }; 269848C9200E9F1300590D6F /* StarModels.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = StarModels.swift; path = Services/Models/StarModels.swift; sourceTree = ""; }; @@ -2816,6 +2827,9 @@ 850833DA2037171600587EEF /* FileExtensionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileExtensionView.swift; sourceTree = ""; }; 8509452A206E684300B43C1C /* AddParticipantsContactCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddParticipantsContactCell.swift; sourceTree = ""; }; 8509AC61206A54420089089B /* ResponseResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ResponseResult.swift; sourceTree = ""; }; + 8509FC842158F7D100734D93 /* AppGroupFlagContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppGroupFlagContainer.swift; sourceTree = ""; }; + 8509FC862158F7FC00734D93 /* DirectoryWatcher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DirectoryWatcher.swift; sourceTree = ""; }; + 8509FC88215908B300734D93 /* AppGroupFlagObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppGroupFlagObserver.swift; sourceTree = ""; }; 850A0C6420469AED004F79AD /* UserSettingsRespondable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSettingsRespondable.swift; sourceTree = ""; }; 850A0C662046B65D004F79AD /* WCItemsFactoryDecorator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WCItemsFactoryDecorator.swift; sourceTree = ""; }; 850A2BAF203584B000D68FDF /* SearchActionsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchActionsView.swift; sourceTree = ""; }; @@ -5635,6 +5649,7 @@ 3A768E1C1ECD152300108F7C /* Services */ = { isa = PBXGroup; children = ( + 8509FC832158F7B400734D93 /* Files */, 4BE2C5E42142EB5A00A73DD9 /* NynjaCalls */, 4BE2C5CE2142EAC500A73DD9 /* Audio */, 4B0DBA892137F6F800D79163 /* ChatService */, @@ -5948,14 +5963,6 @@ path = WireFrame; sourceTree = ""; }; - 4074FC8354B32CD19100C02B /* Interactor */ = { - isa = PBXGroup; - children = ( - 1AAE2417131A6C8ED32A44D2 /* MyGroupAliasInteractor.swift */, - ); - path = Interactor; - sourceTree = ""; - }; 4188F5659F19255180FB387D /* MapSearch */ = { isa = PBXGroup; children = ( @@ -7171,6 +7178,16 @@ path = ThemePicker; sourceTree = ""; }; + 8509FC832158F7B400734D93 /* Files */ = { + isa = PBXGroup; + children = ( + 8509FC842158F7D100734D93 /* AppGroupFlagContainer.swift */, + 8509FC88215908B300734D93 /* AppGroupFlagObserver.swift */, + 8509FC862158F7FC00734D93 /* DirectoryWatcher.swift */, + ); + path = Files; + sourceTree = ""; + }; 850C3015204DA84400DB26C2 /* Privacy */ = { isa = PBXGroup; children = ( @@ -9604,6 +9621,8 @@ A45F10CE20B4218D00F45004 /* BaseChatCellModel.swift */, A45F10CF20B4218D00F45004 /* RepliedMessageModel.swift */, 260225E020F3BA92004FC238 /* ConvertionMessageModel.swift */, + 2695F1FE21625B800095A0FA /* ChangableProgress.swift */, + 2695F20021625CAB0095A0FA /* DisplayableProgress.swift */, ); path = Models; sourceTree = ""; @@ -10223,6 +10242,8 @@ E75E9F201FBB34490063690C /* WheelContainer */, 1457809A715A3526EBF39205 /* MainViewController.swift */, E7EE893A1F83CEF5009D37F9 /* MainViewControllerLayout.swift */, + 260E77D8215D3C5000D18789 /* ComingSoonExtension.swift */, + 260E77DA215D3C7700D18789 /* ComingSoonProtocol.swift */, ); path = View; sourceTree = ""; @@ -10974,7 +10995,6 @@ 8606C1D61AA46EB77821B1B0 /* MyGroupAliasProtocols.swift */, 4734E7A9B497BB740A55319A /* View */, B8DCBB4ACE8A650987F2D234 /* Presenter */, - 4074FC8354B32CD19100C02B /* Interactor */, 48CBD0E1B8BFC875AB252183 /* WireFrame */, ); path = MyGroupAlias; @@ -13092,7 +13112,7 @@ "${BUILT_PRODUCTS_DIR}/CryptoSwift/CryptoSwift.framework", "${BUILT_PRODUCTS_DIR}/GRDBCipher/GRDBCipher.framework", "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework", - "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework", + "${BUILT_PRODUCTS_DIR}/GoogleToolboxForMac/GoogleToolboxForMac.framework", "${BUILT_PRODUCTS_DIR}/JTAppleCalendar/JTAppleCalendar.framework", "${BUILT_PRODUCTS_DIR}/MDFTextAccessibility/MDFTextAccessibility.framework", "${BUILT_PRODUCTS_DIR}/MaterialComponents/MaterialComponents.framework", @@ -13117,7 +13137,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/CryptoSwift.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GRDBCipher.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GTMSessionFetcher.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleUtilities.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/GoogleToolboxForMac.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/JTAppleCalendar.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MDFTextAccessibility.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MaterialComponents.framework", @@ -13372,6 +13392,7 @@ 85E3AB3D21218A57005FC49A /* SeparatorView.swift in Sources */, A47785A220D18D4A0053E0D2 /* BaseView.swift in Sources */, A42CE58020692EDB000889CC /* error2.swift in Sources */, + 8509FC8A2159095900734D93 /* AppGroupFlagContainer.swift in Sources */, A42CE58820692EDB000889CC /* Cursor.swift in Sources */, A49E1BD320A9AA0E0074DFD3 /* BaseChatModel.swift in Sources */, A42CE5C820692EDB000889CC /* act_Spec.swift in Sources */, @@ -13384,6 +13405,7 @@ 359EB23B1F9A1BC700147437 /* ReachabilityService.swift in Sources */, A46032502105D357009783DA /* InputsCachePolicy.swift in Sources */, 852003FB20D45B47007C0036 /* BertBinConvertible.swift in Sources */, + 260E77DC215D3CCD00D18789 /* ComingSoonProtocol.swift in Sources */, A42CE5EA20692EDB000889CC /* operation_Spec.swift in Sources */, A42CE61020692EDB000889CC /* process_Spec.swift in Sources */, 26A373571FC6EFC500616C21 /* ProgressHUD.swift in Sources */, @@ -13679,6 +13701,7 @@ A42CE5AF20692EDB000889CC /* TypeSpec.swift in Sources */, FB0B721320907DB5003B9757 /* MessageEditService.swift in Sources */, 859B862C204820DC003272B2 /* ThemePickerPresenter.swift in Sources */, + 8509FC872158F7FC00734D93 /* DirectoryWatcher.swift in Sources */, 2603139B20A0A4BA009AC66D /* LanguageSelectorViewController.swift in Sources */, 2686D3201FC3E39C0079CB75 /* ContentNavigationVC.swift in Sources */, B7EF8EDB210C759400E0E981 /* InterpretationTypeCellModel.swift in Sources */, @@ -14198,6 +14221,7 @@ 26A856242074C50D00C642EA /* ActionsView+ScheduleAction.swift in Sources */, B1B8ED3EDB12866323C9EE74 /* QRCodeGeneratorInteractor.swift in Sources */, 85F0866220D6412300A7762E /* RemoteStorageDestination.swift in Sources */, + 260E77DB215D3C7700D18789 /* ComingSoonProtocol.swift in Sources */, 8580BABF20BD981900239D9D /* MessageInteractor+Schedule.swift in Sources */, A45F111920B4218D00F45004 /* MessageContactView.swift in Sources */, 4B06D3242028B209003B275B /* WCBaseItemsFactory.swift in Sources */, @@ -14230,6 +14254,7 @@ B7121EB8205045F300AABBE6 /* MediaDownloadManager.swift in Sources */, FBCE840E20E525A6003B7558 /* HTTPMethod.swift in Sources */, 2648C4152069B52100863614 /* ChangeNumberStep3Interactor.swift in Sources */, + 2695F20121625CAB0095A0FA /* DisplayableProgress.swift in Sources */, 2648C40C2069B52100863614 /* ChangeNumberStep1ViewController.swift in Sources */, E7EED2321F740A9D005DAE20 /* ActionsItem.swift in Sources */, B723C632204D9E5100884FFD /* DataAndStorageOption.swift in Sources */, @@ -14625,6 +14650,7 @@ 4B8996CD204ED33400DCB183 /* StarDAOProtocol.swift in Sources */, 85D669EC20BD962800FBD803 /* MessageVCLayout.swift in Sources */, 8EDDB08A200529C6000B7EC2 /* GroupStorageCollectionVC.swift in Sources */, + 2695F1FF21625B800095A0FA /* ChangableProgress.swift in Sources */, B74BB00021076AFA0049CD27 /* UIView+Mask.swift in Sources */, A42D51CD206A361400EEB952 /* operation.swift in Sources */, 265F5D25209B6987008ACCC8 /* LocationType.swift in Sources */, @@ -14778,6 +14804,7 @@ 26B32B961FE20BAB00888A0A /* DescExtension+BERT.swift in Sources */, 4B1D7E0B2029D8CD00703228 /* GroupOptionsItemsFactory.swift in Sources */, CCF8AA193F15D4191EC99051 /* SplashProtocols.swift in Sources */, + 8509FC852158F7D100734D93 /* AppGroupFlagContainer.swift in Sources */, 26342CAF20ECD16A00D2196B /* TranscribeShortResponseData.swift in Sources */, E743B5881FB08F0F00F72F92 /* ParticipantsAvatarCell.swift in Sources */, D883A2CBD629A340B27997EF /* SplashViewController.swift in Sources */, @@ -15046,7 +15073,6 @@ 0B79E13E95305A80847AA99F /* MyGroupAliasViewController.swift in Sources */, B745F2E42109B9E500488A91 /* LanguagePickerDelegate.swift in Sources */, 990A25B2C84CE09B4CE64533 /* MyGroupAliasPresenter.swift in Sources */, - D839883F9B7A8CD245A85701 /* MyGroupAliasInteractor.swift in Sources */, 4BE2C5E82142EB5A00A73DD9 /* NynjaRingingService.swift in Sources */, 4B06D3202028A9B1003B275B /* P2pChatItemsFactory.swift in Sources */, A432CF1820B4347D00993AFB /* MaterialTextField.swift in Sources */, @@ -15130,6 +15156,7 @@ A432CF1F20B44C0000993AFB /* MaterialTextContainer.swift in Sources */, 5AD8110B5B87B1AB9F1C5B52 /* CreateGroupPresenter.swift in Sources */, A43B259520AB1DFA00FF8107 /* InputContentProtocol.swift in Sources */, + 8509FC89215908B300734D93 /* AppGroupFlagObserver.swift in Sources */, 2625DBF620EFC52E00E01C05 /* AudioFileConvertOperation.swift in Sources */, 0062D9482062EC4100B915AC /* InviteFriendsInteractor.swift in Sources */, 8562853220D140FC000C9739 /* InputBar+ButtonType.swift in Sources */, @@ -15195,6 +15222,7 @@ 26053123212741C2002E1CF1 /* LogOutputWireFrame.swift in Sources */, A45F112B20B4218D00F45004 /* MessageContainerView.swift in Sources */, A7285B8B56BFCA857AD9BA8A /* AddContactByUsernameWireframe.swift in Sources */, + 260E77D9215D3C5000D18789 /* ComingSoonExtension.swift in Sources */, 2603139A20A0A4B9009AC66D /* LanguageSelectorTableDelegate.swift in Sources */, 853FB06A2049B193000996C5 /* SupportWireFrame.swift in Sources */, 853D0F9A20C0514E008C3684 /* UICollectionViewFlowLayout+ItemSize.swift in Sources */, @@ -15472,6 +15500,7 @@ PROVISIONING_PROFILE = "2a318f9e-d0ab-41dc-968a-e1cb13de4de5"; PROVISIONING_PROFILE_SPECIFIER = ProductionBundle_AppstoreExt; SKIP_INSTALL = YES; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = RELEASE; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.0; @@ -15647,8 +15676,8 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "$(BundleIdentifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = "452734fb-95bb-4d88-8842-c3dcb9f232fb"; - PROVISIONING_PROFILE_SPECIFIER = ProductionBundle_Dev; + PROVISIONING_PROFILE = "f7246486-87f5-46b9-aeed-3ddf15f9a589"; + PROVISIONING_PROFILE_SPECIFIER = ProductionBundle_Appstore; SWIFT_ACTIVE_COMPILATION_CONDITIONS = RELEASE; SWIFT_COMPILATION_MODE = wholemodule; SWIFT_OBJC_BRIDGING_HEADER = "Nynja-Bridging-Header.h"; @@ -15918,7 +15947,7 @@ CLANG_ENABLE_MODULES = YES; CODE_SIGN_ENTITLEMENTS = Nynja/Resources/Nynja.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; - "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; @@ -15930,9 +15959,9 @@ MTL_ENABLE_DEBUG_INFO = NO; PRODUCT_BUNDLE_IDENTIFIER = "$(BundleIdentifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = "3d9e361e-de0d-4189-be64-4bea82318684"; - PROVISIONING_PROFILE_SPECIFIER = NynjaRC_adhoc; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = RELEASE; + PROVISIONING_PROFILE = "dbc772f0-84af-41c2-8843-c273c4b018f9"; + PROVISIONING_PROFILE_SPECIFIER = NynjaRC_dev; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OBJC_BRIDGING_HEADER = "Nynja-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_SWIFT3_OBJC_INFERENCE = Off; @@ -15950,7 +15979,7 @@ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; CODE_SIGN_ENTITLEMENTS = "Nynja-Share/Resources/Nynja-Share.entitlements"; CODE_SIGN_IDENTITY = "iPhone Developer"; - "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; @@ -15962,10 +15991,10 @@ OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" -DSHARE_EXTENSION"; PRODUCT_BUNDLE_IDENTIFIER = "$(ExtensionBundleIdentifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE = "f232c367-7000-49c5-b32c-0efb36c5f2e3"; - PROVISIONING_PROFILE_SPECIFIER = NynjaRC_adhocExt; + PROVISIONING_PROFILE = "3abc34a3-4327-4bb2-9ad6-7d0e723ae1b8"; + PROVISIONING_PROFILE_SPECIFIER = NynjaRC_devExt; SKIP_INSTALL = YES; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = ""; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_VERSION = 4.0; TARGETED_DEVICE_FAMILY = "1,2"; diff --git a/Nynja/AppDelegate.swift b/Nynja/AppDelegate.swift index 5849d18a0d99163c9f0f5238249cf12281b0769c..92bf7435e273decd6785e63897c1794b26cd61de 100644 --- a/Nynja/AppDelegate.swift +++ b/Nynja/AppDelegate.swift @@ -31,6 +31,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD private let storageService = StorageService.sharedInstance private let antiDebuggingService = AntiDebuggingService() + // FIXME: need to be removed from here when share extension won't require new mqtt connection. + private var appGroupObserver: AppGroupFlagObserver? + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { UNUserNotificationCenter.current().delegate = self @@ -38,6 +41,8 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD configureDependencies() + observeGroupAppChanges() + wipeStorage() configureWindow() @@ -115,6 +120,23 @@ private extension AppDelegate { 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/ChatService/ChatService.swift b/Nynja/ChatService/ChatService.swift index d2a84b297d3244e50d06ab778dc0b74b9ddf2a4c..fb15211b45095d4d2e427e9dc1581963ae593f0d 100644 --- a/Nynja/ChatService/ChatService.swift +++ b/Nynja/ChatService/ChatService.swift @@ -6,14 +6,9 @@ // Copyright © 2018 TecSynt Solutions. All rights reserved. // -enum ReaderOwner { - case contact(String) - case room(String) -} - enum ReaderKind: Int { case other = 0 - case own = 1 + case own } final class ChatService { @@ -22,18 +17,6 @@ final class ChatService { private static let storageService = StorageService.sharedInstance // MARK: - Fetch - static func fetchReader(for owner: ReaderOwner, kind: ReaderKind) -> MessageServerId? { - let reader: Int64? - - switch owner { - case .contact(let phoneId): - reader = ContactDAO.fetchReader(for: phoneId, kind: kind) - case .room(let roomId): - reader = RoomDAO.fetchReader(for: roomId, kind: kind) - } - - return reader - } static func fetchChatModel(from message: Message) -> ChatModel? { if let p = message.feed_id as? p2p, let target = p.opponentId, let contact = ContactDAO.findContactBy(phoneId: target) { @@ -53,8 +36,8 @@ final class ChatService { if let phoneId = message.p2pFeed?.opponentId { ContactDAO.updateReader(reader, phoneId: phoneId, kind: kind) - } else if let roomId = message.mucFeed?.name { - RoomDAO.updateReader(reader, roomId: roomId, kind: kind) + } else if let roomId = message.mucFeed?.name, let phoneId = message.from { + RoomDAO.updateReader(reader, roomId: roomId, phoneId: phoneId, kind: kind) } } @@ -167,22 +150,18 @@ final class ChatService { } private static func updateUnreadCounterAfterRemove(for chat: ChatModel, serverId: MessageServerId) { - guard let selfReader = chat.selfReader, - serverId > selfReader, - chat.unreadCount > 0 else { - return + guard let selfReader = chat.selfReader, serverId > selfReader, chat.unreadCount > 0 else { + return } - - chat.unread = chat.unreadCount - 1 + chat.unread = max(0, chat.unreadCount - 1) updateUnreadCounter(for: chat) } private static func updateLastMessageAfterRemove(for chat: ChatModel, message: Message) { - guard let fetchType = self.fetchType(from: message), + guard let fetchType = self.fetchType(from: message), let lastMessage = MessageDAO.fetchLastMessage(of: fetchType) else { return } - ChatService.updateLastMessage(lastMessage, chat: chat, shouldChangeUnread: false) { (lastMessageId) -> Bool in return message.linkedId == lastMessageId } diff --git a/Nynja/DB/Models/DBStarMessage.swift b/Nynja/DB/Models/DBStarMessage.swift index 39b6070f47b0d6a968b93f0334af3335d13afd0e..00e7da110ef0f2c0866f2b921f35f6a4b3ecefaf 100644 --- a/Nynja/DB/Models/DBStarMessage.swift +++ b/Nynja/DB/Models/DBStarMessage.swift @@ -133,7 +133,7 @@ final class DBStarMessage: Record, DBModelProtocol { } private func setup(room: Room) { - let member = room.members?.first(where: { $0.phone_id == self.from }) + let member = room.allMembersWithoutFilter?.first(where: { $0.phone_id == self.from }) setup(room: room, member: member) } diff --git a/Nynja/DB/Tables/DescTable.swift b/Nynja/DB/Tables/DescTable.swift index 79b49186016c44c1b51e098e2055bb76d497ec32..fe4885e34609c8a7f9c9af2a713a4f8d07aa39bc 100644 --- a/Nynja/DB/Tables/DescTable.swift +++ b/Nynja/DB/Tables/DescTable.swift @@ -16,7 +16,7 @@ final class DescTable: Table { static func create(in db: Database) throws { try db.create(self) { t in - t.primaryKey([Column.serverId.title, Column.targetType.title], onConflict: nil) + t.primaryKey([Column.serverId.title, Column.targetId.title, Column.targetType.title], onConflict: nil) t.column(Column.serverId, .text).notNull() t.column(Column.mime, .text) t.column(Column.payload, .text) diff --git a/Nynja/Extensions/Models/Message/Message+System.swift b/Nynja/Extensions/Models/Message/Message+System.swift index 177dc06635e7bda2508daa2985ebb27810c01436..d3a53ea3d284f889fa1c2a383aa7720dd962ebfe 100644 --- a/Nynja/Extensions/Models/Message/Message+System.swift +++ b/Nynja/Extensions/Models/Message/Message+System.swift @@ -73,14 +73,10 @@ extension Message { } private func member(for phoneId: String, in room: Room?) -> Member? { - if let room = room { - if let members = room.members, let index = members.index(where: { $0.phone_id == phoneId }) { - return members[index] - } else if let admins = room.admins, let index = admins.index(where: {$0.phone_id == phoneId } ) { - return admins[index] - } + guard let room = room else { + return nil } - return nil + return room.members?.first { $0.phone_id == phoneId } + ?? room.admins?.first { $0.phone_id == phoneId } } - } diff --git a/Nynja/Files/AppGroupFlagContainer.swift b/Nynja/Files/AppGroupFlagContainer.swift new file mode 100644 index 0000000000000000000000000000000000000000..f7341dca5db7b91ef06749cda3028fb54f09d555 --- /dev/null +++ b/Nynja/Files/AppGroupFlagContainer.swift @@ -0,0 +1,66 @@ +// +// AppGroupFlagContainer.swift +// Nynja +// +// Created by Anton Poltoratskyi on 24.09.2018. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation + +class AppGroupFlagContainer { + + enum Flag: String { + case shareExtension = "share-extension.lock" + + var fileName: String { + return rawValue + } + } + + let fileManager: FileManager + + let containerURL: URL + + var flagsDirectoryURL: URL { + return containerURL.appendingPathComponent("flags") + } + + + // MARK: - Init + + init?(fileManager: FileManager, appGroup: String) { + self.fileManager = fileManager + + guard let containerURL = fileManager.containerURL(forSecurityApplicationGroupIdentifier: appGroup) else { + return nil + } + self.containerURL = containerURL + } + + func prepare() throws { + if !fileManager.fileExists(atPath: flagsDirectoryURL.path) { + try fileManager.createDirectory(at: flagsDirectoryURL, withIntermediateDirectories: true, attributes: nil) + } + } + + + // MARK: - Flags + + func setFlag(_ flag: Flag) throws { + let flagURL = flagsDirectoryURL.appendingPathComponent(flag.fileName) + + // From Apple docs: + // If a file already exists at path, this method overwrites the contents of that file + // if the current process has the appropriate privileges to do so. + fileManager.createFile(atPath: flagURL.path, contents: nil, attributes: nil) + } + + func removeFlagIfExists(_ flag: Flag) throws { + let flagURL = flagsDirectoryURL.appendingPathComponent(flag.fileName) + guard fileManager.fileExists(atPath: flagURL.path) else { + return + } + try fileManager.removeItem(atPath: flagURL.path) + } +} diff --git a/Nynja/Files/AppGroupFlagObserver.swift b/Nynja/Files/AppGroupFlagObserver.swift new file mode 100644 index 0000000000000000000000000000000000000000..d934c1f35e20b1d013d609bb0ad608852d9e2457 --- /dev/null +++ b/Nynja/Files/AppGroupFlagObserver.swift @@ -0,0 +1,40 @@ +// +// AppGroupFlagObserver.swift +// Nynja +// +// Created by Anton Poltoratskyi on 24.09.2018. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation + +final class AppGroupFlagObserver: AppGroupFlagContainer { + + private var directoryWatcher: DirectoryWatcher? + + + // MARK: - Init + + deinit { + stopObserving() + } + + func observe(callback: @escaping ([Flag]) -> Void) throws { + try prepare() + + directoryWatcher = DirectoryWatcher.makeDirectoryWatcher(withPath: flagsDirectoryURL.path) { [weak self] watcher in + guard let `self` = self else { + return + } + do { + let content = try self.fileManager.contentsOfDirectory(atPath: self.flagsDirectoryURL.path) + let flags = content.compactMap { Flag(rawValue: $0) } + callback(flags) + } catch { } + } + } + + func stopObserving() { + directoryWatcher?.stop() + } +} diff --git a/Nynja/Files/DirectoryWatcher.swift b/Nynja/Files/DirectoryWatcher.swift new file mode 100644 index 0000000000000000000000000000000000000000..f6950e4716dac3f18be45c1db7f97104794d26cf --- /dev/null +++ b/Nynja/Files/DirectoryWatcher.swift @@ -0,0 +1,96 @@ +// +// DirectoryWatcher.swift +// Nynja +// +// Created by Anton Poltoratskyi on 24.09.2018. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation + +public class DirectoryWatcher { + + public typealias Callback = (DirectoryWatcher) -> Void + + private var directoryFileDescriptor: Int32 = -1 { + didSet { + if oldValue != -1 { + close(oldValue) + } + } + } + + private var dispatchSource: DispatchSourceFileSystemObject? + + private let queue: DispatchQueue + + + // MARK: - Init + + private init(queue: DispatchQueue) { + self.queue = queue + } + + deinit { + stop() + } + + public static func makeDirectoryWatcher(withPath path: String, + onQueue queue: DispatchQueue = .main, + callback: @escaping Callback) -> DirectoryWatcher? { + let directoryWatcher = DirectoryWatcher(queue: queue) + + if !directoryWatcher.watch(path: path, callback: callback) { + assertionFailure() + return nil + } + + return directoryWatcher + } + + + // MARK: - Watch + + private func watch(path: String, callback: @escaping Callback) -> Bool { + // Open the directory + directoryFileDescriptor = open(path, O_EVTONLY) + if directoryFileDescriptor < 0 { + return false + } + + // Create and configure a DispatchSource to monitor it + let dispatchSource = DispatchSource.makeFileSystemObjectSource(fileDescriptor: directoryFileDescriptor, + eventMask: .write, + queue: queue) + dispatchSource.setEventHandler { [unowned self] in + callback(self) + } + dispatchSource.setCancelHandler { [unowned self] in + self.directoryFileDescriptor = -1 + } + self.dispatchSource = dispatchSource + + // Start monitoring + dispatchSource.resume() + + // Success + return true + } + + public func stop() { + // Leave if not monitoring + guard let dispatchSource = dispatchSource else { + return + } + + // Don't listen to more events + dispatchSource.setEventHandler(handler: nil) + + // Cancel the source (this will also close the directory) + dispatchSource.cancel() + + dispatchSource.setCancelHandler(handler: nil) + + self.dispatchSource = nil + } +} diff --git a/Nynja/Library/UI/AlertManager.swift b/Nynja/Library/UI/AlertManager.swift index cbea0456e7d852de3b2a90442b63ec89a2d7bace..f1debc751da016196ec1c89d7250e2a2fd0f234a 100644 --- a/Nynja/Library/UI/AlertManager.swift +++ b/Nynja/Library/UI/AlertManager.swift @@ -6,12 +6,11 @@ // Copyright © 2017 TecSynt Solutions. All rights reserved. // -import Foundation import UIKit class AlertManager { - static let sharedInstance : AlertManager = { + static let sharedInstance: AlertManager = { let instance = AlertManager() return instance }() @@ -29,6 +28,14 @@ class AlertManager { presentingController?.present(alert, animated: true, completion: nil) } + func showAlert(title: String, dismissInterval: TimeInterval) { + let alert = UIAlertController(title: "\n\(title)\n ", message: "", preferredStyle: .alert) + dispatchAsyncMainAfter(dismissInterval) { + alert.dismiss(animated: true, completion: nil) + } + presentingController?.present(alert, animated: true, completion: nil) + } + func showAlertOk(message: String, completion:(()->Void)? = nil) { showAlertOk(title: "", message: message, completion: completion) } @@ -190,9 +197,6 @@ class AlertManager { func showNativeShare(with activityItems: [Any]) { let activityViewController = UIActivityViewController(activityItems: activityItems, applicationActivities: nil) - activityViewController.completionWithItemsHandler = { (type, flag, objects, error) in - MQTTService.sharedInstance.reconnect() - } presentingController?.present(activityViewController, animated: true, completion: nil) } diff --git a/Nynja/Library/UI/Extensions/GCD.swift b/Nynja/Library/UI/Extensions/GCD.swift index 9aa6d00bdc2851f9a7c5894d55fc2289a2183790..88181367b29774605aee7a9c9ef43f5c92bb99fc 100644 --- a/Nynja/Library/UI/Extensions/GCD.swift +++ b/Nynja/Library/UI/Extensions/GCD.swift @@ -48,11 +48,7 @@ func dispatchGetDefaultQueue() -> DispatchQueue { } func dispatchAsyncMain(_ block: @escaping GCDBlock) { - if Thread.isMainThread == true { - block() - } else { - DispatchQueue.main.async(execute: block) - } + DispatchQueue.main.async(execute: block) } func dispatchAsyncDefault(_ block: @escaping GCDBlock) { diff --git a/Nynja/MessageDAO.swift b/Nynja/MessageDAO.swift index 2d0f4a88152d725fa6503969cfe5f251cf25886c..30fff554d19ac9f2406f31de47aee521f3cde987 100644 --- a/Nynja/MessageDAO.swift +++ b/Nynja/MessageDAO.swift @@ -240,24 +240,27 @@ final class MessageDAO: MessageDAOProtocol { // MARK: - Remove static func removeMessage(using message: Message) -> Bool { - guard let id = message.linkedId, let deletedMessage = fetchMessage(serverId: id) else { + guard let id = message.linkedId else { return false } - let shouldMarkMessageAsDelete = shouldMarkMessageAsDeleted(message) - if shouldMarkMessageAsDelete { - if let currentLocalStatus = deletedMessage.localStatus { - deletedMessage.localStatus = currentLocalStatus.union(.deleted) - } else { - deletedMessage.localStatus = .deleted - } - } - deletedMessage.seenby = message.seenby - do { - try dbManager.perform(action: .save, with: deletedMessage) - } catch { - return false + if let deletedMessage = fetchMessage(serverId: id) { + + if shouldMarkMessageAsDelete { + if let currentLocalStatus = deletedMessage.localStatus { + deletedMessage.localStatus = currentLocalStatus.union(.deleted) + } else { + deletedMessage.localStatus = .deleted + } + } + deletedMessage.seenby = message.seenby + + do { + try dbManager.perform(action: .save, with: deletedMessage) + } catch { + return false + } } return shouldMarkMessageAsDelete diff --git a/Nynja/Modules/CreateGroup/CreateGroupProtocols.swift b/Nynja/Modules/CreateGroup/CreateGroupProtocols.swift index 0ce0d54b621b4ffd4a95f0dedbedd54d1a731f92..17b5b3db235bd66e5c5cb3b6a256ef54dd78e783 100644 --- a/Nynja/Modules/CreateGroup/CreateGroupProtocols.swift +++ b/Nynja/Modules/CreateGroup/CreateGroupProtocols.swift @@ -20,7 +20,7 @@ protocol CreateGroupWireFrameProtocol: class { * Add here your methods for communication PRESENTER -> WIREFRAME */ func changeGroupName(name: String) - func changeAlias(alias: String, nicks: [String]) + func changeAlias(alias: String) func updateParticipants(contacts: [Contact]) func updateAvatar() func showGroupChat(room: Room) diff --git a/Nynja/Modules/CreateGroup/Presenter/CreateGroupPresenter.swift b/Nynja/Modules/CreateGroup/Presenter/CreateGroupPresenter.swift index 3bf466076517df8b66941b93b4d46b2cd87dbf77..4176a20c1e26bb6eda4ba3b3bcbd5d7adc11fe81 100644 --- a/Nynja/Modules/CreateGroup/Presenter/CreateGroupPresenter.swift +++ b/Nynja/Modules/CreateGroup/Presenter/CreateGroupPresenter.swift @@ -68,11 +68,7 @@ class CreateGroupPresenter: BasePresenter, CreateGroupPresenterProtocol, CreateG } func changeAlias() { - if let nicks = room.members?.map({ member -> String in - return member.alias ?? "" - }) { - self.wireFrame.changeAlias(alias: myAlias, nicks: nicks) - } + self.wireFrame.changeAlias(alias: myAlias) } func updateParticipants() { diff --git a/Nynja/Modules/CreateGroup/WireFrame/CreateGroupWireframe.swift b/Nynja/Modules/CreateGroup/WireFrame/CreateGroupWireframe.swift index ed4d927974b2fe88b13806da301264057f9f82c9..8fcddd64150e919e448db1261711911997429635 100644 --- a/Nynja/Modules/CreateGroup/WireFrame/CreateGroupWireframe.swift +++ b/Nynja/Modules/CreateGroup/WireFrame/CreateGroupWireframe.swift @@ -38,8 +38,8 @@ class CreateGroupWireFrame: CreateGroupWireFrameProtocol { self.navigation?.view.layoutIfNeeded() } - func changeAlias(alias: String, nicks: [String]) { - MyGroupAliasWireFrame().presentMyGroupAlias(navigation: navigation!, currentAlias: alias, delegate: external,nicks: nicks, mode: .create) + func changeAlias(alias: String) { + MyGroupAliasWireFrame().presentMyGroupAlias(navigation: navigation!, currentAlias: alias, delegate: external, mode: .create) self.navigation?.view.layoutIfNeeded() } diff --git a/Nynja/Modules/GroupStorage/View/GroupStorageListVC.swift b/Nynja/Modules/GroupStorage/View/GroupStorageListVC.swift index afbdace84d78b9413c051bf787e2c7cfebc172c8..78d8c57762e992d90a725450a9462e689c672b18 100644 --- a/Nynja/Modules/GroupStorage/View/GroupStorageListVC.swift +++ b/Nynja/Modules/GroupStorage/View/GroupStorageListVC.swift @@ -213,7 +213,6 @@ class GroupStorageListVC : UIViewController, GroupStorageCellDelegate, ContextMe delegate?.pathForUrl(url, completion: { (path) in if path != nil { - MQTTService.sharedInstance.disconnect() let localUrl = URL(fileURLWithPath: path!) AlertManager.sharedInstance.showNativeShare(with: [localUrl]) } diff --git a/Nynja/Modules/InviteFriends/WireFrame/InviteFriendsWireframe.swift b/Nynja/Modules/InviteFriends/WireFrame/InviteFriendsWireframe.swift index 9c05f4b5aa965fc1c4ffbec0822578b7a7f5c482..0908aad2cf066727b9bbcced15c6b25da9f95a29 100644 --- a/Nynja/Modules/InviteFriends/WireFrame/InviteFriendsWireframe.swift +++ b/Nynja/Modules/InviteFriends/WireFrame/InviteFriendsWireframe.swift @@ -58,8 +58,7 @@ class InviteFriendsWireFrame: InviteFriendsWireFrameProtocol { } func shareNynja() { - let activityVC = UIActivityViewController(activityItems: ["nynja_share_string".localized], applicationActivities: nil) - viewController?.present(activityVC, animated: true, completion: nil) + AlertManager.sharedInstance.showNativeShare(with: ["nynja_share_string".localized]) } func closeSMSscreen(smsScreen: MFMessageComposeViewController) { diff --git a/Nynja/Modules/Main/View/ComingSoonExtension.swift b/Nynja/Modules/Main/View/ComingSoonExtension.swift new file mode 100644 index 0000000000000000000000000000000000000000..b7282b6d0750151965b0b2fb5f790109decf5818 --- /dev/null +++ b/Nynja/Modules/Main/View/ComingSoonExtension.swift @@ -0,0 +1,15 @@ +// +// ComingSoonExtension.swift +// Nynja +// +// Created by Roman Chopovenko on 9/27/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation + +extension ComingSoonProtocol { + func unavailableFunctionality() { + AlertManager.sharedInstance.showAlert(title: "coming_soon".localized, dismissInterval: 3) + } +} diff --git a/Nynja/Modules/Main/View/ComingSoonProtocol.swift b/Nynja/Modules/Main/View/ComingSoonProtocol.swift new file mode 100644 index 0000000000000000000000000000000000000000..1e6d3270707ad1dd1b7eddaa6cf74fe4ea24c3dc --- /dev/null +++ b/Nynja/Modules/Main/View/ComingSoonProtocol.swift @@ -0,0 +1,13 @@ +// +// ComingSoonProtocol.swift +// Nynja +// +// Created by Roman Chopovenko on 9/27/18. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation + +protocol ComingSoonProtocol { + func unavailableFunctionality() +} diff --git a/Nynja/Modules/Main/View/MainViewController+NavigateProtocol.swift b/Nynja/Modules/Main/View/MainViewController+NavigateProtocol.swift index 80311b819eb7d3941a8ad0722d79e2529c23d9ff..8f7b0e2989a914d5aac3e0b2626de9d445acbb2d 100644 --- a/Nynja/Modules/Main/View/MainViewController+NavigateProtocol.swift +++ b/Nynja/Modules/Main/View/MainViewController+NavigateProtocol.swift @@ -10,10 +10,7 @@ import Foundation import Photos extension MainViewController: NavigateProtocol { - func unavailableFunctionality() { - AlertManager.sharedInstance.showAlertOk(message: "coming_soon".localized) - } - + //MARK: - First lvl func showSearch(indexPath: IndexPath?) { diff --git a/Nynja/Modules/Main/View/NavigateProtocol.swift b/Nynja/Modules/Main/View/NavigateProtocol.swift index 66ccf2481f4fb4552bc00ab28c6c63153beff73c..910ae76f64ada6a9743255c75e67732fc1fc9f36 100644 --- a/Nynja/Modules/Main/View/NavigateProtocol.swift +++ b/Nynja/Modules/Main/View/NavigateProtocol.swift @@ -8,9 +8,7 @@ import Photos -protocol NavigateProtocol: FirstLevelNavigateProtocol, SecondLevelNavigateProtocol, ThirdLevelNavigateProtocol { - func unavailableFunctionality() -} +typealias NavigateProtocol = FirstLevelNavigateProtocol & SecondLevelNavigateProtocol & ThirdLevelNavigateProtocol & ComingSoonProtocol protocol FirstLevelNavigateProtocol: class { func showSearch(indexPath: IndexPath?) diff --git a/Nynja/Modules/Message/Interactor/MessageInteractor+Fetch.swift b/Nynja/Modules/Message/Interactor/MessageInteractor+Fetch.swift index 98159365106aba6d89708e60c2f28de657089fa2..30fb03171d11b07128fab146bac7752818b2ea57 100644 --- a/Nynja/Modules/Message/Interactor/MessageInteractor+Fetch.swift +++ b/Nynja/Modules/Message/Interactor/MessageInteractor+Fetch.swift @@ -141,6 +141,7 @@ extension MessageInteractor { presentationConfiguration.position = adjustChatPosition(unreadCount) presentationConfiguration.reader = chat.otherReader presentationConfiguration.selfReader = unreadCount > 0 ? initialSelfReader : nil + presentationConfiguration.unreadCount = unreadCount presentationConfiguration.shouldShowUnread = !isAfterConnectionAppeared presentationConfiguration.links = fetchLinks() presentationConfiguration.mentions = fetchMentions(for: messages) diff --git a/Nynja/Modules/Message/Interactor/MessageInteractor+Translation.swift b/Nynja/Modules/Message/Interactor/MessageInteractor+Translation.swift index 50269bbcc1f5a46619491a95c3d469181ffae005..717a27c01b564fdae285998cced98a14edf7c1eb 100644 --- a/Nynja/Modules/Message/Interactor/MessageInteractor+Translation.swift +++ b/Nynja/Modules/Message/Interactor/MessageInteractor+Translation.swift @@ -71,7 +71,7 @@ extension MessageInteractor { var attribute: [String: MentionInfo] = [:] let replacement: (MentionInfo) -> String = { mentionInfo in - return "\(MentionInfo.tag)_\(mentionInfo.accountId)_\(mentionInfo.range.lowerBound.encodedOffset)" + return "\(MentionInfo.translationAlias)_\(mentionInfo.accountId)_\(mentionInfo.range.lowerBound.encodedOffset)" } let result = MessagePayloadRenderer.processPlainTextPayload(into: &attribute, @@ -193,7 +193,6 @@ extension MessageInteractor { let index = messages.count - Int(count) - 1 guard messages.indices.contains(index) else { - assertionFailure("Index out of range in: \(#function)") return [] } @@ -218,7 +217,6 @@ extension MessageInteractor { let index = messages.count - Int(count) guard messages.indices.contains(index) else { - assertionFailure("Index out of range in: \(#function)") return [] } @@ -271,7 +269,7 @@ extension MessageInteractor { let mentions = payloadParser.parse(message) var attribute: [String: String] = [:] let replacement: (MentionInfo) -> String = { mentionInfo in - return "\(MentionInfo.tag)_\(mentionInfo.accountId)" + return "\(MentionInfo.translationAlias)_\(mentionInfo.accountId)" } let result = MessagePayloadRenderer.processPlainTextPayload(into: &attribute, diff --git a/Nynja/Modules/Message/Interactor/MessageInteractor.swift b/Nynja/Modules/Message/Interactor/MessageInteractor.swift index 4536f8dfb624b9da35bacea3361dbb63451698e9..9c773e57b80e4d4e72441eb605b55894955e25ee 100644 --- a/Nynja/Modules/Message/Interactor/MessageInteractor.swift +++ b/Nynja/Modules/Message/Interactor/MessageInteractor.swift @@ -261,7 +261,7 @@ final class MessageInteractor: BaseInteractor, MessageInteractorInputProtocol, H } let shouldReadInMySelf = isMyselfChat && message.isCursor - let shouldReadInOther = !message.isOwn + let shouldReadInOther = !isMyselfChat && (!message.isOwn || message.isSystem) if shouldReadInMySelf || shouldReadInOther { readMessage(serverId) diff --git a/Nynja/Modules/Message/Models/Configurations/ChatConfiguration.swift b/Nynja/Modules/Message/Models/Configurations/ChatConfiguration.swift index e800225ec6228e0635c896603bed1520127c81e8..e7da50d2c7b8576e31ada605175f6a144c6779d7 100644 --- a/Nynja/Modules/Message/Models/Configurations/ChatConfiguration.swift +++ b/Nynja/Modules/Message/Models/Configurations/ChatConfiguration.swift @@ -32,13 +32,13 @@ struct ChatConfiguration { var position: PositionType = .none var reader: Int64? var selfReader: Int64? + var unreadCount: Int = 0 var shouldShowUnread: Bool = false mutating func join(_ configuration: ChatConfiguration) { // left messages as it is, but join other data progressModels.mergeUniquingOther(with: configuration.progressModels) - repliedModels.mergeUniquingOther(with: configuration.repliedModels) stars.mergeUniquingOther(with: configuration.stars) links.mergeUniquingOther(with: configuration.links) @@ -51,6 +51,8 @@ struct ChatConfiguration { position = configuration.position reader = configuration.reader + selfReader = configuration.selfReader + unreadCount = configuration.unreadCount shouldShowUnread = configuration.shouldShowUnread } } diff --git a/Nynja/Modules/Message/Models/Mention/Entity/MentionInfo.swift b/Nynja/Modules/Message/Models/Mention/Entity/MentionInfo.swift index d47dc84cf0674ed0b8731d5869242412463e5632..7734b0ddecf63c8a4425f7fd0259ced3bc924cc6 100644 --- a/Nynja/Modules/Message/Models/Mention/Entity/MentionInfo.swift +++ b/Nynja/Modules/Message/Models/Mention/Entity/MentionInfo.swift @@ -11,6 +11,7 @@ import Foundation /// Model for payload tags link [mention memberId=".." accountId=".."]@alias(optional)[\mention] final class MentionInfo: BBCodeEntity { + static let translationAlias = "mntzqrpd" static let tag = "mention" static let attributes = [Attributes.memberId, Attributes.accountId] diff --git a/Nynja/Modules/Message/Presenter/MessagePresenter+MentionUnreadCounter.swift b/Nynja/Modules/Message/Presenter/MessagePresenter+MentionUnreadCounter.swift index 2e1b5d1d110531414090b59f450fa2f8b8b79701..37fd3d4b36474e96b9d5353fd512bf6ec8abd21c 100644 --- a/Nynja/Modules/Message/Presenter/MessagePresenter+MentionUnreadCounter.swift +++ b/Nynja/Modules/Message/Presenter/MessagePresenter+MentionUnreadCounter.swift @@ -12,7 +12,7 @@ extension MessagePresenter { // MARK: - Unread Counter - func prepareMentionedMessages(in room: Room) { + func fetchMentionedMessages(in room: Room) { guard let mentions = room.mentions?.compactMap({ MessageServerId($0) }) else { return } @@ -27,11 +27,13 @@ extension MessagePresenter { defer { lastVisibleMessageId = lastUnreadId } - guard !unreadMentionIds.isEmpty, uniqueUnreadMentionIds.contains(serverMessageId) else { + guard !unreadMentionIds.isEmpty else { return lastUnreadMentionCount } - let index = unreadMentionIds.index { $0 > lastUnreadId } ?? unreadMentionIds.count - lastUnreadMentionCount = unreadMentionIds.count - index + let totalCount = unreadMentionIds.count + let index = unreadMentionIds.index { $0 > lastUnreadId } ?? totalCount + + lastUnreadMentionCount = totalCount - index return lastUnreadMentionCount } @@ -39,13 +41,18 @@ extension MessagePresenter { func showNextMentionedMessage() { guard let nextUnreadMentionedMessageServerId = nextUnreadMentionIdentifier(after: lastVisibleMessageId) else { // Should never happen but handle this case. - resetUnreadMentionCounterData() + resetMentionsCounterView() view.scrollToBottom() return } view.scrollToMessage(serverId: nextUnreadMentionedMessageServerId, at: .center, animated: true) } + func resetMentionsCounterView() { + resetUnreadMentionCounterData() + view.resetUnreadMentionCounter() + } + func updateMentionsCounter(in room: Room) { guard room.hasMentions else { return @@ -58,14 +65,6 @@ extension MessagePresenter { // MARK: - Utils - func resetMentionsCounterView() { - guard lastUnreadMentionCount > 0 else { - return - } - resetUnreadMentionCounterData() - view.resetUnreadMentionCounter() - } - private func resetUnreadMentionCounterData() { uniqueUnreadMentionIds.removeAll() unreadMentionIds.removeAll() @@ -88,7 +87,7 @@ extension MessagePresenter { return } var unique: Set = [] - for case let mention in mentions { + for mention in mentions { guard let id = MessageServerId(mention) else { continue } diff --git a/Nynja/Modules/Message/Presenter/MessagePresenter.swift b/Nynja/Modules/Message/Presenter/MessagePresenter.swift index 49d438c1771abb56eaa12b298cc8fd8f45a822cf..a567e58e07ff4e1281905aeb72671519b7ceec3c 100644 --- a/Nynja/Modules/Message/Presenter/MessagePresenter.swift +++ b/Nynja/Modules/Message/Presenter/MessagePresenter.swift @@ -71,7 +71,7 @@ class MessagePresenter: BasePresenter, MessagePresenterProtocol, MessageInteract super.screenLoaded() interactor.askForInternetStatus() - interactor.room.map { prepareMentionedMessages(in: $0) } + interactor.room.map { fetchMentionedMessages(in: $0) } } @@ -106,7 +106,7 @@ class MessagePresenter: BasePresenter, MessagePresenterProtocol, MessageInteract if wasViewDisappeared { let unreadCount = Int(interactor.chat.unreadCount) if unreadCount != 0 { - view.updateUnreadTitle(interactor.chat.selfReader) + view.updateUnreadTitle(interactor.chat.selfReader, unreadCount: unreadCount) } } } @@ -600,7 +600,11 @@ class MessagePresenter: BasePresenter, MessagePresenterProtocol, MessageInteract } } - if configuration.shouldShowUnread, let index = cells.unreadIndex(selfReader: configuration.selfReader) { + if configuration.shouldShowUnread, + let index = cells.unreadIndex( + selfReader: configuration.selfReader, + unreadCount: configuration.unreadCount) { + cells.insert(.makeUnreadModel(), at: index) unreadIndex = index } else { @@ -693,8 +697,8 @@ class MessagePresenter: BasePresenter, MessagePresenterProtocol, MessageInteract position = .unread(index) } - let isUnreadShown: Bool = configuration.shouldShowUnread && unreadIndex != nil - + let isUnreadShown = configuration.shouldShowUnread && unreadIndex != nil + return DisplayChatConfiguration(cells: cells, position: position, isUnreadShown: isUnreadShown) } diff --git a/Nynja/Modules/Message/Protocols/MessageProtocols.swift b/Nynja/Modules/Message/Protocols/MessageProtocols.swift index e9701e7f09a07de830f1e17bd74334062bc26f6e..9a5dd81bf9b164e17a372889221d16c083d0b989 100644 --- a/Nynja/Modules/Message/Protocols/MessageProtocols.swift +++ b/Nynja/Modules/Message/Protocols/MessageProtocols.swift @@ -275,7 +275,7 @@ protocol MessageViewProtocol: class { func updateMessage(_ model: BaseChatCellModel) func updateStar(starID: String?, messageId: String) - func updateUnreadTitle(_ selfRead: Int64?) + func updateUnreadTitle(_ selfRead: Int64?, unreadCount: Int) func updateUnreadMentions() func resetUnreadMentionCounter() diff --git a/Nynja/Modules/Message/View/MessageVC.swift b/Nynja/Modules/Message/View/MessageVC.swift index c8cc69c0bcc217f32c33465e6ab7e99edb326100..9b14fd4f7a3abeca26b57b2e5c7986f190525f7f 100644 --- a/Nynja/Modules/Message/View/MessageVC.swift +++ b/Nynja/Modules/Message/View/MessageVC.swift @@ -26,8 +26,6 @@ final class MessageVC: BaseVC, MessageViewProtocol, ReplyPreviewDelegate, BackSw } } - var progressDictionary = [ProgressIdentifier: [(ProgressModel)->Void]]() - var loadingStatus = false var messageDS: MessageCollectionViewDataSource! @@ -669,6 +667,8 @@ final class MessageVC: BaseVC, MessageViewProtocol, ReplyPreviewDelegate, BackSw // MARK: - Mentions + + private(set) var isMentionsVisible = false func setupUnreadMentions(after index: Int) { var serverId = messageDS.cellModel(at: index).serverID @@ -680,14 +680,17 @@ final class MessageVC: BaseVC, MessageViewProtocol, ReplyPreviewDelegate, BackSw if let id = serverId { let count = presenter.mentionsCount(after: id) mentionCounterView.count = count - toggleMentionsCounter(count > 0) + + isMentionsVisible = count > 0 + toggleMentionsCounter(isMentionsVisible) } else { + isMentionsVisible = false presenter.resetMentionsCounterView() } } - func showNexMentionedMessage() { + private func showNexMentionedMessage() { presenter.showNextMentionedMessage() } @@ -830,8 +833,6 @@ final class MessageVC: BaseVC, MessageViewProtocol, ReplyPreviewDelegate, BackSw adjustPosition(with: configuration, isLastMessageVisible: isLastMessageVisible) adjustButtonState(configuration) - - updateUnreadMentions() } func updateNewData(_ history: [BaseChatCellModel]) { @@ -853,8 +854,6 @@ final class MessageVC: BaseVC, MessageViewProtocol, ReplyPreviewDelegate, BackSw collectionView.reloadData() loadingStatus = false - - updateUnreadMentions() } private func adjustPosition(with configuration: DisplayChatConfiguration, isLastMessageVisible: Bool) { @@ -875,8 +874,9 @@ final class MessageVC: BaseVC, MessageViewProtocol, ReplyPreviewDelegate, BackSw case .message(let localId): scrollToMessage(with: localId) case .unread(let index): - let index = messageDS.presentationIndex(from: index) + 1 + let index = messageDS.presentationIndex(from: index) scrollToUnreadMessage(with: index) + updateUnreadMentions() case .checkpoint(let checkpoint): guard case .none = lastPosition else { return @@ -908,7 +908,6 @@ final class MessageVC: BaseVC, MessageViewProtocol, ReplyPreviewDelegate, BackSw } func showNativeShare(for fileUrl: URL) { - MQTTService.sharedInstance.disconnect() AlertManager.sharedInstance.showNativeShare(with: [fileUrl]) } @@ -944,15 +943,11 @@ final class MessageVC: BaseVC, MessageViewProtocol, ReplyPreviewDelegate, BackSw } func updateProgress(progressModel: ProgressModel?) { - DispatchQueue.main.async { - guard let url = progressModel?.url.absoluteString, let model = progressModel else { - return - } - self.progressDictionary.keys.forEach { - guard $0.url == url else { return } - self.progressDictionary[$0]?.forEach { block in block(model) } - } + guard let messageDS = messageDS, + let progressModel = progressModel else { + return } + messageDS.update(progress: progressModel) } func updateTranslationProgress(progressModel: ConvertionProgressModel?) { @@ -1126,10 +1121,11 @@ final class MessageVC: BaseVC, MessageViewProtocol, ReplyPreviewDelegate, BackSw collectionView.reloadData() } - func updateUnreadTitle(_ selfReader: Int64?) { - guard let index = messageDS.unreadIndex(selfReader: selfReader) else { + func updateUnreadTitle(_ selfReader: Int64?, unreadCount: Int) { + guard let index = messageDS.unreadIndex(selfReader: selfReader, unreadCount: unreadCount) else { return } + let unreadIndex = messageDS.unreadCellIndex if let unreadIndex = unreadIndex { diff --git a/Nynja/Modules/Message/View/Views/CollectionView/MessageCollectionViewDataSource.swift b/Nynja/Modules/Message/View/Views/CollectionView/MessageCollectionViewDataSource.swift index 024b4252a0842d964835fb2a348cdc4508f7fdf6..e89ddd6d72d833f55f01df46ab7a144cdc3c7c09 100644 --- a/Nynja/Modules/Message/View/Views/CollectionView/MessageCollectionViewDataSource.swift +++ b/Nynja/Modules/Message/View/Views/CollectionView/MessageCollectionViewDataSource.swift @@ -59,14 +59,23 @@ final class MessageCollectionViewDataSource: NSObject { self.cells = cells } + func update(progress: ProgressModel) { + cells.forEach { + guard $0.progressModel?.url == progress.url else { + return + } + $0.progressModel = progress + } + } + func forEach(block: (BaseChatCellModel) -> Void) { for cell in cells { block(cell) } } - func unreadIndex(selfReader: MessageServerId?) -> Int? { - guard let index = cells.unreadIndex(selfReader: selfReader) else { + func unreadIndex(selfReader: MessageServerId?, unreadCount: Int) -> Int? { + guard let index = cells.unreadIndex(selfReader: selfReader, unreadCount: unreadCount) else { return nil } return presentationIndex(from: index) diff --git a/Nynja/Modules/Message/View/Views/CollectionView/MessageCollectionViewDelegate.swift b/Nynja/Modules/Message/View/Views/CollectionView/MessageCollectionViewDelegate.swift index 13da59484f3b2819162aa7d74d5d43d7b2f5e120..79369dc3ac8877e5740b98c456975f3a3c9cc101 100644 --- a/Nynja/Modules/Message/View/Views/CollectionView/MessageCollectionViewDelegate.swift +++ b/Nynja/Modules/Message/View/Views/CollectionView/MessageCollectionViewDelegate.swift @@ -25,13 +25,6 @@ final class MessageCollectionViewDelegate: NSObject, UICollectionViewDelegateFlo setupMentions(cell: cell, indexPath: indexPath) } - func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { - guard let cell = cell as? BaseChatCell, let url = cell.model?.progressModel?.url.absoluteString else { - return - } - view.progressDictionary.removeValue(forKey: .init(id: cell.id, url: url)) - } - func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: view.view.bounds.width, height: heightForItem(at: indexPath)) } @@ -97,6 +90,10 @@ final class MessageCollectionViewDelegate: NSObject, UICollectionViewDelegateFlo // MARK: - Private private func setupMentions(cell: UICollectionViewCell, indexPath: IndexPath) { + guard view.isMentionsVisible else { + lastVisibleIndex = nil + return + } func setup() { lastVisibleIndex = indexPath.item view.setupUnreadMentions(after: indexPath.item) @@ -112,19 +109,10 @@ final class MessageCollectionViewDelegate: NSObject, UICollectionViewDelegateFlo } private func setupProgress(cell: UICollectionViewCell) { - guard let cell = cell as? BaseChatCell, let url = cell.model?.progressModel?.url.absoluteString else { + guard let cell = cell as? BaseChatCell else { return } - let block: (ProgressModel) -> Void = { model in - cell.updateProgressClosure(model: model) - } - - let identifier = ProgressIdentifier(id: cell.id, url: url) - if view.progressDictionary[identifier] == nil { - view.progressDictionary[identifier] = [block] - } else { - view.progressDictionary[identifier]?.append(block) - } + cell.model?.subscribeToProgressChanges(with: cell) } private func loadData() { diff --git a/Nynja/Modules/Message/View/Views/TableView/Cells/ChatCells/BaseChatCell/BaseChatCell.swift b/Nynja/Modules/Message/View/Views/TableView/Cells/ChatCells/BaseChatCell/BaseChatCell.swift index fbbe8e6c7944522c0c4e3c8df8e153d79c9a35d8..40bf3e286538f5aa8df667aab531d4efb27a6d7d 100644 --- a/Nynja/Modules/Message/View/Views/TableView/Cells/ChatCells/BaseChatCell/BaseChatCell.swift +++ b/Nynja/Modules/Message/View/Views/TableView/Cells/ChatCells/BaseChatCell/BaseChatCell.swift @@ -239,6 +239,7 @@ class BaseChatCell: UICollectionViewCell, MessageBaseImageViewDataSource, Messag override func prepareForReuse() { super.prepareForReuse() model?.resetHandlers() + model?.unsubscribeFormProgressChanges() } @@ -550,11 +551,6 @@ class BaseChatCell: UICollectionViewCell, MessageBaseImageViewDataSource, Messag return textSize } - - func updateProgressClosure(model: ProgressModel) { - downloadProgressModel = model - setupProgress() - } } protocol BaseChatCellImagePreviewTransitionAnimatable { @@ -568,6 +564,14 @@ extension BaseChatCell: BaseChatCellImagePreviewTransitionAnimatable { } //MARK: - Processing handler + extension BaseChatCell: DisplayableProgress { + func updateProgress() { + DispatchQueue.main.async { [weak self] in + self?.setupProgress() + } + } + } + private extension BaseChatCell { var shouldShowNetworkProcessing: Bool { @@ -582,12 +586,7 @@ private extension BaseChatCell { } var downloadProgressModel: ProgressModel? { - set { - model?.progressModel = newValue - } - get { - return model?.progressModel - } + return model?.progressModel } var conversionProgressModel: ConvertionProgressModel? { diff --git a/Nynja/Modules/Message/View/Views/TableView/Cells/Models/BaseChatCellModel.swift b/Nynja/Modules/Message/View/Views/TableView/Cells/Models/BaseChatCellModel.swift index cdc3c66d2e0a1b39bddb3b9e1c34a75c5b6e27f4..72c7fa4dada7ae100572e450f6783871b6a17b6f 100644 --- a/Nynja/Modules/Message/View/Views/TableView/Cells/Models/BaseChatCellModel.swift +++ b/Nynja/Modules/Message/View/Views/TableView/Cells/Models/BaseChatCellModel.swift @@ -102,7 +102,7 @@ enum InfoType { case channel } -final class BaseChatCellModel: AudioPlayable { +final class BaseChatCellModel: AudioPlayable, ChangebleProgress { var messageType: MessageType = .regular @@ -159,6 +159,7 @@ final class BaseChatCellModel: AudioPlayable { let str: String = self.getTransferProgressString(with: model.fileSize, progress: model.progress) self.fileTransferProgressText = str } + self.notifyAboutProgressChanges() } } var convertProgressModel: ConvertionProgressModel? @@ -204,6 +205,8 @@ final class BaseChatCellModel: AudioPlayable { var fileURLHandler: ((URL?) -> Void)? var audioStateHandler: (() -> Void)? + + var changesHandler: ((ProgressModel) -> Void)? } @@ -264,8 +267,8 @@ extension BaseChatCellModel { extension Array where Element == BaseChatCellModel { - func unreadIndex(selfReader: MessageServerId?) -> Int? { - guard let lastSeenIndex = self.lastSeenIndex(selfReader: selfReader) else { + func unreadIndex(selfReader: MessageServerId?, unreadCount: Int) -> Int? { + guard let lastSeenIndex = self.lastSeenIndex(selfReader: selfReader, unreadCount: unreadCount) else { return nil } @@ -282,17 +285,25 @@ extension Array where Element == BaseChatCellModel { return nil } - private func lastSeenIndex(selfReader: MessageServerId?) -> Int? { + private func lastSeenIndex(selfReader: MessageServerId?, unreadCount: Int) -> Int? { guard let selfReader = selfReader else { return nil } - return self.lastIndex { (cell) -> Bool in + let possibleIndex = self.lastIndex { (cell) -> Bool in guard let serverId = cell.serverID else { return false } return serverId <= selfReader } + + if let index = possibleIndex { + return index + } else if unreadCount <= self.count(where: { $0.modelType.isMessage }) { + return 0 + } + + return nil } } diff --git a/Nynja/Modules/Message/View/Views/TableView/Cells/Models/ChangableProgress.swift b/Nynja/Modules/Message/View/Views/TableView/Cells/Models/ChangableProgress.swift new file mode 100644 index 0000000000000000000000000000000000000000..77468255b0381f1e23424d8f10bde15030d20e77 --- /dev/null +++ b/Nynja/Modules/Message/View/Views/TableView/Cells/Models/ChangableProgress.swift @@ -0,0 +1,41 @@ +// +// ChangableProgress.swift +// Nynja +// +// Created by Andrey Reznik on 01.10.2018. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation + +protocol ChangebleProgress: class { + + var progressModel: ProgressModel? { get set } + var changesHandler: ((ProgressModel) -> Void)? { get set } + + func notifyAboutProgressChanges() + func subscribeToProgressChanges(with object: DisplayableProgress) + func unsubscribeFormProgressChanges() +} + + +extension ChangebleProgress { + + func notifyAboutProgressChanges() { + guard let progressModel = progressModel else { + return + } + changesHandler?(progressModel) + } + + func subscribeToProgressChanges(with object: DisplayableProgress) { + changesHandler = { [weak object] _ in + object?.updateProgress() + } + } + + func unsubscribeFormProgressChanges() { + changesHandler = nil + } + +} diff --git a/Nynja/Modules/Message/View/Views/TableView/Cells/Models/DisplayableProgress.swift b/Nynja/Modules/Message/View/Views/TableView/Cells/Models/DisplayableProgress.swift new file mode 100644 index 0000000000000000000000000000000000000000..13dc463d94e14a1d0f35f233e6c2cff1b884cad3 --- /dev/null +++ b/Nynja/Modules/Message/View/Views/TableView/Cells/Models/DisplayableProgress.swift @@ -0,0 +1,13 @@ +// +// DisplayableProgress.swift +// Nynja +// +// Created by Andrey Reznik on 01.10.2018. +// Copyright © 2018 TecSynt Solutions. All rights reserved. +// + +import Foundation + +protocol DisplayableProgress: class { + func updateProgress() +} diff --git a/Nynja/Modules/MyGroupAlias/Interactor/MyGroupAliasInteractor.swift b/Nynja/Modules/MyGroupAlias/Interactor/MyGroupAliasInteractor.swift deleted file mode 100644 index a6f49f1d9d75fb459f567b9d5ad72f4df1518ce5..0000000000000000000000000000000000000000 --- a/Nynja/Modules/MyGroupAlias/Interactor/MyGroupAliasInteractor.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// MyGroupAliasMyGroupAliasInteractor.swift -// Nynja -// -// Created by Sergey Lomov on 08/11/2017. -// Copyright © 2017 TecSynt Solutions. All rights reserved. -// - -class MyGroupAliasInteractor: BaseInteractor, MyGroupAliasInteractorInputProtocol { - - weak var presenter: MyGroupAliasInteractorOutputProtocol! - - var currentAlias: String! - var nicks: [String]! - - - //MARK: - BaseInteractor - - override func loadData() { - super.loadData() - presenter?.update(currentAlias) - } - -} diff --git a/Nynja/Modules/MyGroupAlias/MyGroupAliasProtocols.swift b/Nynja/Modules/MyGroupAlias/MyGroupAliasProtocols.swift index 524312af949000cd816637039ef9372c62a82925..a0499a7a5d805e225501299be0778f1c8025c7fb 100644 --- a/Nynja/Modules/MyGroupAlias/MyGroupAliasProtocols.swift +++ b/Nynja/Modules/MyGroupAlias/MyGroupAliasProtocols.swift @@ -14,7 +14,7 @@ protocol MyGroupAliasEditorDelegate: class { protocol MyGroupAliasWireFrameProtocol: class { - func presentMyGroupAlias(navigation: UINavigationController, currentAlias: String, delegate: MyGroupAliasEditorDelegate?, nicks: [String], mode: GroupMode) + func presentMyGroupAlias(navigation: UINavigationController, currentAlias: String, delegate: MyGroupAliasEditorDelegate?, mode: GroupMode) /** * Add here your methods for communication PRESENTER -> WIREFRAME @@ -34,39 +34,14 @@ protocol MyGroupAliasViewProtocol: class { func setup(alias: String) } -protocol MyGroupAliasPresenterProtocol: AnyObject, BasePresenterProtocol { +protocol MyGroupAliasPresenterProtocol: BasePresenterProtocol { var view: MyGroupAliasViewProtocol! { get set } - var interactor: MyGroupAliasInteractorInputProtocol! { get set } var wireFrame: MyGroupAliasWireFrameProtocol! { get set } - var mode: GroupMode { get set } - /** * Add here your methods for communication VIEW -> PRESENTER */ - func saveAlias(_ alias:String) -} - -protocol MyGroupAliasInteractorOutputProtocol: class { - - /** - * Add here your methods for communication INTERACTOR -> PRESENTER - */ - - func update(_ alias: String) - -} - -protocol MyGroupAliasInteractorInputProtocol: BaseInteractorProtocol { - - var presenter: MyGroupAliasInteractorOutputProtocol! { get set } - - var currentAlias: String! { get set } - var nicks: [String]! { get set } - - /** - * Add here your methods for communication PRESENTER -> INTERACTOR - */ + func save(alias: String) } diff --git a/Nynja/Modules/MyGroupAlias/Presenter/MyGroupAliasPresenter.swift b/Nynja/Modules/MyGroupAlias/Presenter/MyGroupAliasPresenter.swift index f932ec71bcad7eb9c4ef92c9b82b99858cac3dd5..b07fd62837e9c8859358def71968d50d4a168c0a 100644 --- a/Nynja/Modules/MyGroupAlias/Presenter/MyGroupAliasPresenter.swift +++ b/Nynja/Modules/MyGroupAlias/Presenter/MyGroupAliasPresenter.swift @@ -6,18 +6,41 @@ // Copyright © 2017 TecSynt Solutions. All rights reserved. // -class MyGroupAliasPresenter: BasePresenter, MyGroupAliasPresenterProtocol, MyGroupAliasInteractorOutputProtocol { +class MyGroupAliasPresenter: BasePresenter, MyGroupAliasPresenterProtocol, InitializeInjectable { + + weak var view: MyGroupAliasViewProtocol! + var wireFrame: MyGroupAliasWireFrameProtocol! weak var delegate: MyGroupAliasEditorDelegate? - var currentAlias: String! { - get { - return interactor.currentAlias - } + let currentAlias: String + let mode: GroupMode + + + // MARK: - InitializeInjectable + + required init(dependencies: Dependencies) { + view = dependencies.view + wireFrame = dependencies.wireFrame + + delegate = dependencies.delegate + + currentAlias = dependencies.currentAlias + mode = dependencies.mode + } + + struct Dependencies { + let view: MyGroupAliasViewProtocol + let wireFrame: MyGroupAliasWireFrameProtocol + + let delegate: MyGroupAliasEditorDelegate? + + let currentAlias: String + let mode: GroupMode } - //MARK: - BasePresenter + // MARK: - BasePresenter override var itemsFactory: WCItemsFactory? { if mode == .create { @@ -27,34 +50,18 @@ class MyGroupAliasPresenter: BasePresenter, MyGroupAliasPresenterProtocol, MyGro } } - - //MARK: - MyGroupAliasPresenterProtocol - - weak var view: MyGroupAliasViewProtocol! - var interactor: MyGroupAliasInteractorInputProtocol! { - didSet { - _interactor = interactor - } - } - var wireFrame: MyGroupAliasWireFrameProtocol! - - var mode: GroupMode = .create - - func saveAlias(_ alias: String) { - if currentAlias == alias { - aliasAvailable(alias) - } + override func loadData() { + super.loadData() + view.setup(alias: currentAlias) } - //MARK: - MyGroupAliasInteractorOutputProtocol + // MARK: - MyGroupAliasPresenterProtocol - func update(_ alias: String) { - view.setup(alias: alias) - } - - func aliasAvailable(_ alias: String) { - delegate?.myGroupAliasWasChanged(newValue: alias) + func save(alias: String) { + if currentAlias != alias { + delegate?.myGroupAliasWasChanged(newValue: alias) + } wireFrame.hide() } } diff --git a/Nynja/Modules/MyGroupAlias/View/MyGroupAliasViewController.swift b/Nynja/Modules/MyGroupAlias/View/MyGroupAliasViewController.swift index db258fcc77354b1130bb49229e61370ed8ded24a..d9a695031d20adf602144e2137e04eedc28e5778 100644 --- a/Nynja/Modules/MyGroupAlias/View/MyGroupAliasViewController.swift +++ b/Nynja/Modules/MyGroupAlias/View/MyGroupAliasViewController.swift @@ -16,76 +16,15 @@ class MyGroupAliasViewController: BaseVC, MyGroupAliasViewProtocol { } } - // MARK: Views - private lazy var aliasField: EditField = { - let height = Constraints.aliasField.height.adjustedByHeight - let inputHeight = Constraints.aliasField.inputHeight.adjustedByHeight - - let width = Constraints.aliasField.width.adjustedByWidth - - let labelHeight = Constraints.aliasField.labelHeight.adjustedByHeight - - let cf = createEditField(with: CGRect(x: 0, y: 0, width: width, height: height), labelHeight: labelHeight, inputHeight: inputHeight) - let horizontalInset = Constraints.aliasField.horizontalInset.adjustedByWidth - self.view.addSubview(cf) - cf.snp.makeConstraints({ (make) in - make.height.equalTo(height) - make.left.equalTo(horizontalInset) - make.right.equalTo(-horizontalInset) - make.top.equalTo(navigationView.snp.bottom).offset(Constraints.aliasField.topInset.adjustedByHeight) - }) - return cf - }() - private lazy var cancelButton: UIButton = { - let button = UIButton(type: .system) - - let width = Constraints.cancelButton.width.adjustedByWidth - let labelHeight = width * Constraints.cancelButton.labelHeightProportion - - // Set font with adjusted size - let fontName = Constants.fonts.medium - let fontSize = "A".getFontSize(fontName: fontName, width: width, height: labelHeight) - button.titleLabel?.font = UIFont(name: fontName, size: fontSize) - button.setTitle(Strings.cancelGroupAlias.localized, for: .normal) - - // Set title and its color - button.setTitleColor(Constants.colors.lightBlue.getColor(), for: .normal) - - self.view.addSubview(button) - button.snp.makeConstraints({ (make) in - make.top.greaterThanOrEqualTo(aliasField.snp.bottom).offset(Constraints.cancelButton.topInset.adjustedByHeight) - make.left.right.equalTo(aliasField) - make.height.equalTo(Constraints.cancelButton.height.adjustedByHeight) - }) - - return button - }() + // MARK: - Subviews - private lazy var saveButton: NynjaButton = { - let height = Constraints.saveButton.height.adjustedByHeight - let width = Constraints.saveButton.width.adjustedByWidth - let labelHeight = width * Constraints.saveButton.labelHeightProportion - - let frame = CGRect(x: 0, y: 0, width: width, height: height) - - let button = NynjaButton(frame: frame, fontName: Constants.fonts.medium, labelHeight: labelHeight) - - // Set title and its color - button.setTitle(Strings.saveAlias.localized.uppercased(), for: .normal) - - self.view.addSubview(button) - button.snp.makeConstraints({ (make) in - make.height.equalTo(height) - make.top.equalTo(cancelButton.snp.bottom).offset(Constraints.saveButton.topInset.adjustedByHeight) - make.left.right.equalTo(cancelButton) - }) - - return button - }() + private lazy var aliasField: EditField = makeAliasField() + private lazy var cancelButton: UIButton = makeCancelButton() + private lazy var saveButton: NynjaButton = makeSaveButton() - //MARK: - View Lifecycle + // MARK: - View Lifecycle override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) @@ -93,7 +32,8 @@ class MyGroupAliasViewController: BaseVC, MyGroupAliasViewProtocol { } - //MARK: - BaseVC + // MARK: - BaseVC + override func initialize() { super.initialize() @@ -107,14 +47,20 @@ class MyGroupAliasViewController: BaseVC, MyGroupAliasViewProtocol { setupTestingKeysInSubviews() } - //MARK: - Setup + + // MARK: - Setup func setup(alias: String) { aliasField.input.text = alias } +} + +// MARK: - Private + +private extension MyGroupAliasViewController { - //MARK: - Actions + // MARK: - Actions @objc func cancelButtonTapper() { self.navigationController?.popViewController(animated: false) @@ -124,14 +70,14 @@ class MyGroupAliasViewController: BaseVC, MyGroupAliasViewProtocol { aliasField.input.text = aliasField.input.text?.trimmingCharacters(in: .whitespacesAndNewlines) if valid() { self.view.endEditing(true) - self.presenter.saveAlias(aliasField.input.text ?? "") + self.presenter.save(alias: aliasField.input.text ?? "") } } - //MARK: - Private + // MARK: - Helper - private func createEditField(with frame: CGRect, labelHeight: CGFloat, inputHeight: CGFloat) -> EditField { + func createEditField(with frame: CGRect, labelHeight: CGFloat, inputHeight: CGFloat) -> EditField { let cf = EditField(frame: frame) cf.leftLabel.textColor = Constants.colors.darkGray.getColor() @@ -146,7 +92,7 @@ class MyGroupAliasViewController: BaseVC, MyGroupAliasViewProtocol { return cf } - private func valid() -> Bool { + func valid() -> Bool { if let alias = aliasField.input.text { if alias == "" { AlertManager.sharedInstance.showAlertOk(message: Strings.aliasEmptyMessage.localized) @@ -165,10 +111,86 @@ class MyGroupAliasViewController: BaseVC, MyGroupAliasViewProtocol { } } + +// MARK: - Subviews maker + +private extension MyGroupAliasViewController { + + func makeAliasField() -> EditField { + let height = Constraints.aliasField.height.adjustedByHeight + let inputHeight = Constraints.aliasField.inputHeight.adjustedByHeight + + let width = Constraints.aliasField.width.adjustedByWidth + + let labelHeight = Constraints.aliasField.labelHeight.adjustedByHeight + + let cf = createEditField(with: CGRect(x: 0, y: 0, width: width, height: height), labelHeight: labelHeight, inputHeight: inputHeight) + let horizontalInset = Constraints.aliasField.horizontalInset.adjustedByWidth + self.view.addSubview(cf) + cf.snp.makeConstraints({ (make) in + make.height.equalTo(height) + make.left.equalTo(horizontalInset) + make.right.equalTo(-horizontalInset) + make.top.equalTo(navigationView.snp.bottom).offset(Constraints.aliasField.topInset.adjustedByHeight) + }) + return cf + } + + func makeCancelButton() -> UIButton { + let button = UIButton(type: .system) + + let width = Constraints.cancelButton.width.adjustedByWidth + let labelHeight = width * Constraints.cancelButton.labelHeightProportion + + // Set font with adjusted size + let fontName = Constants.fonts.medium + let fontSize = "A".getFontSize(fontName: fontName, width: width, height: labelHeight) + button.titleLabel?.font = UIFont(name: fontName, size: fontSize) + button.setTitle(Strings.cancelGroupAlias.localized, for: .normal) + + // Set title and its color + button.setTitleColor(Constants.colors.lightBlue.getColor(), for: .normal) + + self.view.addSubview(button) + button.snp.makeConstraints({ (make) in + make.top.greaterThanOrEqualTo(aliasField.snp.bottom).offset(Constraints.cancelButton.topInset.adjustedByHeight) + make.left.right.equalTo(aliasField) + make.height.equalTo(Constraints.cancelButton.height.adjustedByHeight) + }) + + return button + } + + func makeSaveButton() -> NynjaButton { + let height = Constraints.saveButton.height.adjustedByHeight + let width = Constraints.saveButton.width.adjustedByWidth + let labelHeight = width * Constraints.saveButton.labelHeightProportion + + let frame = CGRect(x: 0, y: 0, width: width, height: height) + + let button = NynjaButton(frame: frame, fontName: Constants.fonts.medium, labelHeight: labelHeight) + + // Set title and its color + button.setTitle(Strings.saveAlias.localized.uppercased(), for: .normal) + + self.view.addSubview(button) + button.snp.makeConstraints({ (make) in + make.height.equalTo(height) + make.top.equalTo(cancelButton.snp.bottom).offset(Constraints.saveButton.topInset.adjustedByHeight) + make.left.right.equalTo(cancelButton) + }) + + return button + } +} + + +// MARK: - Layout + extension MyGroupAliasViewController { - struct Constraints { + enum Constraints { - struct aliasField { + enum aliasField { static let height: CGFloat = 48.0 static let width: CGFloat = 382.0 @@ -179,7 +201,7 @@ extension MyGroupAliasViewController { static let horizontalInset = 16.0 } - struct cancelButton { + enum cancelButton { static let height = 44.0 static let width = aliasField.width @@ -189,7 +211,7 @@ extension MyGroupAliasViewController { static let labelHeightProportion = labelHeight / width } - struct saveButton { + enum saveButton { static let height: CGFloat = 48.0 static let width = CGFloat(aliasField.width) @@ -216,7 +238,9 @@ extension MyGroupAliasViewController { } } + // MARK: - Testable + extension MyGroupAliasViewController: TestableViewControllerProtocol { private enum Keys: String { diff --git a/Nynja/Modules/MyGroupAlias/WireFrame/MyGroupAliasWireframe.swift b/Nynja/Modules/MyGroupAlias/WireFrame/MyGroupAliasWireframe.swift index 57431ad09676802c270c97da1d5d5aa4ec7d5322..74b070cc73fb4c31cd2cffb7fbc6131e27b5b821 100644 --- a/Nynja/Modules/MyGroupAlias/WireFrame/MyGroupAliasWireframe.swift +++ b/Nynja/Modules/MyGroupAlias/WireFrame/MyGroupAliasWireframe.swift @@ -11,27 +11,25 @@ import UIKit class MyGroupAliasWireFrame: MyGroupAliasWireFrameProtocol { weak var navigation : UINavigationController? - func presentMyGroupAlias(navigation: UINavigationController, currentAlias: String, delegate: MyGroupAliasEditorDelegate?, nicks: [String], mode: GroupMode) { - + func presentMyGroupAlias(navigation: UINavigationController, + currentAlias: String, + delegate: MyGroupAliasEditorDelegate?, + mode: GroupMode) { + let view = MyGroupAliasViewController() - let presenter = MyGroupAliasPresenter() - presenter.delegate = delegate - let interactor = MyGroupAliasInteractor() - interactor.nicks = nicks - interactor.currentAlias = currentAlias - + let presenter = MyGroupAliasPresenter( + dependencies: .init(view: view, + wireFrame: self, + delegate: delegate, + currentAlias: currentAlias, + mode: mode)) + self.navigation = navigation // Connecting view.presenter = presenter - presenter.mode = mode - presenter.view = view - presenter.wireFrame = self - presenter.interactor = interactor - interactor.presenter = presenter navigation.pushViewController(view as UIViewController, animated: true) - } func hide() { diff --git a/Nynja/Modules/Profile/View/DetailsView/ProfileDetailsView.swift b/Nynja/Modules/Profile/View/DetailsView/ProfileDetailsView.swift index c88adbf9c2ccca53f9714348ccb77826f018b9e6..b16bb6c6a458fd2ee01e9bdeb4fe61780d76e4e3 100644 --- a/Nynja/Modules/Profile/View/DetailsView/ProfileDetailsView.swift +++ b/Nynja/Modules/Profile/View/DetailsView/ProfileDetailsView.swift @@ -195,8 +195,6 @@ class ProfileDetailsView: UIView { phoneLabel.isHidden = false walletButton.isHidden = false infoView.isHidden = false - - walletButton.isEnabled = false } // MARK: Recognizer diff --git a/Nynja/Modules/Profile/View/ProfileViewController.swift b/Nynja/Modules/Profile/View/ProfileViewController.swift index fb9ee10480166df4c9c65859ffac0040ac2d3d88..8ef1672dd295be844f67d7687ede181b53f47c3b 100644 --- a/Nynja/Modules/Profile/View/ProfileViewController.swift +++ b/Nynja/Modules/Profile/View/ProfileViewController.swift @@ -104,6 +104,7 @@ class ProfileViewController: BaseVC, ProfileViewProtocol { detailsView.avatarImageView.isUserInteractionEnabled = true let tapRecognizer = UITapGestureRecognizer(target: self, action: #selector(avatarTapped)) detailsView.avatarImageView.addGestureRecognizer(tapRecognizer) + detailsView.walletButton.addTarget(self, action: #selector(walletTapped), for: .touchUpInside) } //MARK: - ProfileViewProtocol @@ -153,11 +154,17 @@ class ProfileViewController: BaseVC, ProfileViewProtocol { presenter.showImagePreview(from: detailsView.avatarImageView) } - @objc private func walletButtonAction() { - presenter.walletTriggered() + @objc private func walletTapped() { + unavailableFunctionality() } + } +// MARK: - ComingSoonProtocol + +extension ProfileViewController: ComingSoonProtocol {} + + // MARK: - ChatListMessageCellModelDelegate extension ProfileViewController: ChatListMessageCellModelDelegate { diff --git a/Nynja/Modules/Profile/View/TableView/Cells/ScheduledMesssageCell/ProfileScheduledMesssageCell.swift b/Nynja/Modules/Profile/View/TableView/Cells/ScheduledMesssageCell/ProfileScheduledMesssageCell.swift index a96923f10c8866efe3623be23e9faaaf460a4928..a5ba1152a76a957e657934f7ea7f7f12128031b3 100644 --- a/Nynja/Modules/Profile/View/TableView/Cells/ScheduledMesssageCell/ProfileScheduledMesssageCell.swift +++ b/Nynja/Modules/Profile/View/TableView/Cells/ScheduledMesssageCell/ProfileScheduledMesssageCell.swift @@ -183,8 +183,6 @@ class ProfileScheduledMesssageCell: UITableViewCell, ConfigurableCell { private func setupMessageLabel(_ message: ScheduledMessage) { guard let sendType = message.job?.data?.first?.sendType else { return } switch sendType { - case .audio: - messageLabel.text = "voice_message".localized case .text: guard let message = message.job?.data?.first, let payload = message.mainFile?.payload else { messageLabel.text = nil @@ -193,8 +191,10 @@ class ProfileScheduledMesssageCell: UITableViewCell, ConfigurableCell { let parser = type(of: self).payloadParser let mentions = parser.parse(message) messageLabel.text = MessagePayloadRenderer.processPlainTextPayload(with: mentions, in: payload).text + case .sticker: + messageLabel.text = message.job?.data?.first?.mainFile?.messageRepresentation default: - messageLabel.text = message.job?.data?.first?.mainFile?.payload + messageLabel.text = message.job?.data?.first?.mainFile?.type?.messageDescription } } diff --git a/Nynja/Modules/ScheduleMessage/Models/ScheduleContentType.swift b/Nynja/Modules/ScheduleMessage/Models/ScheduleContentType.swift index 707838629524bc3767d4c095fd2bf806d7d814d0..790a73a41751b0f67c70aa14bc427506af51b959 100644 --- a/Nynja/Modules/ScheduleMessage/Models/ScheduleContentType.swift +++ b/Nynja/Modules/ScheduleMessage/Models/ScheduleContentType.swift @@ -32,6 +32,10 @@ enum ScheduleContentType { } else { return nil } + case .sticker: + let text = desc.messageRepresentation ?? "" + let model = TextItemModel(text: text, mentions: nil) + self = .text(model: model) default: let model = OtherItemModel(image: type.icon, description: type.messageDescription) self = .other(model: model) diff --git a/Nynja/Modules/SettingsGroup/Presenter/SettingsGroupPresenter.swift b/Nynja/Modules/SettingsGroup/Presenter/SettingsGroupPresenter.swift index 76657b6da3b80ab3f504a85d70dc70c705bc7a80..f2133709048ca2cd7869d44fcedb15761d436ce0 100644 --- a/Nynja/Modules/SettingsGroup/Presenter/SettingsGroupPresenter.swift +++ b/Nynja/Modules/SettingsGroup/Presenter/SettingsGroupPresenter.swift @@ -47,11 +47,10 @@ class SettingsGroupPresenter: BasePresenter, SettingsGroupPresenterProtocol, Cre // MARK: - Actions func changeAlias() { - if let nicks = room?.members?.map({ member -> String in - return member.alias ?? "" - }) { - wireFrame.changeAlias(alias: (ownMember?.alias)!, nicks: nicks) + guard let alias = ownMember?.alias else { + return } + wireFrame.changeAlias(alias: alias) } func openAvatar(from imageView: UIImageView) { diff --git a/Nynja/Modules/SettingsGroup/SettingsProtocols.swift b/Nynja/Modules/SettingsGroup/SettingsProtocols.swift index bb0ca5f62fc78089a196fe4cba51fd841727c1a3..de69828ae5e6dc88ae6aa18cd678e8f06bac8a49 100644 --- a/Nynja/Modules/SettingsGroup/SettingsProtocols.swift +++ b/Nynja/Modules/SettingsGroup/SettingsProtocols.swift @@ -19,7 +19,7 @@ protocol SettingsGroupWireframeProtocol: class { func presentAvatarModally(imageURL: URL, on view: UIViewController, with transitionInfo: ImagePreviewTransitionInfo) func changeAvatar() func changeGroupName(name: String) - func changeAlias(alias: String, nicks: [String]) + func changeAlias(alias: String) func showRules(room: Room?) func showStorage(room: Room?) func showLanguageSettings(_ room: Room?) diff --git a/Nynja/Modules/SettingsGroup/WireFrame/SettingsGroupWireFrame.swift b/Nynja/Modules/SettingsGroup/WireFrame/SettingsGroupWireFrame.swift index 8b2965c885b312fefbceea3845092f15f40c60d9..5a6b06a4352820913fef08c794211488f6ae8d41 100644 --- a/Nynja/Modules/SettingsGroup/WireFrame/SettingsGroupWireFrame.swift +++ b/Nynja/Modules/SettingsGroup/WireFrame/SettingsGroupWireFrame.swift @@ -73,8 +73,8 @@ class SettingsGroupWireFrame: SettingsGroupWireframeProtocol { self.navigation?.view.layoutIfNeeded() } - func changeAlias(alias: String, nicks: [String]) { - MyGroupAliasWireFrame().presentMyGroupAlias(navigation: navigation!, currentAlias: alias, delegate: external, nicks: nicks, mode: .update) + func changeAlias(alias: String) { + MyGroupAliasWireFrame().presentMyGroupAlias(navigation: navigation!, currentAlias: alias, delegate: external, mode: .update) // self.navigation?.view.layoutIfNeeded() } diff --git a/Nynja/Modules/Stickers/View/CollectionView/Cells/Sticker/StickerCellModel.swift b/Nynja/Modules/Stickers/View/CollectionView/Cells/Sticker/StickerCellModel.swift index fc0bd9728c17cabd364ba5905b2adc53a5c7a79f..0dfe5344b922f11243768f357d85335c7c517bb4 100644 --- a/Nynja/Modules/Stickers/View/CollectionView/Cells/Sticker/StickerCellModel.swift +++ b/Nynja/Modules/Stickers/View/CollectionView/Cells/Sticker/StickerCellModel.swift @@ -17,8 +17,8 @@ struct StickerCellModel: CellViewModel { let sticker: Sticker func setup(cell: StickerCollectionViewCell) { - cell.imageView.setImage(url: sticker.url, placeHolder: nil, accessibilityPrefix: nil) { (_, _) in - cell.setupTestingKeys() + cell.imageView.setImage(url: sticker.url) { [weak cell] _, _ in + cell?.setupTestingKeys() } } } diff --git a/Nynja/Modules/Stickers/View/CollectionView/Cells/Sticker/StickerCollectionViewCell.swift b/Nynja/Modules/Stickers/View/CollectionView/Cells/Sticker/StickerCollectionViewCell.swift index 172ab910c7f4901fcab2be28c011a46d18ad8f97..7771cb68c543216043a3407260abcfa7ace4e1a8 100644 --- a/Nynja/Modules/Stickers/View/CollectionView/Cells/Sticker/StickerCollectionViewCell.swift +++ b/Nynja/Modules/Stickers/View/CollectionView/Cells/Sticker/StickerCollectionViewCell.swift @@ -55,6 +55,7 @@ final class StickerCollectionViewCell: UICollectionViewCell, ScalableCell, Testa imageView.transform = .identity } + // MARK: - Testable func setupTestingKeys() { diff --git a/Nynja/OptionsItemsFactory.swift b/Nynja/OptionsItemsFactory.swift index 4f28559b6c98ab77083a9f4f4446ff1e9df8918e..89d3115d1eb09d5158eac182a6f8ab87814f0680 100644 --- a/Nynja/OptionsItemsFactory.swift +++ b/Nynja/OptionsItemsFactory.swift @@ -36,7 +36,7 @@ class OptionsItemsFactory: WCBaseItemsFactory { } var wheelPosition: ImageActionItemModel { - let item = ImageActionItemModel(navItem: .wheelPosition, action: { [weak navigateDelegate] (item, indexPath) in + let item = ImageActionItemModel(navItem: .wheelPosition, isSelectable: false, action: { [weak navigateDelegate] (item, indexPath) in // navigateDelegate?.showWheelPositionPicker(indexPath: indexPath) navigateDelegate?.unavailableFunctionality() }) @@ -58,7 +58,7 @@ class OptionsItemsFactory: WCBaseItemsFactory { } var theme: ImageActionItemModel { - let item = ImageActionItemModel(navItem: .theme, action: { [weak navigateDelegate] (item, indexPath) in + let item = ImageActionItemModel(navItem: .theme, isSelectable: false, action: { [weak navigateDelegate] (item, indexPath) in // navigateDelegate?.showThemePicker(indexPath: indexPath) navigateDelegate?.unavailableFunctionality() }) @@ -73,7 +73,7 @@ class OptionsItemsFactory: WCBaseItemsFactory { } var about: ImageActionItemModel { - let item = ImageActionItemModel(navItem: .about, action: { [weak navigateDelegate] (item, indexPath) in + let item = ImageActionItemModel(navItem: .about, isSelectable: false, action: { [weak navigateDelegate] (item, indexPath) in // navigateDelegate?.showAbout(indexPath: indexPath) navigateDelegate?.unavailableFunctionality() }) @@ -89,7 +89,7 @@ class OptionsItemsFactory: WCBaseItemsFactory { } var changeNumber: ImageActionItemModel { - let item = ImageActionItemModel(navItem: .phoneNumber, action: { [weak navigateDelegate] (item, indexPath) in + let item = ImageActionItemModel(navItem: .phoneNumber, isSelectable: false, action: { [weak navigateDelegate] (item, indexPath) in // navigateDelegate?.showChangeNumber(indexPath: indexPath) navigateDelegate?.unavailableFunctionality() }) diff --git a/Nynja/Resources/Info.plist b/Nynja/Resources/Info.plist index 5472ab2b7a70a4cae93b9b54aaa3489d3b24f3c4..3b4e210861d1f5dae15b38c0e89c19e132bedf43 100644 --- a/Nynja/Resources/Info.plist +++ b/Nynja/Resources/Info.plist @@ -21,7 +21,7 @@ CFBundleShortVersionString 1.0 CFBundleVersion - 0.2.158 + 0.2.163 ConfServerAddress $(ConfServerAddress) ConfServerPort diff --git a/Nynja/Resources/ReleaseConfig.xcconfig b/Nynja/Resources/ReleaseConfig.xcconfig index 5558ccba715dc67536d6eb90a0480a3a361fe840..556cb1b2bbbdf3ca26017d32979a29c36ac4fcf2 100644 --- a/Nynja/Resources/ReleaseConfig.xcconfig +++ b/Nynja/Resources/ReleaseConfig.xcconfig @@ -14,7 +14,7 @@ AppName = NYNJA ServerPort = 8443 Config = release AppGroup = group.com.nynja.mobile.communicator -ModelsVersion = 8 +ModelsVersion = 9 isServerConnectionSecure = true ConfServerAddress = call.nynja.net ConfServerPort = 443 diff --git a/Nynja/RoomDAO.swift b/Nynja/RoomDAO.swift index ddefef3d8c684caa208603782dcf092810bf8962..477c02b81058823b5e6851286b4431f1dc1fb93a 100644 --- a/Nynja/RoomDAO.swift +++ b/Nynja/RoomDAO.swift @@ -73,13 +73,11 @@ class RoomDAO: RoomDAOProtocol { .asRequest(of: Int64.self) .fetchOne(db) } - } else { - guard let phoneId = StorageService.sharedInstance.phoneId else { - return nil - } - + } else if let phoneId = StorageService.sharedInstance.phoneId { return MemberDAO.findMemberBy(roomId: roomId, phoneId: phoneId)?.reader } + + return nil } // MARK: -- Mentions @@ -122,35 +120,42 @@ class RoomDAO: RoomDAOProtocol { } // MARK: -- Fields - static func updateReader(_ reader: Int64, roomId: String, kind: ReaderKind) { + static func updateReader(_ reader: Int64, roomId: String, phoneId: String, kind: ReaderKind) { if kind == .other { - updateOtherReader(reader, roomId: roomId) - } else { - updateOwnReader(reader, roomId: roomId) + updateChatReader(reader, roomId: roomId) + } else if kind == .own { + updateMentions(with: reader, roomId: roomId) } + + MemberDAO.updateReader(reader, roomId: roomId, phoneId: phoneId) } - private static func updateOtherReader(_ reader: Int64, roomId: String) { - // Remove mentions that has been read. - let unreadMentions = fetchMentions(for: roomId)?.compactMap { $0 > reader ? $0 as AnyObject : nil } - - let room = Room() - room.id = roomId - room.readers = [reader as AnyObject] - room.mentions = unreadMentions + private static func updateChatReader(_ reader: Int64, roomId: String) { + guard let room = fetchRoom(by: roomId), + let oldReader = room.reader, + oldReader < reader else { + return + } - let columns: Set = [RoomTable.Column.reader.title, RoomTable.Column.mentions.title] + room.reader = reader + let columns: Set = [RoomTable.Column.reader.title] try? dbManager.perform(action: .updateColumns(columns), with: room) } - private static func updateOwnReader(_ reader: Int64, roomId: String) { - guard let phoneId = StorageService.sharedInstance.phoneId, - let member = MemberDAO.findMemberBy(roomId: roomId, phoneId: phoneId) else { - return + private static func updateMentions(with reader: Int64, roomId: String) { + let mentions = fetchMentions(for: roomId) ?? [] + guard !mentions.isEmpty else { + return } - member.reader = reader - MemberDAO.updateColumns([.reader], member: member) + let unreadMentions = mentions.compactMap { $0 > reader ? $0 as AnyObject : nil } + + let room = Room() + room.id = roomId + room.mentions = unreadMentions + + let columns: Set = [RoomTable.Column.mentions.title] + try? dbManager.perform(action: .updateColumns(columns), with: room) } static func updatedMentions(with message: Message, roomId: String) -> UpdateResult<[Int64]> { diff --git a/Nynja/RoomDAOProtocol.swift b/Nynja/RoomDAOProtocol.swift index 2dd4ef83b9a118a651842d46f9f6cd09ef4c7dab..0cd19c45180d660e226a397c92fca37a18021469 100644 --- a/Nynja/RoomDAOProtocol.swift +++ b/Nynja/RoomDAOProtocol.swift @@ -29,7 +29,7 @@ protocol RoomDAOProtocol: DAOProtocol { static func updateColumns(_ columns: Set, room: Room) // MARK: -- Fields - static func updateReader(_ reader: Int64, roomId: String, kind: ReaderKind) + static func updateReader(_ reader: Int64, roomId: String, phoneId: String, kind: ReaderKind) static func updatedMentions(with message: Message, roomId: String) -> UpdateResult<[Int64]> // MARK: - Contains Members diff --git a/Nynja/Services/Aps.swift b/Nynja/Services/Aps.swift index 14a69cd788fd5ed5409acaf7ea5fab6b51948c5c..6323b5e3e4953fb1607621497218da39766cd3c3 100644 --- a/Nynja/Services/Aps.swift +++ b/Nynja/Services/Aps.swift @@ -99,28 +99,30 @@ struct Aps { } if let r = room { chat = r - if let member = r.members?.filter({ (member) -> Bool in - guard let memId = member.phone_id, - let lastMessSender = r.last_msg?.from else { return false } + if let member = r.allMembersWithoutFilter?.first(where: { + guard let memId = $0.phone_id, let lastMessSender = r.last_msg?.from else { + return false + } return memId == lastMessSender - }).first { + }) { text = notificationTextFrom(room: r, member: member) sender = "\(member.alias ?? member.fullName ?? "")@\(r.name ?? "")" } } if text == nil, - let desc = chat?.last_msg?.mainFile, - let type = desc.type { + let desc = chat?.last_msg?.mainFile, + let type = desc.type { + if (contact?.status as? StringAtom)?.string == "friend" && (desc.payload == "" && desc.mime == "text") { + return "\(sender ?? "") accepted your contact request! Send a message!" + } switch type { case .sticker: let stick: String = desc.messageRepresentation ?? "" text = "\(sender ?? ""): \(stick)" - default: - if (contact?.status as? StringAtom)?.string == "friend" { - text = "\(sender ?? "") accepted your contact request! Send a message!" - break - } + case .audio,.contact,.location,.image,.video,.file,.place: text = "\(sender ?? ""): \(type.messageDescription)" + default: + break } } if text == nil, let c = contact { diff --git a/Nynja/Services/HandleServices/MessageHandler.swift b/Nynja/Services/HandleServices/MessageHandler.swift index 8b2f411a16be814166bf6fe9ccab4a734bc60fc6..b585642f2f3393f57c8bafb42eeb83a4f6964391 100644 --- a/Nynja/Services/HandleServices/MessageHandler.swift +++ b/Nynja/Services/HandleServices/MessageHandler.swift @@ -80,10 +80,7 @@ final class MessageHandler: BaseHandler { } if let oldMessage = MessageDAO.fetchMessage(serverId: link) { - oldMessage.files = message.files - - oldMessage.markAsEdited() - oldMessage.messageStatus = nil + oldMessage.edit(by: message) do { try saveIntoDatabase(message: oldMessage) diff --git a/Nynja/Services/HandleServices/RoomHandler.swift b/Nynja/Services/HandleServices/RoomHandler.swift index 34d7b905ca0083944f6776b5dee90eafcef250a9..0ac15f114bd15af7681e56adae050afb7bc8ea74 100644 --- a/Nynja/Services/HandleServices/RoomHandler.swift +++ b/Nynja/Services/HandleServices/RoomHandler.swift @@ -39,6 +39,7 @@ class RoomHandler: BaseHandler { switch status { case .get: RoomDAO.updateRoom(room) { (new, old) in + new.mentions = old.mentions new.message = old.message return new } @@ -131,26 +132,24 @@ class RoomHandler: BaseHandler { } private static func filterAdmins(using room: Room, in oldRoom: Room) { - oldRoom.admins = oldRoom.admins?.filter { member -> Bool in - if let isContains = room.members?.contains(where: { newMember -> Bool in - return newMember.phone_id == member.phone_id - }) { - return !isContains + oldRoom.admins = oldRoom.admins?.filter { admin in + guard let members = room.members else { + return true } - return true + return !members.contains { $0.phone_id == admin.phone_id } } } private static func addNotExistedAdmins(from room: Room, to oldRoom: Room) { var notExistsAdmins: [Member] = [] - room.admins?.forEach({ member in + room.admins?.forEach { member in if let oldMember = oldRoom.admins?.first(where: { $0.phone_id == member.phone_id }) { oldMember.status = member.status } else { notExistsAdmins.append(member) } - }) + } var admins = oldRoom.admins ?? [] admins.append(contentsOf: notExistsAdmins) @@ -158,14 +157,12 @@ class RoomHandler: BaseHandler { } private static func filterMembers(using room: Room, in oldRoom: Room) { - oldRoom.members = oldRoom.members?.filter({ member -> Bool in - if let isContains = room.admins?.contains(where: { newMember -> Bool in - return newMember.phone_id == member.phone_id - }) { - return !isContains + oldRoom.members = oldRoom.members?.filter { member in + guard let admins = room.admins else { + return true } - return true - }) + return !admins.contains { $0.phone_id == member.phone_id } + } } @@ -173,11 +170,11 @@ class RoomHandler: BaseHandler { private static func handleRemoveMember(_ room: Room) { if let id = room.id, let oldRoom = RoomDAO.findRoom(by: id) { - room.members?.forEach({ member in - if let oldMember = oldRoom.members?.first(where: { $0.phone_id == member.phone_id }) { + room.allMembersWithoutFilter?.forEach { member in + if let oldMember = oldRoom.allMembersWithoutFilter?.first(where: { $0.phone_id == member.phone_id }) { oldMember.status = member.status } - }) + } oldRoom.status = room.status try? storageService.perform(action: .save, with: oldRoom) } @@ -187,21 +184,21 @@ class RoomHandler: BaseHandler { // MARK: - Leave private static func handleLeave(_ room: Room) { - if let id = room.id, let oldRoom = RoomDAO.findRoom(by: id) { - let phoneId = storageService.phoneId - if let _ = room.allMembersWithRemoved?.first(where: { $0.phone_id == phoneId }) { - room.unread = 0 - try? storageService.perform(action: .save, with: room) - } else { - if let ad = oldRoom.admins?.first(where: { $0.phone_id == room.allMembers?.first?.phone_id }) { - ad.status = StringAtom(string: "removed") - } else if let mm = oldRoom.members?.first(where: { $0.phone_id == room.allMembers?.first?.phone_id }) { - mm.status = StringAtom(string: "removed") - } - oldRoom.status = StringAtom(string: "get") - oldRoom.unread = 0 - try? storageService.perform(action: .save, with: oldRoom) + guard let id = room.id, let oldRoom = RoomDAO.findRoom(by: id), let phoneId = storageService.phoneId else { + return + } + if let _ = room.allMembersWithRemoved?.first(where: { $0.phone_id == phoneId }) { + room.unread = 0 + try? storageService.perform(action: .save, with: room) + } else { + if let ad = oldRoom.admins?.first(where: { $0.phone_id == room.allMembers?.first?.phone_id }) { + ad.status = StringAtom(string: "removed") + } else if let mm = oldRoom.members?.first(where: { $0.phone_id == room.allMembers?.first?.phone_id }) { + mm.status = StringAtom(string: "removed") } + oldRoom.status = StringAtom(string: "get") + oldRoom.unread = 0 + try? storageService.perform(action: .save, with: oldRoom) } } diff --git a/Nynja/Services/MQTT/MQTTServiceProfile.swift b/Nynja/Services/MQTT/MQTTServiceProfile.swift index 0ba490286618fb91efc5c00da6d6ceec60ec34df..48f53411f3fec4887cc61ab98740e77dcdd354ab 100644 --- a/Nynja/Services/MQTT/MQTTServiceProfile.swift +++ b/Nynja/Services/MQTT/MQTTServiceProfile.swift @@ -12,7 +12,12 @@ extension MQTTService { func updateAccount(id: Int64, name: String, surname: String, phone: String) { if let _ = StorageService.sharedInstance.token { - let model = UpdateRosterModel(id: id, name: name, surname: surname, avatar: nil, email: nil,nick: nil) + var model:UpdateRosterModel! + if surname != "" { + model = UpdateRosterModel(id: id, name: name, surname: surname, avatar: nil, email: nil,nick: nil) + } else { + model = UpdateRosterModel(id: id, name: name, surname: nil, avatar: nil, email: nil,nick: nil) + } publish(model: model) } } diff --git a/Nynja/Services/Member/MemberDAO.swift b/Nynja/Services/Member/MemberDAO.swift index 9af0b48c9664cc286b2069c90bd6cead643662ba..9cf7ed62a213c754530a8e8225a72be8f597268f 100644 --- a/Nynja/Services/Member/MemberDAO.swift +++ b/Nynja/Services/Member/MemberDAO.swift @@ -60,4 +60,13 @@ class MemberDAO: MemberDAOProtocol { try? dbManager.perform(action: .updateColumns(columns), with: member) } + static func updateReader(_ reader: Int64, roomId: String, phoneId: String) { + guard let member = MemberDAO.findMemberBy(roomId: roomId, phoneId: phoneId) else { + return + } + + member.reader = reader + MemberDAO.updateColumns([.reader], member: member) + } + } diff --git a/Nynja/Services/Member/MemberDAOProtocol.swift b/Nynja/Services/Member/MemberDAOProtocol.swift index 379bd5a8ba9fef92b8a4734f2a796d85c77c9615..a8d461120e5eafe0a3de125159ba54602ef286a6 100644 --- a/Nynja/Services/Member/MemberDAOProtocol.swift +++ b/Nynja/Services/Member/MemberDAOProtocol.swift @@ -19,5 +19,6 @@ protocol MemberDAOProtocol: DAOProtocol { // MARK: - Update static func updateColumns(_ columns: Set, member: Member) + static func updateReader(_ reader: Int64, roomId: String, phoneId: String) } diff --git a/Nynja/Services/PushService.swift b/Nynja/Services/PushService.swift index 4a4fd9ccc897b1ae7075a5bd5b429a940c50a996..4713eafe5559d5dcc719b55abb7d43be51eda9ca 100644 --- a/Nynja/Services/PushService.swift +++ b/Nynja/Services/PushService.swift @@ -90,8 +90,14 @@ final class PushService: NSObject, PKPushRegistryDelegate, UserSettingsRespondab removePushesFromChat(message) case .updateHistory: if let room = aps.room { - guard let reader = room.reader else { return } - RoomDAO.updateColumns([.unread, .reader], room: room) + guard let reader = room.selfReader, + let phoneId = room.selfMember?.phone_id, + let roomId = room.id else { + return + } + + MemberDAO.updateReader(reader, roomId: roomId, phoneId: phoneId) + RoomDAO.updateColumns([.unread], room: room) readPushes(feed: room, reader: reader) } if let contact = aps.contact { @@ -102,8 +108,10 @@ final class PushService: NSObject, PKPushRegistryDelegate, UserSettingsRespondab case .messageDelete: guard let message = getMessage(aps) else { return } try? saveIntoDatabase(message: message) - ChatService.removeMessage(message) - removePush(message) + if MessageDAO.shouldMarkMessageAsDeleted(message) { + ChatService.removeMessage(message) + removePush(message) + } case .messageEdit: guard let message = getMessage(aps) else { return } try? saveIntoDatabase(message: message) @@ -113,10 +121,7 @@ final class PushService: NSObject, PKPushRegistryDelegate, UserSettingsRespondab } if let oldMessage = MessageDAO.fetchMessage(serverId: link) { - oldMessage.files = message.files - - oldMessage.markAsEdited() - oldMessage.messageStatus = nil + oldMessage.edit(by: message) do { try saveIntoDatabase(message: oldMessage) @@ -133,7 +138,7 @@ final class PushService: NSObject, PKPushRegistryDelegate, UserSettingsRespondab try? messageEditService.deleteEditActionForMessage(oldMessage) } - updatePush(message) + updatePush(message, text: aps.text) case .undefined: handleNynjaNotification(with: aps, data: data) } } @@ -177,7 +182,7 @@ final class PushService: NSObject, PKPushRegistryDelegate, UserSettingsRespondab } } - private func updatePush(_ message: Message) { + private func updatePush(_ message: Message, text: String) { guard let link = message.link as? Int64 else { return } let predicate = basePredicate(message: message) + "\(link)" UNUserNotificationCenter.current().getDeliveredNotifications { (notifications) in @@ -187,7 +192,7 @@ final class PushService: NSObject, PKPushRegistryDelegate, UserSettingsRespondab let request = find.first?.request let data = request?.content.body.split(separator: ":") let sender = String(data?.first ?? "") - let newBody = "\(sender):\(message.files?.first?.payload ?? "")" + let newBody = text let content = UNMutableNotificationContent() content.body = newBody diff --git a/Nynja/WCBaseItemsFactory.swift b/Nynja/WCBaseItemsFactory.swift index 58b219d27fa9330bce9af5569ac7f378e0a044e3..c211d63e66aebc98771e6c7c40b8c4c9be7527ac 100644 --- a/Nynja/WCBaseItemsFactory.swift +++ b/Nynja/WCBaseItemsFactory.swift @@ -93,8 +93,9 @@ class WCBaseItemsFactory: WCItemsFactory { } var channels: ImageActionItemModel { - return ImageActionItemModel(nameImage: "ic_channel_inactive", navItem: .channels) { [weak navigateDelegate] (item, indexPath) in - navigateDelegate?.showChannels(indexPath: indexPath) + return ImageActionItemModel(nameImage: "ic_channel_inactive", navItem: .channels, isSelectable: false) { [weak navigateDelegate] (item, indexPath) in + // navigateDelegate?.showChannels(indexPath: indexPath) + navigateDelegate?.unavailableFunctionality() } } diff --git a/Podfile b/Podfile index 7591f30d602ae50d0dc7ecb78b2c5be0f5504dd0..b040182dc285faa2c782642932568639e1aafd80 100644 --- a/Podfile +++ b/Podfile @@ -8,7 +8,7 @@ project 'Nynja' project 'Frameworks/NynjaUIKit/NynjaUIKit' plugin 'cocoapods-art', :sources => [ - 'cocoapods-local' +'cocoapods-local' ] def installationSettings @@ -17,67 +17,67 @@ def installationSettings end def commonPodsForNynja - pod 'TestFairy', '~> 1.13.1' - pod 'SnapKit', '~> 4.0.0' - pod 'Fabric', '~> 1.6.13' - pod 'Crashlytics', '~> 3.8.6' - pod 'CocoaMQTT' - pod 'libPhoneNumber-iOS', '~> 0.8' - pod 'QRCode' + pod 'TestFairy', '= 1.13.4' + pod 'SnapKit', '= 4.0.0' + pod 'Fabric', '= 1.6.13' + pod 'Crashlytics', '= 3.8.6' + pod 'CocoaMQTT', '= 1.1.2' + pod 'libPhoneNumber-iOS', '= 0.9.13' + pod 'QRCode', '= 2.0' pod 'CocoaLumberjack', :git => 'https://github.com/CocoaLumberjack/CocoaLumberjack', :commit => '12948ff' - pod 'AWSS3', '~> 2.6.1' - pod 'SDWebImage', '~> 4.0' - - pod 'GoogleMaps' - pod 'GooglePlaces' + pod 'AWSS3', '= 2.6.20' + pod 'SDWebImage', '= 4.4.2' + + pod 'GoogleMaps', '= 2.7.0' + pod 'GooglePlaces', '= 2.7.0' pod 'Firebase/Storage' pod 'Firebase/Auth' - pod 'GRDBCipher', '~> 2.10.0' - pod 'SwiftyJSON', '~> 4.0.0' - - pod 'AutoScrollLabel' - pod 'MaterialComponents/FlexibleHeader' - pod 'JTAppleCalendar', '~> 7.0' - - pod 'NynjaSDK', '= 1.5.5' - - pod 'CryptoSwift' + pod 'GRDBCipher', '= 2.10.0' + pod 'SwiftyJSON', '= 4.0.0' + + pod 'AutoScrollLabel', '= 0.4.3' + pod 'MaterialComponents/FlexibleHeader', '= 55.3.0' + pod 'JTAppleCalendar', '= 7.1.5' + + pod 'NynjaSDK', '= 1.5.6' - pod 'MulticastDelegateSwift', '~> 2.1.1' + pod 'CryptoSwift', '= 0.10.0' + + pod 'MulticastDelegateSwift', '= 2.1.1' end def commonPodsForNynjaTests - pod 'SnapKit', '~> 4.0.0' - pod 'Fabric', '~> 1.6.13' - pod 'Crashlytics', '~> 3.8.6' - pod 'CocoaMQTT' - pod 'libPhoneNumber-iOS', '~> 0.8' - pod 'QRCode' + pod 'SnapKit', '= 4.0.0' + pod 'Fabric', '= 1.6.13' + pod 'Crashlytics', '= 3.8.6' + pod 'CocoaMQTT', '= 1.1.2' + pod 'libPhoneNumber-iOS', '= 0.9.13' + pod 'QRCode', '= 2.0' pod 'CocoaLumberjack', :git => 'https://github.com/CocoaLumberjack/CocoaLumberjack', :commit => '12948ff' - pod 'AWSS3', '~> 2.6.1' - pod 'SDWebImage', '~> 4.0' - - pod 'GoogleMaps' - pod 'GooglePlaces' - pod 'GRDBCipher', '~> 2.10.0' - - pod 'AutoScrollLabel' - pod 'MaterialComponents/FlexibleHeader' - pod 'JTAppleCalendar', '~> 7.0' + pod 'AWSS3', '= 2.6.20' + pod 'SDWebImage', '= 4.4.2' + + pod 'GoogleMaps', '= 2.7.0' + pod 'GooglePlaces', '= 2.7.0' + pod 'GRDBCipher', '= 2.10.0' + + pod 'AutoScrollLabel', '= 0.4.3' + pod 'MaterialComponents/FlexibleHeader', '= 55.3.0' + pod 'JTAppleCalendar', '= 7.1.5' end def commonPodsForNynjaShare - pod 'libPhoneNumber-iOS', '~> 0.8' - pod 'AWSS3', '~> 2.6.1' - pod 'CocoaMQTT' - pod 'SnapKit', '~> 4.0.0' - pod 'SDWebImage', '~> 4.0' - pod 'GRDBCipher', '~> 2.10.0' - pod 'CryptoSwift' + pod 'libPhoneNumber-iOS', '= 0.9.13' + pod 'AWSS3', '= 2.6.20' + pod 'CocoaMQTT', '= 1.1.2' + pod 'SnapKit', '= 4.0.0' + pod 'SDWebImage', '= 4.4.2' + pod 'GRDBCipher', '= 2.10.0' + pod 'CryptoSwift', '= 0.10.0' end def commonPodsForNynjaUIKit - pod 'SnapKit', '~> 4.0.0' + pod 'SnapKit', '= 4.0.0' end target 'Nynja' do @@ -110,7 +110,7 @@ post_install do |installer| config.build_settings['SWIFT_VERSION'] = '4.0' end end - + installer.pods_project.build_configurations.each do |config| config.build_settings['PROVISIONING_PROFILE_SPECIFIER'] = '' end diff --git a/Podfile.lock b/Podfile.lock new file mode 100644 index 0000000000000000000000000000000000000000..c8c9dad063b3cd81068f5b13bdfabbccf1415f1f --- /dev/null +++ b/Podfile.lock @@ -0,0 +1,178 @@ +PODS: + - AutoScrollLabel (0.4.3) + - AWSCore (2.6.20) + - AWSS3 (2.6.20): + - AWSCore (= 2.6.20) + - CocoaAsyncSocket (7.6.3) + - CocoaLumberjack (3.2.1): + - CocoaLumberjack/Default (= 3.2.1) + - CocoaLumberjack/Extensions (= 3.2.1) + - CocoaLumberjack/Default (3.2.1) + - CocoaLumberjack/Extensions (3.2.1): + - CocoaLumberjack/Default + - CocoaMQTT (1.1.2): + - CocoaAsyncSocket (~> 7.6.1) + - SwiftyTimer (~> 2.0.0) + - Crashlytics (3.8.6): + - Fabric (~> 1.6.3) + - CryptoSwift (0.10.0) + - Fabric (1.6.13) + - Firebase/Auth (5.1.0): + - Firebase/CoreOnly + - FirebaseAuth (= 5.0.0) + - Firebase/CoreOnly (5.1.0): + - FirebaseCore (= 5.0.2) + - Firebase/Storage (5.1.0): + - Firebase/CoreOnly + - FirebaseStorage (= 3.0.0) + - FirebaseAuth (5.0.0): + - FirebaseCore (~> 5.0) + - GTMSessionFetcher/Core (~> 1.1) + - FirebaseCore (5.0.2): + - "GoogleToolboxForMac/NSData+zlib (~> 2.1)" + - FirebaseStorage (3.0.0): + - FirebaseCore (~> 5.0) + - GTMSessionFetcher/Core (~> 1.1) + - GoogleMaps (2.7.0): + - GoogleMaps/Maps (= 2.7.0) + - GoogleMaps/Base (2.7.0) + - GoogleMaps/Maps (2.7.0): + - GoogleMaps/Base + - GooglePlaces (2.7.0): + - GoogleMaps/Base (= 2.7.0) + - GoogleToolboxForMac/Defines (2.1.4) + - "GoogleToolboxForMac/NSData+zlib (2.1.4)": + - GoogleToolboxForMac/Defines (= 2.1.4) + - GRDBCipher (2.10.0): + - SQLCipher (~> 3.4.1) + - GTMSessionFetcher/Core (1.1.15) + - JTAppleCalendar (7.1.5) + - libPhoneNumber-iOS (0.9.13) + - MaterialComponents/FlexibleHeader (55.3.0): + - MaterialComponents/private/Application + - MaterialComponents/private/UIMetrics + - MDFTextAccessibility + - MaterialComponents/private/Application (55.3.0) + - MaterialComponents/private/UIMetrics (55.3.0): + - MaterialComponents/private/Application + - MDFTextAccessibility (1.2.0) + - MulticastDelegateSwift (2.1.1) + - NynjaSDK (1.5.6) + - QRCode (2.0) + - SDWebImage (4.4.2): + - SDWebImage/Core (= 4.4.2) + - SDWebImage/Core (4.4.2) + - SnapKit (4.0.0) + - SQLCipher (3.4.2): + - SQLCipher/standard (= 3.4.2) + - SQLCipher/common (3.4.2) + - SQLCipher/standard (3.4.2): + - SQLCipher/common + - SwiftyJSON (4.0.0) + - SwiftyTimer (2.0.0) + - TestFairy (1.13.4) + +DEPENDENCIES: + - AutoScrollLabel (= 0.4.3) + - AWSS3 (= 2.6.20) + - CocoaLumberjack (from `https://github.com/CocoaLumberjack/CocoaLumberjack`, commit `12948ff`) + - CocoaMQTT (= 1.1.2) + - Crashlytics (= 3.8.6) + - CryptoSwift (= 0.10.0) + - Fabric (= 1.6.13) + - Firebase/Auth + - Firebase/Storage + - GoogleMaps (= 2.7.0) + - GooglePlaces (= 2.7.0) + - GRDBCipher (= 2.10.0) + - JTAppleCalendar (= 7.1.5) + - libPhoneNumber-iOS (= 0.9.13) + - MaterialComponents/FlexibleHeader (= 55.3.0) + - MulticastDelegateSwift (= 2.1.1) + - NynjaSDK (= 1.5.6) + - QRCode (= 2.0) + - SDWebImage (= 4.4.2) + - SnapKit (= 4.0.0) + - SwiftyJSON (= 4.0.0) + - TestFairy (= 1.13.4) + +SPEC REPOS: + https://github.com/cocoapods/specs.git: + - AutoScrollLabel + - AWSCore + - AWSS3 + - CocoaAsyncSocket + - CocoaMQTT + - Crashlytics + - CryptoSwift + - Fabric + - Firebase + - FirebaseAuth + - FirebaseCore + - FirebaseStorage + - GoogleMaps + - GooglePlaces + - GoogleToolboxForMac + - GRDBCipher + - GTMSessionFetcher + - JTAppleCalendar + - libPhoneNumber-iOS + - MaterialComponents + - MDFTextAccessibility + - MulticastDelegateSwift + - QRCode + - SDWebImage + - SnapKit + - SQLCipher + - SwiftyJSON + - SwiftyTimer + - TestFairy + https://nynjagroup.jfrog.io/nynjagroup/api/pods/cocoapods-local: + - NynjaSDK + +EXTERNAL SOURCES: + CocoaLumberjack: + :commit: 12948ff + :git: https://github.com/CocoaLumberjack/CocoaLumberjack + +CHECKOUT OPTIONS: + CocoaLumberjack: + :commit: 12948ff + :git: https://github.com/CocoaLumberjack/CocoaLumberjack + +SPEC CHECKSUMS: + AutoScrollLabel: bee53a1d4532569b49cbecaf9b80ca003bed3767 + AWSCore: dd4d3d4fcafdce68a42025c3e9e45b026cf1f33b + AWSS3: 69589dec1883cdca872b4ddd1ea2ef814b0846fe + CocoaAsyncSocket: eafaa68a7e0ec99ead0a7b35015e0bf25d2c8987 + CocoaLumberjack: 520616f8e72226ca2c729b43981b66bc483745ce + CocoaMQTT: d33ab3cd4e329f9f1cfbb62e25306a318a606616 + Crashlytics: 95d05f4e4c19a771250c4bd9ce344d996de32bbf + CryptoSwift: 6c778d69282bed3b4e975ff97a79d074f20bb011 + Fabric: 2fb5676bc811af011a04513451f463dac6803206 + Firebase: e08fb0795f35707aeb1d8a715c731c45bdf6fd56 + FirebaseAuth: acbeef02fe7c3a26624e309849f3fe30c84115af + FirebaseCore: b81044df1044c0857a0737c6324678b72d4f7f00 + FirebaseStorage: 7ca4bb7b58a25fa647b04f524033fc7cb7eb272b + GoogleMaps: f79af95cb24d869457b1f961c93d3ce8b2f3b848 + GooglePlaces: 3d06e6c99654545b4738ce49648745779c25f2ef + GoogleToolboxForMac: 91c824d21e85b31c2aae9bb011c5027c9b4e738f + GRDBCipher: eef21d242c727a21e0f87ad44f8ea2df03edd252 + GTMSessionFetcher: 5fa5b80fd20e439ef5f545fb2cb3ca6c6714caa2 + JTAppleCalendar: 2d4f974f9f3c8b4964d51ca1f6e004883c031fbe + libPhoneNumber-iOS: e444379ac18bbfbdefad571da735b2cd7e096caa + MaterialComponents: 915f4e844400a35db3ea4c710a9af40aa8bcb093 + MDFTextAccessibility: 94098925e0853551c5a311ce7c1ecefbe297cdb6 + MulticastDelegateSwift: 93eb077c24f50574b3f8a3f23bf71be6de6e3b41 + NynjaSDK: 83e97b19149b19ffd5219bca3c5ef4a9906b1b0f + QRCode: f98a1886c8f37523704a7512a4c0cd45b34c18a4 + SDWebImage: 624d6e296c69b244bcede364c72ae0430ac14681 + SnapKit: a42d492c16e80209130a3379f73596c3454b7694 + SQLCipher: f9fcf29b2e59ced7defc2a2bdd0ebe79b40d4990 + SwiftyJSON: 070dabdcb1beb81b247c65ffa3a79dbbfb3b48aa + SwiftyTimer: 2efd74b060d69ad4f1496baf5bbedbe132125fcf + TestFairy: 842f8ddc45477b208eb85326b0418047b40f7137 + +PODFILE CHECKSUM: 7e29c30b225b81fe9cd363f542473994d7969f73 + +COCOAPODS: 1.5.3 diff --git a/Shared/Library/Extensions/Models/Message/MessageExtension.swift b/Shared/Library/Extensions/Models/Message/MessageExtension.swift index 3b25236b89faaaaafd7480bcce4bd054ca27cd82..5e1fbf9465eb4b94b305b3353754973696e0d356 100644 --- a/Shared/Library/Extensions/Models/Message/MessageExtension.swift +++ b/Shared/Library/Extensions/Models/Message/MessageExtension.swift @@ -123,6 +123,18 @@ extension Message { } } +// MARK: - Actions + +extension Message { + + func edit(by message: Message) { + files = message.files + mentioned = message.mentioned + markAsEdited() + messageStatus = nil + } +} + // MARK: - Feed extension Message { diff --git a/Shared/Library/Extensions/Models/Room/Room+BaseChatModel.swift b/Shared/Library/Extensions/Models/Room/Room+BaseChatModel.swift index 68e9ed45506acbde912eb98d268e66ef6cb55b44..ee3c6ff7860a6399eef609c0f8f16c844e8badd6 100644 --- a/Shared/Library/Extensions/Models/Room/Room+BaseChatModel.swift +++ b/Shared/Library/Extensions/Models/Room/Room+BaseChatModel.swift @@ -18,7 +18,7 @@ extension Room: BaseChatModel { var selfReader: Int64? { get { - return allMembers?.filter { $0.phone_id == StorageService.sharedInstance.phoneId}.first?.reader + return selfMember?.reader } }