Merge remote-tracking branch 'origin/fix/minor-outgoing-quote-bugs' into fix/deadlock-improvements

This commit is contained in:
Morgan Pretty 2023-08-18 08:48:02 +10:00
commit 769d9b567b
221 changed files with 4054 additions and 4495 deletions

@ -1 +1 @@
Subproject commit d8f07fa92c12c5c2409774e03e03395d7847d1c2
Subproject commit e3ccf29db08aaf0b9bb6bbe72ae5967cd183a78d

View File

@ -19,7 +19,6 @@
3496956021A2FC8100DCFE74 /* CloudKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3496955F21A2FC8100DCFE74 /* CloudKit.framework */; };
34A6C28021E503E700B5B12E /* OWSImagePickerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A6C27F21E503E600B5B12E /* OWSImagePickerController.swift */; };
34A8B3512190A40E00218A25 /* MediaAlbumView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34A8B3502190A40E00218A25 /* MediaAlbumView.swift */; };
34B0796D1FCF46B100E248C2 /* MainAppContext.m in Sources */ = {isa = PBXBuildFile; fileRef = 34B0796B1FCF46B000E248C2 /* MainAppContext.m */; };
34B6A903218B3F63007C4606 /* TypingIndicatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34B6A902218B3F62007C4606 /* TypingIndicatorView.swift */; };
34BECE2E1F7ABCE000D7438D /* GifPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BECE2D1F7ABCE000D7438D /* GifPickerViewController.swift */; };
34BECE301F7ABCF800D7438D /* GifPickerLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34BECE2F1F7ABCF800D7438D /* GifPickerLayout.swift */; };
@ -128,7 +127,6 @@
7B8C44C528B49DDA00FBE25F /* NewConversationVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B8C44C428B49DDA00FBE25F /* NewConversationVC.swift */; };
7B8D5FC428332600008324D9 /* VisibleMessage+Reaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B8D5FC328332600008324D9 /* VisibleMessage+Reaction.swift */; };
7B93D06A27CF173D00811CB6 /* MessageRequestsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B93D06927CF173D00811CB6 /* MessageRequestsViewController.swift */; };
7B93D07027CF194000811CB6 /* ConfigurationMessage+Convenience.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B93D06E27CF194000811CB6 /* ConfigurationMessage+Convenience.swift */; };
7B93D07127CF194000811CB6 /* MessageRequestResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B93D06F27CF194000811CB6 /* MessageRequestResponse.swift */; };
7B93D07727CF1A8A00811CB6 /* MockDataGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B93D07527CF1A8900811CB6 /* MockDataGenerator.swift */; };
7B9F71C928470667006DFE7B /* ReactionListSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7B9F71C828470667006DFE7B /* ReactionListSheet.swift */; };
@ -314,27 +312,13 @@
C33FDC29255A581F00E217F9 /* ReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA6F255A57FA00E217F9 /* ReachabilityManager.swift */; };
C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8B255A57FD00E217F9 /* AppVersion.m */; };
C33FDC58255A582000E217F9 /* ReverseDispatchQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */; };
C33FDC78255A582000E217F9 /* TSConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDABE255A580100E217F9 /* TSConstants.m */; };
C33FDC98255A582000E217F9 /* SwiftSingletons.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDADE255A580400E217F9 /* SwiftSingletons.swift */; };
C33FDC9A255A582000E217F9 /* ByteParser.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAE0255A580400E217F9 /* ByteParser.m */; };
C33FDCD1255A582000E217F9 /* FunctionalUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB17255A580800E217F9 /* FunctionalUtil.m */; };
C33FDCFA255A582000E217F9 /* SignalIOSProto.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB40255A580C00E217F9 /* SignalIOSProto.swift */; };
C33FDD03255A582000E217F9 /* WeakTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB49255A580C00E217F9 /* WeakTimer.swift */; };
C33FDD06255A582000E217F9 /* AppVersion.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB4C255A580D00E217F9 /* AppVersion.h */; settings = {ATTRIBUTES = (Public, ); }; };
C33FDD23255A582000E217F9 /* FeatureFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB69255A580F00E217F9 /* FeatureFlags.swift */; };
C33FDD32255A582000E217F9 /* OWSOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB78255A581000E217F9 /* OWSOperation.m */; };
C33FDD3A255A582000E217F9 /* Notification+Loki.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB80255A581100E217F9 /* Notification+Loki.swift */; };
C33FDD49255A582000E217F9 /* ParamParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB8F255A581200E217F9 /* ParamParser.swift */; };
C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBA1255A581400E217F9 /* OWSOperation.h */; settings = {ATTRIBUTES = (Public, ); }; };
C33FDD6E255A582000E217F9 /* NSURLSessionDataTask+StatusCode.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB4255A581600E217F9 /* NSURLSessionDataTask+StatusCode.m */; };
C33FDD8D255A582000E217F9 /* OWSSignalAddress.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */; };
C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */; };
C33FDDB0255A582000E217F9 /* NSURLSessionDataTask+StatusCode.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */; settings = {ATTRIBUTES = (Public, ); }; };
C33FDDB3255A582000E217F9 /* OWSError.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBF9255A581C00E217F9 /* OWSError.h */; settings = {ATTRIBUTES = (Public, ); }; };
C33FDDBD255A582000E217F9 /* ByteParser.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC03255A581D00E217F9 /* ByteParser.h */; settings = {ATTRIBUTES = (Public, ); }; };
C33FDDC5255A582000E217F9 /* OWSError.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDC0B255A581D00E217F9 /* OWSError.m */; };
C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC12255A581E00E217F9 /* TSConstants.h */; settings = {ATTRIBUTES = (Public, ); }; };
C33FDDD0255A582000E217F9 /* FunctionalUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDC16255A581E00E217F9 /* FunctionalUtil.h */; settings = {ATTRIBUTES = (Public, ); }; };
C3402FE52559036600EA6424 /* SessionUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C331FF1B2558F9D300070591 /* SessionUIKit.framework */; };
C3471ECB2555356A00297E91 /* MessageSender+Encryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3471ECA2555356A00297E91 /* MessageSender+Encryption.swift */; };
C3471F4C25553AB000297E91 /* MessageReceiver+Decryption.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3471F4B25553AB000297E91 /* MessageReceiver+Decryption.swift */; };
@ -531,6 +515,9 @@
FD1A94FB2900D1C2000D73D3 /* PersistableRecord+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1A94FA2900D1C2000D73D3 /* PersistableRecord+Utilities.swift */; };
FD1A94FE2900D2EA000D73D3 /* PersistableRecordUtilitiesSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1A94FD2900D2EA000D73D3 /* PersistableRecordUtilitiesSpec.swift */; };
FD1C98E4282E3C5B00B76F9E /* UINavigationBar+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1C98E3282E3C5B00B76F9E /* UINavigationBar+Utilities.swift */; };
FD1D732A2A85AA2000E3F410 /* Setting+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1D73292A85AA2000E3F410 /* Setting+Utilities.swift */; };
FD1D732E2A86114600E3F410 /* _015_BlockCommunityMessageRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1D732D2A86114600E3F410 /* _015_BlockCommunityMessageRequests.swift */; };
FD1F9C9F2A862BE60050F671 /* MigrationRequirement.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD1F9C9E2A862BE60050F671 /* MigrationRequirement.swift */; };
FD23CE1B2A651E6D0000B97C /* NetworkType.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE1A2A651E6D0000B97C /* NetworkType.swift */; };
FD23CE1F2A65269C0000B97C /* Crypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE1E2A65269C0000B97C /* Crypto.swift */; };
FD23CE222A661D000000B97C /* OpenGroupAPI+Crypto.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD23CE212A661D000000B97C /* OpenGroupAPI+Crypto.swift */; };
@ -648,11 +635,12 @@
FD52090928B59411006098F6 /* ScreenLockUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52090828B59411006098F6 /* ScreenLockUI.swift */; };
FD52090B28B59BB4006098F6 /* ScreenLockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52090A28B59BB4006098F6 /* ScreenLockViewController.swift */; };
FD559DF52A7368CB00C7C62A /* DispatchQueue+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD559DF42A7368CB00C7C62A /* DispatchQueue+Utilities.swift */; };
FD5931A72A8DA5DA0040147D /* SQLInterpolation+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5931A62A8DA5DA0040147D /* SQLInterpolation+Utilities.swift */; };
FD5931AB2A8DCB0A0040147D /* ScopeAdapter+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5931AA2A8DCB0A0040147D /* ScopeAdapter+Utilities.swift */; };
FD5C72F7284F0E560029977D /* MessageReceiver+ReadReceipts.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C72F6284F0E560029977D /* MessageReceiver+ReadReceipts.swift */; };
FD5C72F9284F0E880029977D /* MessageReceiver+TypingIndicators.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C72F8284F0E880029977D /* MessageReceiver+TypingIndicators.swift */; };
FD5C72FB284F0EA10029977D /* MessageReceiver+DataExtractionNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C72FA284F0EA10029977D /* MessageReceiver+DataExtractionNotification.swift */; };
FD5C72FD284F0EC90029977D /* MessageReceiver+ExpirationTimers.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C72FC284F0EC90029977D /* MessageReceiver+ExpirationTimers.swift */; };
FD5C72FF284F0F120029977D /* MessageReceiver+ConfigurationMessages.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C72FE284F0F120029977D /* MessageReceiver+ConfigurationMessages.swift */; };
FD5C7301284F0F7A0029977D /* MessageReceiver+UnsendRequests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C7300284F0F7A0029977D /* MessageReceiver+UnsendRequests.swift */; };
FD5C7303284F0FA50029977D /* MessageReceiver+Calls.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C7302284F0FA50029977D /* MessageReceiver+Calls.swift */; };
FD5C7305284F0FF30029977D /* MessageReceiver+VisibleMessages.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C7304284F0FF30029977D /* MessageReceiver+VisibleMessages.swift */; };
@ -662,6 +650,7 @@
FD6A7A692818BE7300035AC1 /* RetrieveDefaultOpenGroupRoomsJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6A7A682818BE7300035AC1 /* RetrieveDefaultOpenGroupRoomsJob.swift */; };
FD6A7A6B2818C17C00035AC1 /* UpdateProfilePictureJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6A7A6A2818C17C00035AC1 /* UpdateProfilePictureJob.swift */; };
FD6A7A6D2818C61500035AC1 /* _002_SetupStandardJobs.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6A7A6C2818C61500035AC1 /* _002_SetupStandardJobs.swift */; };
FD6E4C8A2A1AEE4700C7C243 /* LegacyUnsubscribeRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6E4C892A1AEE4700C7C243 /* LegacyUnsubscribeRequest.swift */; };
FD705A92278D051200F16121 /* ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD705A91278D051200F16121 /* ReusableView.swift */; };
FD7115EB28C5D78E00B47552 /* ThreadSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD7115EA28C5D78E00B47552 /* ThreadSettingsViewModel.swift */; };
FD7115F228C6CB3900B47552 /* _010_AddThreadIdToFTS.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD7115F128C6CB3900B47552 /* _010_AddThreadIdToFTS.swift */; };
@ -771,6 +760,15 @@
FDBB25E12983909300F1508E /* ConfigConvoInfoVolatileSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDBB25E02983909300F1508E /* ConfigConvoInfoVolatileSpec.swift */; };
FDBB25E32988B13800F1508E /* _004_AddJobPriority.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDBB25E22988B13800F1508E /* _004_AddJobPriority.swift */; };
FDBB25E72988BBBE00F1508E /* UIContextualAction+Theming.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDBB25E62988BBBD00F1508E /* UIContextualAction+Theming.swift */; };
FDC13D472A16E4CA007267C7 /* SubscribeRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC13D462A16E4CA007267C7 /* SubscribeRequest.swift */; };
FDC13D492A16EC20007267C7 /* Service.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC13D482A16EC20007267C7 /* Service.swift */; };
FDC13D4B2A16ECBA007267C7 /* SubscribeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC13D4A2A16ECBA007267C7 /* SubscribeResponse.swift */; };
FDC13D502A16EE50007267C7 /* PushNotificationAPIEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC13D4F2A16EE50007267C7 /* PushNotificationAPIEndpoint.swift */; };
FDC13D522A16F22E007267C7 /* PushNotificationAPIRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC13D512A16F22E007267C7 /* PushNotificationAPIRequest.swift */; };
FDC13D542A16FF29007267C7 /* LegacyGroupRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC13D532A16FF29007267C7 /* LegacyGroupRequest.swift */; };
FDC13D562A171FE4007267C7 /* UnsubscribeRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC13D552A171FE4007267C7 /* UnsubscribeRequest.swift */; };
FDC13D582A17207D007267C7 /* UnsubscribeResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC13D572A17207D007267C7 /* UnsubscribeResponse.swift */; };
FDC13D5A2A1721C5007267C7 /* LegacyNotifyRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC13D592A1721C5007267C7 /* LegacyNotifyRequest.swift */; };
FDC2908727D7047F005DAE71 /* RoomSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC2908627D7047F005DAE71 /* RoomSpec.swift */; };
FDC2908927D70656005DAE71 /* RoomPollInfoSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC2908827D70656005DAE71 /* RoomPollInfoSpec.swift */; };
FDC2908B27D707F3005DAE71 /* SendMessageRequestSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC2908A27D707F3005DAE71 /* SendMessageRequestSpec.swift */; };
@ -788,7 +786,7 @@
FDC4380927B31D4E00C60D73 /* OpenGroupAPIError.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4380827B31D4E00C60D73 /* OpenGroupAPIError.swift */; };
FDC4381727B32EC700C60D73 /* Personalization.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4381627B32EC700C60D73 /* Personalization.swift */; };
FDC4382027B36ADC00C60D73 /* SOGSEndpoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4381F27B36ADC00C60D73 /* SOGSEndpoint.swift */; };
FDC4382F27B383AF00C60D73 /* PushServerResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4382E27B383AF00C60D73 /* PushServerResponse.swift */; };
FDC4382F27B383AF00C60D73 /* LegacyPushServerResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4382E27B383AF00C60D73 /* LegacyPushServerResponse.swift */; };
FDC4383827B3863200C60D73 /* VersionResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4383727B3863200C60D73 /* VersionResponse.swift */; };
FDC4385D27B4C18900C60D73 /* Room.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4385C27B4C18900C60D73 /* Room.swift */; };
FDC4385F27B4C4A200C60D73 /* PinnedMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC4385E27B4C4A200C60D73 /* PinnedMessage.swift */; };
@ -811,11 +809,13 @@
FDC438CD27BC641200C60D73 /* Set+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC438CC27BC641200C60D73 /* Set+Utilities.swift */; };
FDC6D6F32860607300B04575 /* Environment.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF0B7542807C4BB004C14C5 /* Environment.swift */; };
FDC6D7602862B3F600B04575 /* Dependencies.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC6D75F2862B3F600B04575 /* Dependencies.swift */; };
FDCD2E032A41294E00964D6A /* LegacyGroupOnlyRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDCD2E022A41294E00964D6A /* LegacyGroupOnlyRequest.swift */; };
FDCDB8DE2810F73B00352A0C /* Differentiable+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDCDB8DD2810F73B00352A0C /* Differentiable+Utilities.swift */; };
FDCDB8E02811007F00352A0C /* HomeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDCDB8DF2811007F00352A0C /* HomeViewModel.swift */; };
FDD2506E283711D600198BDA /* DifferenceKit+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD2506D283711D600198BDA /* DifferenceKit+Utilities.swift */; };
FDD250702837199200198BDA /* GarbageCollectionJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD2506F2837199200198BDA /* GarbageCollectionJob.swift */; };
FDD250722837234B00198BDA /* MediaGalleryNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD250712837234B00198BDA /* MediaGalleryNavigationController.swift */; };
FDD82C3F2A205D0A00425F05 /* ProcessResult.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDD82C3E2A205D0A00425F05 /* ProcessResult.swift */; };
FDDC08F229A300E800BF9681 /* LibSessionTypeConversionUtilitiesSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDDC08F129A300E800BF9681 /* LibSessionTypeConversionUtilitiesSpec.swift */; };
FDDCBDA829E776BF00303C38 /* seed2-2023-2y.crt in Resources */ = {isa = PBXBuildFile; fileRef = FDDCBDA229E776BF00303C38 /* seed2-2023-2y.crt */; };
FDDCBDA929E776BF00303C38 /* seed1-2023-2y.crt in Resources */ = {isa = PBXBuildFile; fileRef = FDDCBDA329E776BF00303C38 /* seed1-2023-2y.crt */; };
@ -825,6 +825,7 @@
FDDCBDAD29E776BF00303C38 /* seed3-2023-2y.der in Resources */ = {isa = PBXBuildFile; fileRef = FDDCBDA729E776BF00303C38 /* seed3-2023-2y.der */; };
FDDF074429C3E3D000E5E8B5 /* FetchRequest+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDDF074329C3E3D000E5E8B5 /* FetchRequest+Utilities.swift */; };
FDDF074A29DAB36900E5E8B5 /* JobRunnerSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDDF074929DAB36900E5E8B5 /* JobRunnerSpec.swift */; };
FDE125232A837E4E002DA685 /* MainAppContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE125222A837E4E002DA685 /* MainAppContext.swift */; };
FDE658A129418C7900A33BC1 /* CryptoKit+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE658A029418C7900A33BC1 /* CryptoKit+Utilities.swift */; };
FDE658A329418E2F00A33BC1 /* KeyPair.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE658A229418E2F00A33BC1 /* KeyPair.swift */; };
FDE6E99829F8E63A00F93C5D /* Accessibility.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDE6E99729F8E63A00F93C5D /* Accessibility.swift */; };
@ -909,6 +910,9 @@
FDF848F329413DB0007DCAE5 /* ImagePickerHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF848F229413DB0007DCAE5 /* ImagePickerHandler.swift */; };
FDF848F529413EEC007DCAE5 /* SessionCell+Styling.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF848F429413EEC007DCAE5 /* SessionCell+Styling.swift */; };
FDF848F729414477007DCAE5 /* CurrentUserPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDF848F629414477007DCAE5 /* CurrentUserPoller.swift */; };
FDFBB74B2A1EFF4900CA7350 /* Bencode.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDFBB74A2A1EFF4900CA7350 /* Bencode.swift */; };
FDFBB74D2A1F3C4E00CA7350 /* NotificationMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDFBB74C2A1F3C4E00CA7350 /* NotificationMetadata.swift */; };
FDFBB7542A2023EB00CA7350 /* BencodeSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDFBB7532A2023EB00CA7350 /* BencodeSpec.swift */; };
FDFC4D9A29F0C51500992FB6 /* String+Trimming.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D22553860900C340D1 /* String+Trimming.swift */; };
FDFD645927F26C6800808CA1 /* Array+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5D12553860800C340D1 /* Array+Utilities.swift */; };
FDFD645D27F273F300808CA1 /* MockGeneralCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDFD645C27F273F300808CA1 /* MockGeneralCache.swift */; };
@ -1114,8 +1118,6 @@
3496955F21A2FC8100DCFE74 /* CloudKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CloudKit.framework; path = System/Library/Frameworks/CloudKit.framework; sourceTree = SDKROOT; };
34A6C27F21E503E600B5B12E /* OWSImagePickerController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSImagePickerController.swift; sourceTree = "<group>"; };
34A8B3502190A40E00218A25 /* MediaAlbumView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaAlbumView.swift; sourceTree = "<group>"; };
34B0796B1FCF46B000E248C2 /* MainAppContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainAppContext.m; sourceTree = "<group>"; };
34B0796C1FCF46B000E248C2 /* MainAppContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainAppContext.h; sourceTree = "<group>"; };
34B0796E1FD07B1E00E248C2 /* SignalShareExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SignalShareExtension.entitlements; sourceTree = "<group>"; };
34B6A902218B3F62007C4606 /* TypingIndicatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TypingIndicatorView.swift; sourceTree = "<group>"; };
34BECE2D1F7ABCE000D7438D /* GifPickerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GifPickerViewController.swift; sourceTree = "<group>"; };
@ -1237,7 +1239,6 @@
7B8C44C428B49DDA00FBE25F /* NewConversationVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewConversationVC.swift; sourceTree = "<group>"; };
7B8D5FC328332600008324D9 /* VisibleMessage+Reaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+Reaction.swift"; sourceTree = "<group>"; };
7B93D06927CF173D00811CB6 /* MessageRequestsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRequestsViewController.swift; sourceTree = "<group>"; };
7B93D06E27CF194000811CB6 /* ConfigurationMessage+Convenience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ConfigurationMessage+Convenience.swift"; sourceTree = "<group>"; };
7B93D06F27CF194000811CB6 /* MessageRequestResponse.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MessageRequestResponse.swift; sourceTree = "<group>"; };
7B93D07527CF1A8900811CB6 /* MockDataGenerator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockDataGenerator.swift; sourceTree = "<group>"; };
7B9F71C828470667006DFE7B /* ReactionListSheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReactionListSheet.swift; sourceTree = "<group>"; };
@ -1418,9 +1419,7 @@
C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSFileSystem.m; sourceTree = "<group>"; };
C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReverseDispatchQueue.swift; sourceTree = "<group>"; };
C33FDAA8255A57FF00E217F9 /* BuildConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BuildConfiguration.swift; sourceTree = "<group>"; };
C33FDABE255A580100E217F9 /* TSConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSConstants.m; sourceTree = "<group>"; };
C33FDADE255A580400E217F9 /* SwiftSingletons.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SwiftSingletons.swift; sourceTree = "<group>"; };
C33FDAE0255A580400E217F9 /* ByteParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ByteParser.m; sourceTree = "<group>"; };
C33FDAEF255A580500E217F9 /* NSData+Image.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSData+Image.m"; sourceTree = "<group>"; };
C33FDAF1255A580500E217F9 /* ThumbnailService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThumbnailService.swift; sourceTree = "<group>"; };
C33FDAF2255A580500E217F9 /* ProxiedContentDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ProxiedContentDownloader.swift; sourceTree = "<group>"; };
@ -1428,7 +1427,6 @@
C33FDAFD255A580600E217F9 /* LRUCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LRUCache.swift; sourceTree = "<group>"; };
C33FDB01255A580700E217F9 /* AppReadiness.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppReadiness.h; sourceTree = "<group>"; };
C33FDB14255A580800E217F9 /* OWSMath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMath.h; sourceTree = "<group>"; };
C33FDB17255A580800E217F9 /* FunctionalUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FunctionalUtil.m; sourceTree = "<group>"; };
C33FDB1C255A580900E217F9 /* UIImage+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+OWS.h"; sourceTree = "<group>"; };
C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSMediaUtils.swift; sourceTree = "<group>"; };
C33FDB29255A580A00E217F9 /* NSData+Image.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSData+Image.h"; sourceTree = "<group>"; };
@ -1436,7 +1434,6 @@
C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackgroundTask.h; sourceTree = "<group>"; };
C33FDB3A255A580B00E217F9 /* Poller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Poller.swift; sourceTree = "<group>"; };
C33FDB3F255A580C00E217F9 /* String+SSK.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "String+SSK.swift"; sourceTree = "<group>"; };
C33FDB40255A580C00E217F9 /* SignalIOSProto.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalIOSProto.swift; sourceTree = "<group>"; };
C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MIMETypeUtil.m; sourceTree = "<group>"; };
C33FDB49255A580C00E217F9 /* WeakTimer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = WeakTimer.swift; sourceTree = "<group>"; };
C33FDB4C255A580D00E217F9 /* AppVersion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppVersion.h; sourceTree = "<group>"; };
@ -1447,27 +1444,17 @@
C33FDB6B255A580F00E217F9 /* SNUserDefaults.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SNUserDefaults.swift; sourceTree = "<group>"; };
C33FDB75255A581000E217F9 /* AppReadiness.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppReadiness.m; sourceTree = "<group>"; };
C33FDB77255A581000E217F9 /* NSUserDefaults+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSUserDefaults+OWS.m"; sourceTree = "<group>"; };
C33FDB78255A581000E217F9 /* OWSOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSOperation.m; sourceTree = "<group>"; };
C33FDB80255A581100E217F9 /* Notification+Loki.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Notification+Loki.swift"; sourceTree = "<group>"; };
C33FDB81255A581100E217F9 /* UIImage+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+OWS.m"; sourceTree = "<group>"; };
C33FDB85255A581100E217F9 /* AppContext.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppContext.m; sourceTree = "<group>"; };
C33FDB8A255A581200E217F9 /* AppContext.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppContext.h; sourceTree = "<group>"; };
C33FDB8F255A581200E217F9 /* ParamParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ParamParser.swift; sourceTree = "<group>"; };
C33FDBA1255A581400E217F9 /* OWSOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSOperation.h; sourceTree = "<group>"; };
C33FDBA8255A581500E217F9 /* LinkPreviewDraft.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LinkPreviewDraft.swift; sourceTree = "<group>"; };
C33FDBAB255A581500E217F9 /* OWSFileSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSFileSystem.h; sourceTree = "<group>"; };
C33FDBB4255A581600E217F9 /* NSURLSessionDataTask+StatusCode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSURLSessionDataTask+StatusCode.m"; sourceTree = "<group>"; };
C33FDBB6255A581600E217F9 /* DataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DataSource.m; sourceTree = "<group>"; };
C33FDBBC255A581600E217F9 /* SSKKeychainStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKKeychainStorage.swift; sourceTree = "<group>"; };
C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSSignalAddress.swift; sourceTree = "<group>"; };
C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SignalIOS.pb.swift; sourceTree = "<group>"; };
C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushNotificationAPI.swift; sourceTree = "<group>"; };
C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSURLSessionDataTask+StatusCode.h"; sourceTree = "<group>"; };
C33FDBF9255A581C00E217F9 /* OWSError.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSError.h; sourceTree = "<group>"; };
C33FDC03255A581D00E217F9 /* ByteParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ByteParser.h; sourceTree = "<group>"; };
C33FDC0B255A581D00E217F9 /* OWSError.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSError.m; sourceTree = "<group>"; };
C33FDC12255A581E00E217F9 /* TSConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSConstants.h; sourceTree = "<group>"; };
C33FDC16255A581E00E217F9 /* FunctionalUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FunctionalUtil.h; sourceTree = "<group>"; };
C33FDC1B255A581F00E217F9 /* OWSBackgroundTask.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBackgroundTask.m; sourceTree = "<group>"; };
C3471ECA2555356A00297E91 /* MessageSender+Encryption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageSender+Encryption.swift"; sourceTree = "<group>"; };
C3471F4B25553AB000297E91 /* MessageReceiver+Decryption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+Decryption.swift"; sourceTree = "<group>"; };
@ -1689,6 +1676,9 @@
FD1A94FA2900D1C2000D73D3 /* PersistableRecord+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PersistableRecord+Utilities.swift"; sourceTree = "<group>"; };
FD1A94FD2900D2EA000D73D3 /* PersistableRecordUtilitiesSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistableRecordUtilitiesSpec.swift; sourceTree = "<group>"; };
FD1C98E3282E3C5B00B76F9E /* UINavigationBar+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationBar+Utilities.swift"; sourceTree = "<group>"; };
FD1D73292A85AA2000E3F410 /* Setting+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Setting+Utilities.swift"; sourceTree = "<group>"; };
FD1D732D2A86114600E3F410 /* _015_BlockCommunityMessageRequests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _015_BlockCommunityMessageRequests.swift; sourceTree = "<group>"; };
FD1F9C9E2A862BE60050F671 /* MigrationRequirement.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MigrationRequirement.swift; sourceTree = "<group>"; };
FD23CE1A2A651E6D0000B97C /* NetworkType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkType.swift; sourceTree = "<group>"; };
FD23CE1E2A65269C0000B97C /* Crypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Crypto.swift; sourceTree = "<group>"; };
FD23CE212A661D000000B97C /* OpenGroupAPI+Crypto.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OpenGroupAPI+Crypto.swift"; sourceTree = "<group>"; };
@ -1767,11 +1757,12 @@
FD52090828B59411006098F6 /* ScreenLockUI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenLockUI.swift; sourceTree = "<group>"; };
FD52090A28B59BB4006098F6 /* ScreenLockViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenLockViewController.swift; sourceTree = "<group>"; };
FD559DF42A7368CB00C7C62A /* DispatchQueue+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DispatchQueue+Utilities.swift"; sourceTree = "<group>"; };
FD5931A62A8DA5DA0040147D /* SQLInterpolation+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SQLInterpolation+Utilities.swift"; sourceTree = "<group>"; };
FD5931AA2A8DCB0A0040147D /* ScopeAdapter+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ScopeAdapter+Utilities.swift"; sourceTree = "<group>"; };
FD5C72F6284F0E560029977D /* MessageReceiver+ReadReceipts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+ReadReceipts.swift"; sourceTree = "<group>"; };
FD5C72F8284F0E880029977D /* MessageReceiver+TypingIndicators.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+TypingIndicators.swift"; sourceTree = "<group>"; };
FD5C72FA284F0EA10029977D /* MessageReceiver+DataExtractionNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+DataExtractionNotification.swift"; sourceTree = "<group>"; };
FD5C72FC284F0EC90029977D /* MessageReceiver+ExpirationTimers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+ExpirationTimers.swift"; sourceTree = "<group>"; };
FD5C72FE284F0F120029977D /* MessageReceiver+ConfigurationMessages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+ConfigurationMessages.swift"; sourceTree = "<group>"; };
FD5C7300284F0F7A0029977D /* MessageReceiver+UnsendRequests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+UnsendRequests.swift"; sourceTree = "<group>"; };
FD5C7302284F0FA50029977D /* MessageReceiver+Calls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+Calls.swift"; sourceTree = "<group>"; };
FD5C7304284F0FF30029977D /* MessageReceiver+VisibleMessages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+VisibleMessages.swift"; sourceTree = "<group>"; };
@ -1782,6 +1773,7 @@
FD6A7A682818BE7300035AC1 /* RetrieveDefaultOpenGroupRoomsJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RetrieveDefaultOpenGroupRoomsJob.swift; sourceTree = "<group>"; };
FD6A7A6A2818C17C00035AC1 /* UpdateProfilePictureJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateProfilePictureJob.swift; sourceTree = "<group>"; };
FD6A7A6C2818C61500035AC1 /* _002_SetupStandardJobs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _002_SetupStandardJobs.swift; sourceTree = "<group>"; };
FD6E4C892A1AEE4700C7C243 /* LegacyUnsubscribeRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyUnsubscribeRequest.swift; sourceTree = "<group>"; };
FD705A91278D051200F16121 /* ReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReusableView.swift; sourceTree = "<group>"; };
FD7115EA28C5D78E00B47552 /* ThreadSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadSettingsViewModel.swift; sourceTree = "<group>"; };
FD7115EF28C5D7DE00B47552 /* SessionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SessionHeaderView.swift; sourceTree = "<group>"; };
@ -1881,6 +1873,15 @@
FDBB25E02983909300F1508E /* ConfigConvoInfoVolatileSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigConvoInfoVolatileSpec.swift; sourceTree = "<group>"; };
FDBB25E22988B13800F1508E /* _004_AddJobPriority.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _004_AddJobPriority.swift; sourceTree = "<group>"; };
FDBB25E62988BBBD00F1508E /* UIContextualAction+Theming.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIContextualAction+Theming.swift"; sourceTree = "<group>"; };
FDC13D462A16E4CA007267C7 /* SubscribeRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscribeRequest.swift; sourceTree = "<group>"; };
FDC13D482A16EC20007267C7 /* Service.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Service.swift; sourceTree = "<group>"; };
FDC13D4A2A16ECBA007267C7 /* SubscribeResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubscribeResponse.swift; sourceTree = "<group>"; };
FDC13D4F2A16EE50007267C7 /* PushNotificationAPIEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushNotificationAPIEndpoint.swift; sourceTree = "<group>"; };
FDC13D512A16F22E007267C7 /* PushNotificationAPIRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushNotificationAPIRequest.swift; sourceTree = "<group>"; };
FDC13D532A16FF29007267C7 /* LegacyGroupRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyGroupRequest.swift; sourceTree = "<group>"; };
FDC13D552A171FE4007267C7 /* UnsubscribeRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsubscribeRequest.swift; sourceTree = "<group>"; };
FDC13D572A17207D007267C7 /* UnsubscribeResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnsubscribeResponse.swift; sourceTree = "<group>"; };
FDC13D592A1721C5007267C7 /* LegacyNotifyRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyNotifyRequest.swift; sourceTree = "<group>"; };
FDC2908627D7047F005DAE71 /* RoomSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomSpec.swift; sourceTree = "<group>"; };
FDC2908827D70656005DAE71 /* RoomPollInfoSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RoomPollInfoSpec.swift; sourceTree = "<group>"; };
FDC2908A27D707F3005DAE71 /* SendMessageRequestSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendMessageRequestSpec.swift; sourceTree = "<group>"; };
@ -1897,7 +1898,7 @@
FDC4380827B31D4E00C60D73 /* OpenGroupAPIError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupAPIError.swift; sourceTree = "<group>"; };
FDC4381627B32EC700C60D73 /* Personalization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Personalization.swift; sourceTree = "<group>"; };
FDC4381F27B36ADC00C60D73 /* SOGSEndpoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SOGSEndpoint.swift; sourceTree = "<group>"; };
FDC4382E27B383AF00C60D73 /* PushServerResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PushServerResponse.swift; sourceTree = "<group>"; };
FDC4382E27B383AF00C60D73 /* LegacyPushServerResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyPushServerResponse.swift; sourceTree = "<group>"; };
FDC4383727B3863200C60D73 /* VersionResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VersionResponse.swift; sourceTree = "<group>"; };
FDC4383D27B4708600C60D73 /* Atomic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = "<group>"; };
FDC4385C27B4C18900C60D73 /* Room.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Room.swift; sourceTree = "<group>"; };
@ -1921,11 +1922,13 @@
FDC438CA27BB7DB100C60D73 /* UpdateMessageRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpdateMessageRequest.swift; sourceTree = "<group>"; };
FDC438CC27BC641200C60D73 /* Set+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Set+Utilities.swift"; sourceTree = "<group>"; };
FDC6D75F2862B3F600B04575 /* Dependencies.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Dependencies.swift; sourceTree = "<group>"; };
FDCD2E022A41294E00964D6A /* LegacyGroupOnlyRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacyGroupOnlyRequest.swift; sourceTree = "<group>"; };
FDCDB8DD2810F73B00352A0C /* Differentiable+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Differentiable+Utilities.swift"; sourceTree = "<group>"; };
FDCDB8DF2811007F00352A0C /* HomeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HomeViewModel.swift; sourceTree = "<group>"; };
FDD2506D283711D600198BDA /* DifferenceKit+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DifferenceKit+Utilities.swift"; sourceTree = "<group>"; };
FDD2506F2837199200198BDA /* GarbageCollectionJob.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GarbageCollectionJob.swift; sourceTree = "<group>"; };
FDD250712837234B00198BDA /* MediaGalleryNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaGalleryNavigationController.swift; sourceTree = "<group>"; };
FDD82C3E2A205D0A00425F05 /* ProcessResult.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProcessResult.swift; sourceTree = "<group>"; };
FDDC08F129A300E800BF9681 /* LibSessionTypeConversionUtilitiesSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LibSessionTypeConversionUtilitiesSpec.swift; sourceTree = "<group>"; };
FDDCBDA229E776BF00303C38 /* seed2-2023-2y.crt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "seed2-2023-2y.crt"; sourceTree = "<group>"; };
FDDCBDA329E776BF00303C38 /* seed1-2023-2y.crt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = "seed1-2023-2y.crt"; sourceTree = "<group>"; };
@ -1935,6 +1938,7 @@
FDDCBDA729E776BF00303C38 /* seed3-2023-2y.der */ = {isa = PBXFileReference; lastKnownFileType = file; path = "seed3-2023-2y.der"; sourceTree = "<group>"; };
FDDF074329C3E3D000E5E8B5 /* FetchRequest+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FetchRequest+Utilities.swift"; sourceTree = "<group>"; };
FDDF074929DAB36900E5E8B5 /* JobRunnerSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JobRunnerSpec.swift; sourceTree = "<group>"; };
FDE125222A837E4E002DA685 /* MainAppContext.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainAppContext.swift; sourceTree = "<group>"; };
FDE658A029418C7900A33BC1 /* CryptoKit+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CryptoKit+Utilities.swift"; sourceTree = "<group>"; };
FDE658A229418E2F00A33BC1 /* KeyPair.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyPair.swift; sourceTree = "<group>"; };
FDE6E99729F8E63A00F93C5D /* Accessibility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Accessibility.swift; sourceTree = "<group>"; };
@ -2022,6 +2026,9 @@
FDF848F229413DB0007DCAE5 /* ImagePickerHandler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ImagePickerHandler.swift; sourceTree = "<group>"; };
FDF848F429413EEC007DCAE5 /* SessionCell+Styling.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "SessionCell+Styling.swift"; sourceTree = "<group>"; };
FDF848F629414477007DCAE5 /* CurrentUserPoller.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CurrentUserPoller.swift; sourceTree = "<group>"; };
FDFBB74A2A1EFF4900CA7350 /* Bencode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Bencode.swift; sourceTree = "<group>"; };
FDFBB74C2A1F3C4E00CA7350 /* NotificationMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationMetadata.swift; sourceTree = "<group>"; };
FDFBB7532A2023EB00CA7350 /* BencodeSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BencodeSpec.swift; sourceTree = "<group>"; };
FDFD645A27F26D4600808CA1 /* Data+Utilities.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+Utilities.swift"; sourceTree = "<group>"; };
FDFD645C27F273F300808CA1 /* MockGeneralCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockGeneralCache.swift; sourceTree = "<group>"; };
FDFDE123282D04F20098B17F /* MediaDismissAnimationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MediaDismissAnimationController.swift; sourceTree = "<group>"; };
@ -2730,7 +2737,6 @@
C34A977325A3E34A00852C71 /* ClosedGroupControlMessage.swift */,
FD8ECF8A2935DB4B00C0D1BB /* SharedConfigMessage.swift */,
C3DA9C0625AE7396008F7C7E /* ConfigurationMessage.swift */,
7B93D06E27CF194000811CB6 /* ConfigurationMessage+Convenience.swift */,
B8F5F60225EDE16F003BF8D4 /* DataExtractionNotification.swift */,
C300A5E62554B07300555489 /* ExpirationTimerUpdate.swift */,
7B93D06F27CF194000811CB6 /* MessageRequestResponse.swift */,
@ -3126,6 +3132,7 @@
C379DC6825672B5E0002D4EB /* Notifications */ = {
isa = PBXGroup;
children = (
FDC13D4E2A16EE41007267C7 /* Types */,
FDC4382D27B383A600C60D73 /* Models */,
FDF0B7502807BA56004C14C5 /* NotificationsProtocol.swift */,
C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */,
@ -3368,34 +3375,20 @@
FD71161D28D9772700B47552 /* UIViewController+OWS.swift */,
C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */,
C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */,
C33FDBF9255A581C00E217F9 /* OWSError.h */,
C33FDC0B255A581D00E217F9 /* OWSError.m */,
C33FDBA1255A581400E217F9 /* OWSOperation.h */,
C33FDB78255A581000E217F9 /* OWSOperation.m */,
C33FDBD3255A581800E217F9 /* OWSSignalAddress.swift */,
C33FDA6F255A57FA00E217F9 /* ReachabilityManager.swift */,
C33FDBD8255A581900E217F9 /* SignalIOS.pb.swift */,
C33FDB40255A580C00E217F9 /* SignalIOSProto.swift */,
C33FDC12255A581E00E217F9 /* TSConstants.h */,
C33FDABE255A580100E217F9 /* TSConstants.m */,
C33FDB4C255A580D00E217F9 /* AppVersion.h */,
C33FDA8B255A57FD00E217F9 /* AppVersion.m */,
C38EF3E4255B6DF4007E1867 /* CommonStrings.swift */,
C38EF304255B6DBE007E1867 /* ImageCache.swift */,
C38EF2F2255B6DBC007E1867 /* Searcher.swift */,
C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */,
C33FDA8B255A57FD00E217F9 /* AppVersion.m */,
C33FDB69255A580F00E217F9 /* FeatureFlags.swift */,
C33FDB80255A581100E217F9 /* Notification+Loki.swift */,
C33FDC16255A581E00E217F9 /* FunctionalUtil.h */,
C33FDB17255A580800E217F9 /* FunctionalUtil.m */,
C33FDB8F255A581200E217F9 /* ParamParser.swift */,
C33FDADE255A580400E217F9 /* SwiftSingletons.swift */,
C33FDB49255A580C00E217F9 /* WeakTimer.swift */,
C33FDA9E255A57FF00E217F9 /* ReverseDispatchQueue.swift */,
C33FDBF6255A581C00E217F9 /* NSURLSessionDataTask+StatusCode.h */,
C33FDBB4255A581600E217F9 /* NSURLSessionDataTask+StatusCode.m */,
C33FDC03255A581D00E217F9 /* ByteParser.h */,
C33FDAE0255A580400E217F9 /* ByteParser.m */,
C38EF3DD255B6DF1007E1867 /* UIAlertController+OWS.swift */,
C38EF241255B6D67007E1867 /* Collection+OWS.swift */,
C38EF3AE255B6DE5007E1867 /* OrderedDictionary.swift */,
@ -3425,8 +3418,7 @@
34330A581E7875FB00DF2FB9 /* Fonts */,
B66DBF4919D5BBC8006EA940 /* Images.xcassets */,
45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */,
34B0796C1FCF46B000E248C2 /* MainAppContext.h */,
34B0796B1FCF46B000E248C2 /* MainAppContext.m */,
FDE125222A837E4E002DA685 /* MainAppContext.swift */,
C3CA3AA0255CDA7000F4C6D4 /* Mnemonic */,
B67EBF5C19194AC60084CCFD /* Settings.bundle */,
B657DDC91911A40500F45B0C /* Signal.entitlements */,
@ -3553,6 +3545,7 @@
FD09796527F6B0A800936362 /* Utilities */ = {
isa = PBXGroup;
children = (
FDFBB74A2A1EFF4900CA7350 /* Bencode.swift */,
FD97B23F2A3FEB050027DD57 /* ARC4RandomNumberGenerator.swift */,
FDA8EB0F280F8238002B68E5 /* Codable+Utilities.swift */,
FD3003692A3ADD6000B5A5FB /* CExceptionHelper.h */,
@ -3618,6 +3611,7 @@
FD368A6729DE8F9B000DBF1E /* _012_AddFTSIfNeeded.swift */,
FD8ECF7C2934293A00C0D1BB /* _013_SessionUtilChanges.swift */,
FD778B6329B189FF001BAC6B /* _014_GenerateInitialUserConfigDumps.swift */,
FD1D732D2A86114600E3F410 /* _015_BlockCommunityMessageRequests.swift */,
);
path = Migrations;
sourceTree = "<group>";
@ -3683,6 +3677,7 @@
children = (
FD17D7BE27F51F8200122BE0 /* ColumnExpressible.swift */,
FD17D7B727F51ECA00122BE0 /* Migration.swift */,
FD1F9C9E2A862BE60050F671 /* MigrationRequirement.swift */,
FD17D7B927F51F2100122BE0 /* TargetMigrations.swift */,
FD17D7C027F5200100122BE0 /* TypedTableDefinition.swift */,
FD37EA1028AB34B3003AE748 /* TypedTableAlteration.swift */,
@ -3702,6 +3697,8 @@
FDDF074329C3E3D000E5E8B5 /* FetchRequest+Utilities.swift */,
FDF2220E281B55E6000A4995 /* QueryInterfaceRequest+Utilities.swift */,
FD1A94FA2900D1C2000D73D3 /* PersistableRecord+Utilities.swift */,
FD5931AA2A8DCB0A0040147D /* ScopeAdapter+Utilities.swift */,
FD5931A62A8DA5DA0040147D /* SQLInterpolation+Utilities.swift */,
);
path = Utilities;
sourceTree = "<group>";
@ -3763,6 +3760,7 @@
FD2B4B022949886900AB4848 /* Database */ = {
isa = PBXGroup;
children = (
FD1D73292A85AA2000E3F410 /* Setting+Utilities.swift */,
FD2B4B032949887A00AB4848 /* QueryInterfaceRequest+Utilities.swift */,
);
path = Database;
@ -4002,7 +4000,6 @@
FD5C72F8284F0E880029977D /* MessageReceiver+TypingIndicators.swift */,
FD5C72FA284F0EA10029977D /* MessageReceiver+DataExtractionNotification.swift */,
FD5C72FC284F0EC90029977D /* MessageReceiver+ExpirationTimers.swift */,
FD5C72FE284F0F120029977D /* MessageReceiver+ConfigurationMessages.swift */,
FD5C7300284F0F7A0029977D /* MessageReceiver+UnsendRequests.swift */,
FD5C7302284F0FA50029977D /* MessageReceiver+Calls.swift */,
FD5C7304284F0FF30029977D /* MessageReceiver+VisibleMessages.swift */,
@ -4019,6 +4016,7 @@
FD83B9B927CF20A5005E1583 /* General */,
FDDF074829DAB35200E5E8B5 /* JobRunner */,
FD9B30F1293EA0AF008DEE3E /* Networking */,
FDFBB7522A2023DE00CA7350 /* Utilities */,
FD29598E2A43BE5400888A17 /* Utilities */,
);
path = SessionUtilitiesKitTests;
@ -4157,6 +4155,16 @@
path = Configs;
sourceTree = "<group>";
};
FDC13D4E2A16EE41007267C7 /* Types */ = {
isa = PBXGroup;
children = (
FDC13D482A16EC20007267C7 /* Service.swift */,
FDD82C3E2A205D0A00425F05 /* ProcessResult.swift */,
FDC13D4F2A16EE50007267C7 /* PushNotificationAPIEndpoint.swift */,
);
path = Types;
sourceTree = "<group>";
};
FDC2909227D710A9005DAE71 /* Types */ = {
isa = PBXGroup;
children = (
@ -4207,7 +4215,17 @@
FDC4382D27B383A600C60D73 /* Models */ = {
isa = PBXGroup;
children = (
FDC4382E27B383AF00C60D73 /* PushServerResponse.swift */,
FDC13D512A16F22E007267C7 /* PushNotificationAPIRequest.swift */,
FDC13D462A16E4CA007267C7 /* SubscribeRequest.swift */,
FDC13D4A2A16ECBA007267C7 /* SubscribeResponse.swift */,
FDC13D552A171FE4007267C7 /* UnsubscribeRequest.swift */,
FDC13D572A17207D007267C7 /* UnsubscribeResponse.swift */,
FD6E4C892A1AEE4700C7C243 /* LegacyUnsubscribeRequest.swift */,
FDC13D532A16FF29007267C7 /* LegacyGroupRequest.swift */,
FDCD2E022A41294E00964D6A /* LegacyGroupOnlyRequest.swift */,
FDC4382E27B383AF00C60D73 /* LegacyPushServerResponse.swift */,
FDC13D592A1721C5007267C7 /* LegacyNotifyRequest.swift */,
FDFBB74C2A1F3C4E00CA7350 /* NotificationMetadata.swift */,
);
path = Models;
sourceTree = "<group>";
@ -4407,6 +4425,14 @@
path = Models;
sourceTree = "<group>";
};
FDFBB7522A2023DE00CA7350 /* Utilities */ = {
isa = PBXGroup;
children = (
FDFBB7532A2023EB00CA7350 /* BencodeSpec.swift */,
);
path = Utilities;
sourceTree = "<group>";
};
FDFDE122282D04E30098B17F /* Transitions */ = {
isa = PBXGroup;
children = (
@ -4433,12 +4459,6 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
C33FDDB0255A582000E217F9 /* NSURLSessionDataTask+StatusCode.h in Headers */,
C33FDDD0255A582000E217F9 /* FunctionalUtil.h in Headers */,
C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */,
C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */,
C33FDDBD255A582000E217F9 /* ByteParser.h in Headers */,
C33FDDB3255A582000E217F9 /* OWSError.h in Headers */,
C38EF35E255B6DCC007E1867 /* OWSViewController.h in Headers */,
C33FD9AF255A548A00E217F9 /* SignalUtilitiesKit.h in Headers */,
C33FDD06255A582000E217F9 /* AppVersion.h in Headers */,
@ -4739,6 +4759,7 @@
D221A080169C9E5E00537ABF /* Project object */ = {
isa = PBXProject;
attributes = {
BuildIndependentTargetsInParallel = YES;
DefaultBuildSystemTypeForWorkspace = Original;
LastSwiftUpdateCheck = 1430;
LastTestingUpgradeCheck = 0600;
@ -5500,10 +5521,8 @@
C38EF30C255B6DBF007E1867 /* ScreenLock.swift in Sources */,
C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */,
C38EF38A255B6DD2007E1867 /* AttachmentCaptionToolbar.swift in Sources */,
C33FDCD1255A582000E217F9 /* FunctionalUtil.m in Sources */,
C38EF402255B6DF7007E1867 /* CommonStrings.swift in Sources */,
C38EF3C1255B6DE7007E1867 /* ImageEditorBrushViewController.swift in Sources */,
C33FDD32255A582000E217F9 /* OWSOperation.m in Sources */,
C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */,
C33FDD8D255A582000E217F9 /* OWSSignalAddress.swift in Sources */,
C38EF388255B6DD2007E1867 /* AttachmentApprovalViewController.swift in Sources */,
@ -5511,7 +5530,6 @@
C33FDC29255A581F00E217F9 /* ReachabilityManager.swift in Sources */,
C38EF407255B6DF7007E1867 /* Toast.swift in Sources */,
C38EF38C255B6DD2007E1867 /* ApprovalRailCellView.swift in Sources */,
C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */,
C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */,
C38EF3C7255B6DE7007E1867 /* ImageEditorCanvasView.swift in Sources */,
C38EF400255B6DF7007E1867 /* GalleryRailView.swift in Sources */,
@ -5520,7 +5538,6 @@
C38EF3BA255B6DE7007E1867 /* ImageEditorItem.swift in Sources */,
C33FDD3A255A582000E217F9 /* Notification+Loki.swift in Sources */,
C38EF24E255B6D67007E1867 /* Collection+OWS.swift in Sources */,
C33FDCFA255A582000E217F9 /* SignalIOSProto.swift in Sources */,
C38EF24D255B6D67007E1867 /* UIView+OWS.swift in Sources */,
C38EF38B255B6DD2007E1867 /* AttachmentPrepViewController.swift in Sources */,
C38EF405255B6DF7007E1867 /* OWSButton.swift in Sources */,
@ -5536,9 +5553,7 @@
FD52090B28B59BB4006098F6 /* ScreenLockViewController.swift in Sources */,
C38EF401255B6DF7007E1867 /* VideoPlayerView.swift in Sources */,
C38EF3BD255B6DE7007E1867 /* ImageEditorTransform.swift in Sources */,
C33FDC9A255A582000E217F9 /* ByteParser.m in Sources */,
C33FDC58255A582000E217F9 /* ReverseDispatchQueue.swift in Sources */,
C33FDC78255A582000E217F9 /* TSConstants.m in Sources */,
C38EF324255B6DBF007E1867 /* Bench.swift in Sources */,
FDCDB8DE2810F73B00352A0C /* Differentiable+Utilities.swift in Sources */,
C38EF3F9255B6DF7007E1867 /* OWSLayerView.swift in Sources */,
@ -5550,12 +5565,10 @@
C38EF386255B6DD2007E1867 /* AttachmentApprovalInputAccessoryView.swift in Sources */,
B8C2B2C82563685C00551B4D /* CircleView.swift in Sources */,
C38EF331255B6DBF007E1867 /* UIGestureRecognizer+OWS.swift in Sources */,
C33FDDC5255A582000E217F9 /* OWSError.m in Sources */,
FD848B9C284435D7000E298B /* AppSetup.swift in Sources */,
C38EF31C255B6DBF007E1867 /* Searcher.swift in Sources */,
C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */,
C38EF3BE255B6DE7007E1867 /* OrderedDictionary.swift in Sources */,
C33FDD6E255A582000E217F9 /* NSURLSessionDataTask+StatusCode.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -5658,6 +5671,8 @@
C3D9E4C02567767F0040E4F3 /* DataSource.m in Sources */,
C32C5DD2256DD9E5003C73A2 /* LRUCache.swift in Sources */,
FD71160228C8255900B47552 /* UIControl+Combine.swift in Sources */,
FDFBB74B2A1EFF4900CA7350 /* Bencode.swift in Sources */,
FD5931A72A8DA5DA0040147D /* SQLInterpolation+Utilities.swift in Sources */,
FD9004152818B46300ABAAF6 /* JobRunner.swift in Sources */,
FDF8487929405906007DCAE5 /* HTTPQueryParam.swift in Sources */,
FD17D7CA27F546D900122BE0 /* _001_InitialSetupMigration.swift in Sources */,
@ -5669,10 +5684,12 @@
C3D9E4DA256778410040E4F3 /* UIImage+OWS.m in Sources */,
C32C600F256E07F5003C73A2 /* NSUserDefaults+OWS.m in Sources */,
FDE658A329418E2F00A33BC1 /* KeyPair.swift in Sources */,
FD5931AB2A8DCB0A0040147D /* ScopeAdapter+Utilities.swift in Sources */,
FD37E9FF28A5F2CD003AE748 /* Configuration.swift in Sources */,
FDB7400B28EB99A70094D718 /* TimeInterval+Utilities.swift in Sources */,
C3D9E35E25675F640040E4F3 /* OWSFileSystem.m in Sources */,
FD09797D27FBDB2000936362 /* Notification+Utilities.swift in Sources */,
FD1F9C9F2A862BE60050F671 /* MigrationRequirement.swift in Sources */,
FDC6D7602862B3F600B04575 /* Dependencies.swift in Sources */,
C3C2AC2E2553CBEB00C340D1 /* String+Trimming.swift in Sources */,
FD17D7C727F5207C00122BE0 /* DatabaseMigrator+Utilities.swift in Sources */,
@ -5757,6 +5774,7 @@
FD245C672850665E00B966DD /* AttachmentDownloadJob.swift in Sources */,
C300A5D32554B05A00555489 /* TypingIndicator.swift in Sources */,
7B521E0A29BFF84400C3C36A /* GroupLeavingJob.swift in Sources */,
FDC13D582A17207D007267C7 /* UnsubscribeResponse.swift in Sources */,
FD09799927FFC1A300936362 /* Attachment.swift in Sources */,
FD245C5F2850662200B966DD /* OWSWindowManager.m in Sources */,
C3471ECB2555356A00297E91 /* MessageSender+Encryption.swift in Sources */,
@ -5776,6 +5794,7 @@
FD245C5A2850660100B966DD /* LinkPreviewDraft.swift in Sources */,
FDD250702837199200198BDA /* GarbageCollectionJob.swift in Sources */,
FD6A7A6B2818C17C00035AC1 /* UpdateProfilePictureJob.swift in Sources */,
FDD82C3F2A205D0A00425F05 /* ProcessResult.swift in Sources */,
FD716E6A2850327900C96BF4 /* EndCallMode.swift in Sources */,
FDF0B75C2807F41D004C14C5 /* MessageSender+Convenience.swift in Sources */,
7B81682A28B6F1420069F315 /* ReactionResponse.swift in Sources */,
@ -5789,6 +5808,7 @@
FD245C57285065F100B966DD /* Poller.swift in Sources */,
FDA8EAFE280E8B78002B68E5 /* FailedMessageSendsJob.swift in Sources */,
FD245C6A2850666F00B966DD /* FileServerAPI.swift in Sources */,
FDFBB74D2A1F3C4E00CA7350 /* NotificationMetadata.swift in Sources */,
FDC4386927B4E6B800C60D73 /* String+Utlities.swift in Sources */,
FD716E6628502EE200C96BF4 /* CurrentCallProtocol.swift in Sources */,
FD8ECF9029381FC200C0D1BB /* SessionUtil+UserProfile.swift in Sources */,
@ -5803,6 +5823,7 @@
FD37EA0F28AB3330003AE748 /* _006_FixHiddenModAdminSupport.swift in Sources */,
FD2B4AFD294688D000AB4848 /* SessionUtil+Contacts.swift in Sources */,
7B81682328A4C1210069F315 /* UpdateTypes.swift in Sources */,
FDC13D472A16E4CA007267C7 /* SubscribeRequest.swift in Sources */,
FD2B4AFF2946C93200AB4848 /* ConfigurationSyncJob.swift in Sources */,
FDC438A627BB113A00C60D73 /* UserUnbanRequest.swift in Sources */,
FD5C72FB284F0EA10029977D /* MessageReceiver+DataExtractionNotification.swift in Sources */,
@ -5811,18 +5832,22 @@
C379DCF4256735770002D4EB /* VisibleMessage+Attachment.swift in Sources */,
FDB4BBC72838B91E00B7C95D /* LinkPreviewError.swift in Sources */,
FD09798327FD1A1500936362 /* ClosedGroup.swift in Sources */,
FDC13D542A16FF29007267C7 /* LegacyGroupRequest.swift in Sources */,
B8B320B7258C30D70020074B /* HTMLMetadata.swift in Sources */,
FD8ECF8B2935DB4B00C0D1BB /* SharedConfigMessage.swift in Sources */,
FD09798727FD1B7800936362 /* GroupMember.swift in Sources */,
FDB4BBC92839BEF000B7C95D /* ProfileManagerError.swift in Sources */,
FDCD2E032A41294E00964D6A /* LegacyGroupOnlyRequest.swift in Sources */,
FD3E0C84283B5835002A425C /* SessionThreadViewModel.swift in Sources */,
FD09C5EC282B8F18000CE219 /* AttachmentError.swift in Sources */,
FD17D79927F40AB800122BE0 /* _003_YDBToGRDBMigration.swift in Sources */,
FDF0B7512807BA56004C14C5 /* NotificationsProtocol.swift in Sources */,
B8DE1FB426C22F2F0079C9CE /* WebRTCSession.swift in Sources */,
FDC13D5A2A1721C5007267C7 /* LegacyNotifyRequest.swift in Sources */,
FDC6D6F32860607300B04575 /* Environment.swift in Sources */,
C3A3A171256E1D25004D228D /* SSKReachabilityManager.swift in Sources */,
FD245C59285065FC00B966DD /* ControlMessage.swift in Sources */,
FD6E4C8A2A1AEE4700C7C243 /* LegacyUnsubscribeRequest.swift in Sources */,
B8DE1FB626C22FCB0079C9CE /* CallMessage.swift in Sources */,
FD245C50285065C700B966DD /* VisibleMessage+Quote.swift in Sources */,
FD8ECF892935AB7200C0D1BB /* SessionUtilError.swift in Sources */,
@ -5848,23 +5873,24 @@
FD6A7A692818BE7300035AC1 /* RetrieveDefaultOpenGroupRoomsJob.swift in Sources */,
FD09798D27FD1D8900936362 /* DisappearingMessageConfiguration.swift in Sources */,
FDF0B75A2807F3A3004C14C5 /* MessageSenderError.swift in Sources */,
FDC4382F27B383AF00C60D73 /* PushServerResponse.swift in Sources */,
FDC4382F27B383AF00C60D73 /* LegacyPushServerResponse.swift in Sources */,
FDC4386327B4D94E00C60D73 /* SOGSMessage.swift in Sources */,
FD245C692850666800B966DD /* ExpirationTimerUpdate.swift in Sources */,
FD42F9A8285064B800A0C77D /* PushNotificationAPI.swift in Sources */,
FD245C6C2850669200B966DD /* MessageReceiveJob.swift in Sources */,
FD43EE9D297A5190009C87C5 /* SessionUtil+UserGroups.swift in Sources */,
FD83B9CC27D179BC005E1583 /* FSEndpoint.swift in Sources */,
FDC13D4B2A16ECBA007267C7 /* SubscribeResponse.swift in Sources */,
FD7115F228C6CB3900B47552 /* _010_AddThreadIdToFTS.swift in Sources */,
FD716E6428502DDD00C96BF4 /* CallManagerProtocol.swift in Sources */,
FDC438C727BB6DF000C60D73 /* DirectMessage.swift in Sources */,
FDC13D502A16EE50007267C7 /* PushNotificationAPIEndpoint.swift in Sources */,
FD432434299C6985008A0213 /* PendingReadReceipt.swift in Sources */,
FDC4381727B32EC700C60D73 /* Personalization.swift in Sources */,
FD245C51285065CC00B966DD /* MessageReceiver.swift in Sources */,
FD23CE222A661D000000B97C /* OpenGroupAPI+Crypto.swift in Sources */,
FD245C652850665400B966DD /* ClosedGroupControlMessage.swift in Sources */,
FDC4387827B5C35400C60D73 /* SendMessageRequest.swift in Sources */,
7B93D07027CF194000811CB6 /* ConfigurationMessage+Convenience.swift in Sources */,
FD5C72FD284F0EC90029977D /* MessageReceiver+ExpirationTimers.swift in Sources */,
C32C5A88256DBCF9003C73A2 /* MessageReceiver+ClosedGroups.swift in Sources */,
B8D0A25925E367AC00C1835E /* Notification+MessageReceiver.swift in Sources */,
@ -5874,7 +5900,6 @@
C32C599E256DB02B003C73A2 /* TypingIndicators.swift in Sources */,
FD716E682850318E00C96BF4 /* CallMode.swift in Sources */,
FD09799527FE7B8E00936362 /* Interaction.swift in Sources */,
FD5C72FF284F0F120029977D /* MessageReceiver+ConfigurationMessages.swift in Sources */,
FD37EA0D28AB2A45003AE748 /* _005_FixDeletedMessageReadState.swift in Sources */,
7BAA7B6628D2DE4700AE1489 /* _009_OpenGroupPermission.swift in Sources */,
FDC4380927B31D4E00C60D73 /* OpenGroupAPIError.swift in Sources */,
@ -5885,7 +5910,9 @@
FD09796E27FA6D0000936362 /* Contact.swift in Sources */,
C38D5E8D2575011E00B6A65C /* MessageSender+ClosedGroups.swift in Sources */,
FD5C72F7284F0E560029977D /* MessageReceiver+ReadReceipts.swift in Sources */,
FDC13D492A16EC20007267C7 /* Service.swift in Sources */,
FD778B6429B189FF001BAC6B /* _014_GenerateInitialUserConfigDumps.swift in Sources */,
FDC13D562A171FE4007267C7 /* UnsubscribeRequest.swift in Sources */,
C32C598A256D0664003C73A2 /* SNProtoEnvelope+Conversion.swift in Sources */,
FDC438CB27BB7DB100C60D73 /* UpdateMessageRequest.swift in Sources */,
FD8ECF7F2934298100C0D1BB /* ConfigDump.swift in Sources */,
@ -5909,17 +5936,20 @@
FD245C682850666300B966DD /* Message+Destination.swift in Sources */,
FDF8488029405994007DCAE5 /* HTTPQueryParam+OpenGroup.swift in Sources */,
FD09798527FD1A6500936362 /* ClosedGroupKeyPair.swift in Sources */,
FDC13D522A16F22E007267C7 /* PushNotificationAPIRequest.swift in Sources */,
FD245C632850664600B966DD /* Configuration.swift in Sources */,
C32C5DBF256DD743003C73A2 /* ClosedGroupPoller.swift in Sources */,
C352A35B2557824E00338F3E /* AttachmentUploadJob.swift in Sources */,
FD2959922A4417A900888A17 /* PreparedSendData.swift in Sources */,
FD5C7305284F0FF30029977D /* MessageReceiver+VisibleMessages.swift in Sources */,
FD1D732E2A86114600E3F410 /* _015_BlockCommunityMessageRequests.swift in Sources */,
FD432437299DEA38008A0213 /* TypeConversion+Utilities.swift in Sources */,
FD2B4B042949887A00AB4848 /* QueryInterfaceRequest+Utilities.swift in Sources */,
FD09797027FA6FF300936362 /* Profile.swift in Sources */,
FD245C56285065EA00B966DD /* SNProto.swift in Sources */,
FD09798B27FD1CFE00936362 /* Capability.swift in Sources */,
C3BBE0C72554F1570050F1E3 /* FixedWidthInteger+BigEndian.swift in Sources */,
FD1D732A2A85AA2000E3F410 /* Setting+Utilities.swift in Sources */,
FD17D79C27F40B2E00122BE0 /* SMKLegacy.swift in Sources */,
FD09798127FCFEE800936362 /* SessionThread.swift in Sources */,
FD09C5EA282A1BB2000CE219 /* ThreadTypingIndicator.swift in Sources */,
@ -5983,10 +6013,10 @@
B83F2B88240CB75A000A54AB /* UIImage+Scaling.swift in Sources */,
3430FE181F7751D4000EC51B /* GiphyAPI.swift in Sources */,
4C090A1B210FD9C7001FD7F9 /* HapticFeedback.swift in Sources */,
FDE125232A837E4E002DA685 /* MainAppContext.swift in Sources */,
7B9F71D12852EEE2006DFE7B /* EmojiWithSkinTones+String.swift in Sources */,
34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */,
B886B4A92398BA1500211ABE /* QRCode.swift in Sources */,
34B0796D1FCF46B100E248C2 /* MainAppContext.m in Sources */,
34A8B3512190A40E00218A25 /* MediaAlbumView.swift in Sources */,
FD09C5E828264937000CE219 /* MediaDetailViewController.swift in Sources */,
3496955E219B605E00DCFE74 /* PhotoLibrary.swift in Sources */,
@ -6172,6 +6202,7 @@
FD2AAAF228ED57B500A49611 /* SynchronousStorage.swift in Sources */,
FD078E4927E02576000769AF /* CommonMockedExtensions.swift in Sources */,
FD83B9BF27CF2294005E1583 /* TestConstants.swift in Sources */,
FDFBB7542A2023EB00CA7350 /* BencodeSpec.swift in Sources */,
FD9DD2732A72516D00ECB68E /* TestExtensions.swift in Sources */,
FD83B9BB27CF20AF005E1583 /* SessionIdSpec.swift in Sources */,
FDC290A927D9B46D005DAE71 /* NimbleExtensions.swift in Sources */,
@ -6414,7 +6445,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 421;
CURRENT_PROJECT_VERSION = 422;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
@ -6438,7 +6469,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.3.2;
MARKETING_VERSION = 2.4.0;
MTL_ENABLE_DEBUG_INFO = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension";
PRODUCT_NAME = "$(TARGET_NAME)";
@ -6486,7 +6517,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 421;
CURRENT_PROJECT_VERSION = 422;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = SUQ8J2PCT7;
ENABLE_NS_ASSERTIONS = NO;
@ -6515,7 +6546,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.3.2;
MARKETING_VERSION = 2.4.0;
MTL_ENABLE_DEBUG_INFO = NO;
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.ShareExtension";
PRODUCT_NAME = "$(TARGET_NAME)";
@ -6551,7 +6582,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 421;
CURRENT_PROJECT_VERSION = 422;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = "$(inherited)";
@ -6574,7 +6605,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.3.2;
MARKETING_VERSION = 2.4.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension";
@ -6625,7 +6656,7 @@
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 421;
CURRENT_PROJECT_VERSION = 422;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = SUQ8J2PCT7;
ENABLE_NS_ASSERTIONS = NO;
@ -6653,7 +6684,7 @@
"@executable_path/Frameworks",
"@executable_path/../../Frameworks",
);
MARKETING_VERSION = 2.3.2;
MARKETING_VERSION = 2.4.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger.NotificationServiceExtension";
@ -7585,7 +7616,7 @@
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 421;
CURRENT_PROJECT_VERSION = 422;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@ -7623,7 +7654,7 @@
"$(SRCROOT)",
);
LLVM_LTO = NO;
MARKETING_VERSION = 2.3.2;
MARKETING_VERSION = 2.4.0;
OTHER_LDFLAGS = "$(inherited)";
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" \"-DDEBUG\"";
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger";
@ -7656,7 +7687,7 @@
CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements;
CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CURRENT_PROJECT_VERSION = 421;
CURRENT_PROJECT_VERSION = 422;
DEVELOPMENT_TEAM = SUQ8J2PCT7;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
@ -7694,7 +7725,7 @@
"$(SRCROOT)",
);
LLVM_LTO = NO;
MARKETING_VERSION = 2.3.2;
MARKETING_VERSION = 2.4.0;
OTHER_LDFLAGS = "$(inherited)";
PRODUCT_BUNDLE_IDENTIFIER = "com.loki-project.loki-messenger";
PRODUCT_NAME = Session;

View File

@ -9,6 +9,8 @@ import WebRTC
import SessionUIKit
import SignalUtilitiesKit
import SessionMessagingKit
import SessionUtilitiesKit
import SessionSnodeKit
public final class SessionCall: CurrentCallProtocol, WebRTCSessionDelegate {
@objc static let isEnabled = true

View File

@ -2,6 +2,7 @@
import UIKit
import GRDB
import SessionUtilitiesKit
extension SessionCallManager {
@discardableResult

View File

@ -6,6 +6,7 @@ import GRDB
import SessionMessagingKit
import SignalCoreKit
import SignalUtilitiesKit
import SessionUtilitiesKit
public final class SessionCallManager: NSObject, CallManagerProtocol {
let provider: CXProvider?

View File

@ -4,6 +4,7 @@ import UIKit
import SessionUIKit
import SessionMessagingKit
import SignalUtilitiesKit
import SessionUtilitiesKit
final class IncomingCallBanner: UIView, UIGestureRecognizerDelegate {
private static let swipeToOperateThreshold: CGFloat = 60

View File

@ -3,6 +3,7 @@
import UIKit
import WebRTC
import SessionUIKit
import SessionUtilitiesKit
final class MiniCallView: UIView, RTCVideoViewDelegate {
var callVC: CallVC

View File

@ -7,6 +7,7 @@ import DifferenceKit
import SessionUIKit
import SessionMessagingKit
import SignalUtilitiesKit
import SessionUtilitiesKit
final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate {
private struct GroupMemberDisplayInfo: FetchableRecord, Equatable, Hashable, Decodable, Differentiable {

View File

@ -2,6 +2,7 @@
import UIKit
import SessionMessagingKit
import SessionUtilitiesKit
extension ContextMenuVC {
struct Action {

View File

@ -5,6 +5,7 @@ import GRDB
import SignalUtilitiesKit
import SignalCoreKit
import SessionUIKit
import SessionUtilitiesKit
public class StyledSearchController: UISearchController {
public override var preferredStatusBarStyle: UIStatusBarStyle {

View File

@ -11,6 +11,7 @@ import SessionUIKit
import SessionMessagingKit
import SessionUtilitiesKit
import SignalUtilitiesKit
import SessionSnodeKit
extension ConversationVC:
InputViewDelegate,

View File

@ -208,17 +208,7 @@ final class ConversationVC: BaseVC, SessionUtilRespondingViewController, Convers
}()
private lazy var emptyStateLabel: UILabel = {
let text: String = String(
format: {
switch (viewModel.threadData.threadIsNoteToSelf, viewModel.threadData.canWrite) {
case (true, _): return "CONVERSATION_EMPTY_STATE_NOTE_TO_SELF".localized()
case (_, false): return "CONVERSATION_EMPTY_STATE_READ_ONLY".localized()
default: return "CONVERSATION_EMPTY_STATE".localized()
}
}(),
viewModel.threadData.displayName
)
let text: String = emptyStateText(for: viewModel.threadData)
let result: UILabel = UILabel()
result.accessibilityLabel = "Empty state label"
result.translatesAutoresizingMaskIntoConstraints = false
@ -698,6 +688,24 @@ final class ConversationVC: BaseVC, SessionUtilRespondingViewController, Convers
self.viewModel.onInteractionChange = nil
}
private func emptyStateText(for threadData: SessionThreadViewModel) -> String {
return String(
format: {
switch (threadData.threadIsNoteToSelf, threadData.canWrite) {
case (true, _): return "CONVERSATION_EMPTY_STATE_NOTE_TO_SELF".localized()
case (_, false):
return (threadData.profile?.blocksCommunityMessageRequests == true ?
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE".localized() :
"CONVERSATION_EMPTY_STATE_READ_ONLY".localized()
)
default: return "CONVERSATION_EMPTY_STATE".localized()
}
}(),
threadData.displayName
)
}
private func handleThreadUpdates(_ updatedThreadData: SessionThreadViewModel, initialLoad: Bool = false) {
// Ensure the first load or a load when returning from a child screen runs without animations (if
// we don't do this the cells will animate in from a frame of CGRect.zero or have a buggy transition)
@ -738,17 +746,7 @@ final class ConversationVC: BaseVC, SessionUtilRespondingViewController, Convers
)
// Update the empty state
let text: String = String(
format: {
switch (updatedThreadData.threadIsNoteToSelf, updatedThreadData.canWrite) {
case (true, _): return "CONVERSATION_EMPTY_STATE_NOTE_TO_SELF".localized()
case (_, false): return "CONVERSATION_EMPTY_STATE_READ_ONLY".localized()
default: return "CONVERSATION_EMPTY_STATE".localized()
}
}(),
updatedThreadData.displayName
)
let text: String = emptyStateText(for: updatedThreadData)
emptyStateLabel.attributedText = NSAttributedString(string: text)
.adding(
attributes: [.font: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize)],
@ -791,8 +789,10 @@ final class ConversationVC: BaseVC, SessionUtilRespondingViewController, Convers
updatedThreadData.threadRequiresApproval == true
)
self?.messageRequestStackView.isHidden = (
updatedThreadData.threadIsMessageRequest == false &&
updatedThreadData.threadRequiresApproval == false
!updatedThreadData.canWrite || (
updatedThreadData.threadIsMessageRequest == false &&
updatedThreadData.threadRequiresApproval == false
)
)
self?.messageRequestBackgroundView.isHidden = (self?.messageRequestStackView.isHidden == true)
self?.messageRequestDescriptionLabelBottomConstraint?.constant = (updatedThreadData.threadRequiresApproval == true ? -4 : -20)

View File

@ -2,6 +2,7 @@
import UIKit
import SessionUIKit
import SessionUtilitiesKit
final class InputViewButton: UIView {
private let icon: UIImage?

View File

@ -3,6 +3,7 @@
import UIKit
import SessionUIKit
import SessionMessagingKit
import SessionUtilitiesKit
final class CallMessageCell: MessageCell {
private static let iconSize: CGFloat = 16

View File

@ -3,6 +3,7 @@
import UIKit
import SessionMessagingKit
import SignalCoreKit
import SessionUtilitiesKit
public class MediaAlbumView: UIStackView {
private let items: [Attachment]

View File

@ -6,6 +6,7 @@ import SessionUIKit
import SessionMessagingKit
import SignalCoreKit
import SignalUtilitiesKit
import SessionUtilitiesKit
public class MediaView: UIView {
static let contentMode: UIView.ContentMode = .scaleAspectFill

View File

@ -156,7 +156,7 @@ final class QuoteView: UIView {
if attachment.isVisualMedia {
attachment.thumbnail(
size: .small,
success: { image, _ in
success: { [imageView] image, _ in
guard Thread.isMainThread else {
DispatchQueue.main.async {
imageView.image = image
@ -234,8 +234,6 @@ final class QuoteView: UIView {
}
// Label stack view
let bodyLabelSize = bodyLabel.systemLayoutSizeFitting(availableSpace)
let isCurrentUser: Bool = [
currentUserPublicKey,
currentUserBlinded15PublicKey,
@ -288,9 +286,8 @@ final class QuoteView: UIView {
cancelButton.set(.height, to: cancelButtonSize)
cancelButton.addTarget(self, action: #selector(cancel), for: UIControl.Event.touchUpInside)
addSubview(cancelButton)
mainStackView.addArrangedSubview(cancelButton)
cancelButton.center(.vertical, in: self)
cancelButton.pin(.right, to: .right, of: self)
}
}

View File

@ -3,6 +3,7 @@
import UIKit
import SessionUIKit
import SignalCoreKit
import SessionUtilitiesKit
@objc class TypingIndicatorView: UIStackView {
// This represents the spacing between the dots

View File

@ -2,6 +2,7 @@
import UIKit
import SessionMessagingKit
import SessionUtilitiesKit
public enum SwipeState {
case began

View File

@ -9,6 +9,7 @@ import SessionUIKit
import SessionMessagingKit
import SignalUtilitiesKit
import SessionUtilitiesKit
import SessionSnodeKit
class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.NavButton, ThreadSettingsViewModel.Section, ThreadSettingsViewModel.Setting> {
// MARK: - Config
@ -178,6 +179,7 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
// MARK: - Content
private var originalState: SessionThreadViewModel?
override var title: String {
switch threadVariant {
case .contact: return "vc_settings_title".localized()
@ -235,6 +237,8 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
threadViewModel.currentUserIsClosedGroupAdmin == true
)
let editIcon: UIImage? = UIImage(named: "icon_edit")
let originalState: SessionThreadViewModel = (self?.originalState ?? threadViewModel)
self?.originalState = threadViewModel
return [
SectionModel(
@ -577,7 +581,10 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
title: "vc_conversation_settings_notify_for_mentions_only_title".localized(),
subtitle: "vc_conversation_settings_notify_for_mentions_only_explanation".localized(),
rightAccessory: .toggle(
.boolValue(threadViewModel.threadOnlyNotifyForMentions == true)
.boolValue(
threadViewModel.threadOnlyNotifyForMentions == true,
oldValue: (originalState.threadOnlyNotifyForMentions == true)
)
),
isEnabled: (
(
@ -615,7 +622,10 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
),
title: "CONVERSATION_SETTINGS_MUTE_LABEL".localized(),
rightAccessory: .toggle(
.boolValue(threadViewModel.threadMutedUntilTimestamp != nil)
.boolValue(
threadViewModel.threadMutedUntilTimestamp != nil,
oldValue: (originalState.threadMutedUntilTimestamp != nil)
)
),
isEnabled: (
(
@ -661,7 +671,10 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
),
title: "CONVERSATION_SETTINGS_BLOCK_THIS_USER".localized(),
rightAccessory: .toggle(
.boolValue(threadViewModel.threadIsBlocked == true)
.boolValue(
threadViewModel.threadIsBlocked == true,
oldValue: (originalState.threadIsBlocked == true)
)
),
accessibility: Accessibility(
identifier: "\(ThreadSettingsViewModel.self).block",

View File

@ -5,6 +5,7 @@ import DifferenceKit
import SessionUIKit
import SessionMessagingKit
import SignalUtilitiesKit
import SessionUtilitiesKit
final class ReactionListSheet: BaseVC {
public struct ReactionSummary: Hashable, Differentiable {

View File

@ -1,5 +1,6 @@
import Foundation
import SignalCoreKit
import SessionUtilitiesKit
extension Emoji {
private static let availableCache: Atomic<[Emoji:Bool]> = Atomic([:])

View File

@ -203,6 +203,11 @@ class GlobalSearchViewController: BaseVC, SessionUtilRespondingViewController, U
])
}
catch {
// Don't log the 'interrupt' error as that's just the user typing too fast
if (error as? DatabaseError)?.resultCode != DatabaseError.SQLITE_INTERRUPT {
SNLog("[GlobalSearch] Failed to find results due to error: \(error)")
}
return .failure(error)
}
}

View File

@ -283,14 +283,6 @@ final class HomeVC: BaseVC, SessionUtilRespondingViewController, UITableViewData
// Start polling if needed (i.e. if the user just created or restored their Session ID)
if Identity.userExists(), let appDelegate: AppDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.startPollersIfNeeded()
// FIXME: Remove this once `useSharedUtilForUserConfig` is permanent
if !SessionUtil.userConfigsEnabled {
// Do this only if we created a new Session ID, or if we already received the initial configuration message
if UserDefaults.standard[.hasSyncedInitialConfiguration] {
appDelegate.syncConfigurationIfNeeded()
}
}
}
// Onion request path countries cache

View File

@ -6,6 +6,7 @@ import DifferenceKit
import SessionUIKit
import SessionMessagingKit
import SignalUtilitiesKit
import SessionUtilitiesKit
class MessageRequestsViewController: BaseVC, SessionUtilRespondingViewController, UITableViewDelegate, UITableViewDataSource {
private static let loadingHeaderHeight: CGFloat = 40

View File

@ -4,6 +4,7 @@ import Foundation
import GRDB
import DifferenceKit
import SignalUtilitiesKit
import SessionUtilitiesKit
public class MessageRequestsViewModel {
public typealias SectionModel = ArraySection<Section, SessionThreadViewModel>

View File

@ -7,6 +7,7 @@ import SessionUIKit
import SessionMessagingKit
import SessionUtilitiesKit
import SignalUtilitiesKit
import SessionSnodeKit
final class NewDMVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControllerDelegate, QRScannerDelegate {
private var shouldShowBackButton: Bool = true

View File

@ -5,6 +5,7 @@ import MediaPlayer
import SessionUIKit
import SignalUtilitiesKit
import SignalCoreKit
import SessionUtilitiesKit
// This kind of view is tricky. I've tried to organize things in the
// simplest possible way.
@ -359,54 +360,54 @@ import SignalCoreKit
@objc func handlePinch(sender: UIPinchGestureRecognizer) {
switch sender.state {
case .possible:
break
case .began:
srcTranslationAtPinchStart = srcTranslation
imageScaleAtPinchStart = imageScale
case .possible: break
case .began:
srcTranslationAtPinchStart = srcTranslation
imageScaleAtPinchStart = imageScale
lastPinchLocation =
sender.location(in: sender.view)
lastPinchScale = sender.scale
break
case .changed, .ended:
if sender.numberOfTouches > 1 {
let location =
lastPinchLocation =
sender.location(in: sender.view)
let scaleDiff = sender.scale / lastPinchScale
// Update scaling.
let srcCropSizeBeforeScalePoints = CGSize(width: srcDefaultCropSizePoints.width / imageScale,
height: srcDefaultCropSizePoints.height / imageScale)
imageScale = max(kMinImageScale, min(kMaxImageScale, imageScale * scaleDiff))
let srcCropSizeAfterScalePoints = CGSize(width: srcDefaultCropSizePoints.width / imageScale,
height: srcDefaultCropSizePoints.height / imageScale)
// Since the translation state reflects the "upper left" corner of the crop region, we need to
// adjust the translation when scaling to preserve the "center" of the crop region.
srcTranslation.x += (srcCropSizeBeforeScalePoints.width - srcCropSizeAfterScalePoints.width) * 0.5
srcTranslation.y += (srcCropSizeBeforeScalePoints.height - srcCropSizeAfterScalePoints.height) * 0.5
// Update translation.
let viewSizePoints = imageView.frame.size
let srcCropSizePoints = CGSize(width: srcDefaultCropSizePoints.width / imageScale,
height: srcDefaultCropSizePoints.height / imageScale)
let viewToSrcRatio = srcCropSizePoints.width / viewSizePoints.width
let gestureTranslation = CGPoint(x: location.x - lastPinchLocation.x,
y: location.y - lastPinchLocation.y)
srcTranslation = CGPoint(x: srcTranslation.x + gestureTranslation.x * -viewToSrcRatio,
y: srcTranslation.y + gestureTranslation.y * -viewToSrcRatio)
lastPinchLocation = location
lastPinchScale = sender.scale
}
break
case .cancelled, .failed:
srcTranslation = srcTranslationAtPinchStart
imageScale = imageScaleAtPinchStart
break
case .changed, .ended:
if sender.numberOfTouches > 1 {
let location =
sender.location(in: sender.view)
let scaleDiff = sender.scale / lastPinchScale
// Update scaling.
let srcCropSizeBeforeScalePoints = CGSize(width: srcDefaultCropSizePoints.width / imageScale,
height: srcDefaultCropSizePoints.height / imageScale)
imageScale = max(kMinImageScale, min(kMaxImageScale, imageScale * scaleDiff))
let srcCropSizeAfterScalePoints = CGSize(width: srcDefaultCropSizePoints.width / imageScale,
height: srcDefaultCropSizePoints.height / imageScale)
// Since the translation state reflects the "upper left" corner of the crop region, we need to
// adjust the translation when scaling to preserve the "center" of the crop region.
srcTranslation.x += (srcCropSizeBeforeScalePoints.width - srcCropSizeAfterScalePoints.width) * 0.5
srcTranslation.y += (srcCropSizeBeforeScalePoints.height - srcCropSizeAfterScalePoints.height) * 0.5
// Update translation.
let viewSizePoints = imageView.frame.size
let srcCropSizePoints = CGSize(width: srcDefaultCropSizePoints.width / imageScale,
height: srcDefaultCropSizePoints.height / imageScale)
let viewToSrcRatio = srcCropSizePoints.width / viewSizePoints.width
let gestureTranslation = CGPoint(x: location.x - lastPinchLocation.x,
y: location.y - lastPinchLocation.y)
srcTranslation = CGPoint(x: srcTranslation.x + gestureTranslation.x * -viewToSrcRatio,
y: srcTranslation.y + gestureTranslation.y * -viewToSrcRatio)
lastPinchLocation = location
lastPinchScale = sender.scale
}
case .cancelled, .failed:
srcTranslation = srcTranslationAtPinchStart
imageScale = imageScaleAtPinchStart
@unknown default: break
}
updateImageLayout()
@ -416,29 +417,28 @@ import SignalCoreKit
@objc func handlePan(sender: UIPanGestureRecognizer) {
switch sender.state {
case .possible:
break
case .began:
srcTranslationAtPanStart = srcTranslation
break
case .changed, .ended:
let viewSizePoints = imageView.frame.size
let srcCropSizePoints = CGSize(width: srcDefaultCropSizePoints.width / imageScale,
height: srcDefaultCropSizePoints.height / imageScale)
case .possible: break
case .began:
srcTranslationAtPanStart = srcTranslation
case .changed, .ended:
let viewSizePoints = imageView.frame.size
let srcCropSizePoints = CGSize(width: srcDefaultCropSizePoints.width / imageScale,
height: srcDefaultCropSizePoints.height / imageScale)
let viewToSrcRatio = srcCropSizePoints.width / viewSizePoints.width
let viewToSrcRatio = srcCropSizePoints.width / viewSizePoints.width
let gestureTranslation =
sender.translation(in: sender.view)
let gestureTranslation =
sender.translation(in: sender.view)
// Update translation.
srcTranslation = CGPoint(x: srcTranslationAtPanStart.x + gestureTranslation.x * -viewToSrcRatio,
y: srcTranslationAtPanStart.y + gestureTranslation.y * -viewToSrcRatio)
break
case .cancelled, .failed:
srcTranslation
= srcTranslationAtPanStart
break
// Update translation.
srcTranslation = CGPoint(x: srcTranslationAtPanStart.x + gestureTranslation.x * -viewToSrcRatio,
y: srcTranslationAtPanStart.y + gestureTranslation.y * -viewToSrcRatio)
case .cancelled, .failed:
srcTranslation = srcTranslationAtPanStart
@unknown default: break
}
updateImageLayout()

View File

@ -7,6 +7,7 @@ import DifferenceKit
import SessionUIKit
import SignalUtilitiesKit
import SignalCoreKit
import SessionUtilitiesKit
public class DocumentTileViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {

View File

@ -5,6 +5,7 @@ import Combine
import YYImage
import SignalUtilitiesKit
import SignalCoreKit
import SessionUtilitiesKit
class GifPickerCell: UICollectionViewCell {

View File

@ -6,6 +6,7 @@ import Reachability
import SignalUtilitiesKit
import SessionUIKit
import SignalCoreKit
import SessionUtilitiesKit
class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollectionViewDataSource, UICollectionViewDelegate, GifPickerLayoutDelegate {

View File

@ -2,6 +2,7 @@
import Foundation
import SignalUtilitiesKit
import SessionUtilitiesKit
public class GiphyDownloader: ProxiedContentDownloader {

View File

@ -6,6 +6,7 @@ import Photos
import SessionUIKit
import SignalUtilitiesKit
import SignalCoreKit
import SessionUtilitiesKit
protocol ImagePickerGridControllerDelegate: AnyObject {
func imagePickerDidCompleteSelection(_ imagePicker: ImagePickerGridController)
@ -155,6 +156,8 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
case .cancelled, .ended, .failed:
collectionView.isUserInteractionEnabled = true
collectionView.isScrollEnabled = true
@unknown default: break
}
}

View File

@ -6,6 +6,7 @@ import SessionUIKit
import SignalUtilitiesKit
import SessionMessagingKit
import SignalCoreKit
import SessionUtilitiesKit
public enum MediaGalleryOption {
case sliderEnabled

View File

@ -199,16 +199,18 @@ public class MediaGalleryViewModel {
}
}
public struct Item: FetchableRecordWithRowId, Decodable, Identifiable, Differentiable, Equatable, Hashable {
fileprivate static let interactionIdKey: SQL = SQL(stringLiteral: CodingKeys.interactionId.stringValue)
fileprivate static let interactionVariantKey: SQL = SQL(stringLiteral: CodingKeys.interactionVariant.stringValue)
fileprivate static let interactionAuthorIdKey: SQL = SQL(stringLiteral: CodingKeys.interactionAuthorId.stringValue)
fileprivate static let interactionTimestampMsKey: SQL = SQL(stringLiteral: CodingKeys.interactionTimestampMs.stringValue)
fileprivate static let rowIdKey: SQL = SQL(stringLiteral: CodingKeys.rowId.stringValue)
fileprivate static let attachmentKey: SQL = SQL(stringLiteral: CodingKeys.attachment.stringValue)
fileprivate static let attachmentAlbumIndexKey: SQL = SQL(stringLiteral: CodingKeys.attachmentAlbumIndex.stringValue)
fileprivate static let attachmentString: String = CodingKeys.attachment.stringValue
public struct Item: FetchableRecordWithRowId, Decodable, Identifiable, Differentiable, Equatable, Hashable, ColumnExpressible {
public typealias Columns = CodingKeys
public enum CodingKeys: String, CodingKey, ColumnExpression, CaseIterable {
case interactionId
case interactionVariant
case interactionAuthorId
case interactionTimestampMs
case rowId
case attachmentAlbumIndex
case attachment
}
public var id: String { attachment.id }
public var differenceIdentifier: String { attachment.id }
@ -306,7 +308,7 @@ public class MediaGalleryViewModel {
let finalFilterSQL: SQL = {
guard let customFilters: SQL = customFilters else {
return """
WHERE \(attachment.alias[Column.rowID]) IN \(rowIds)
WHERE \(attachment[.rowId]) IN \(rowIds)
"""
}
@ -318,14 +320,14 @@ public class MediaGalleryViewModel {
}()
let request: SQLRequest<Item> = """
SELECT
\(interaction[.id]) AS \(Item.interactionIdKey),
\(interaction[.variant]) AS \(Item.interactionVariantKey),
\(interaction[.authorId]) AS \(Item.interactionAuthorIdKey),
\(interaction[.timestampMs]) AS \(Item.interactionTimestampMsKey),
\(interaction[.id]) AS \(Item.Columns.interactionId),
\(interaction[.variant]) AS \(Item.Columns.interactionVariant),
\(interaction[.authorId]) AS \(Item.Columns.interactionAuthorId),
\(interaction[.timestampMs]) AS \(Item.Columns.interactionTimestampMs),
\(attachment.alias[Column.rowID]) AS \(Item.rowIdKey),
\(interactionAttachment[.albumIndex]) AS \(Item.attachmentAlbumIndexKey),
\(Item.attachmentKey).*
\(attachment[.rowId]) AS \(Item.Columns.rowId),
\(interactionAttachment[.albumIndex]) AS \(Item.Columns.attachmentAlbumIndex),
\(attachment.allColumns)
FROM \(Attachment.self)
\(joinSQL)
\(finalFilterSQL)
@ -338,8 +340,8 @@ public class MediaGalleryViewModel {
Attachment.numberOfSelectedColumns(db)
])
return ScopeAdapter([
Item.attachmentString: adapters[1]
return ScopeAdapter.with(Item.self, [
.attachment: adapters[1]
])
}
}

View File

@ -6,6 +6,8 @@ import SessionUIKit
import SessionMessagingKit
import SignalUtilitiesKit
import SignalCoreKit
import SessionUtilitiesKit
import SessionSnodeKit
class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSource, UIPageViewControllerDelegate, MediaDetailViewControllerDelegate, InteractivelyDismissableViewController {
class DynamicallySizedView: UIView {

View File

@ -7,6 +7,7 @@ import DifferenceKit
import SessionUIKit
import SignalUtilitiesKit
import SignalCoreKit
import SessionUtilitiesKit
public class MediaTileViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout {

View File

@ -6,6 +6,7 @@ import AVFoundation
import SessionUIKit
import SignalUtilitiesKit
import SignalCoreKit
import SessionUtilitiesKit
protocol PhotoCaptureViewControllerDelegate: AnyObject {
func photoCaptureViewController(_ photoCaptureViewController: PhotoCaptureViewController, didFinishProcessingAttachment attachment: SignalAttachment)

View File

@ -6,6 +6,7 @@ import Photos
import CoreServices
import SignalUtilitiesKit
import SignalCoreKit
import SessionUtilitiesKit
protocol PhotoLibraryDelegate: AnyObject {
func photoLibraryDidChange(_ photoLibrary: PhotoLibrary)

View File

@ -6,6 +6,7 @@ import Photos
import SignalUtilitiesKit
import SignalCoreKit
import SessionUIKit
import SessionUtilitiesKit
class SendMediaNavigationController: UINavigationController {
public override var preferredStatusBarStyle: UIStatusBarStyle {
@ -539,8 +540,8 @@ private struct MediaLibrarySelection: Hashable, Equatable {
let asset: PHAsset
let signalAttachmentPublisher: AnyPublisher<SignalAttachment, Error>
var hashValue: Int {
return asset.hashValue
func hash(into hasher: inout Hasher) {
asset.hash(into: &hasher)
}
var publisher: AnyPublisher<MediaLibraryAttachment, Error> {
@ -559,8 +560,8 @@ private struct MediaLibraryAttachment: Hashable, Equatable {
let asset: PHAsset
let signalAttachment: SignalAttachment
public var hashValue: Int {
return asset.hashValue
func hash(into hasher: inout Hasher) {
asset.hash(into: &hasher)
}
public static func == (lhs: MediaLibraryAttachment, rhs: MediaLibraryAttachment) -> Bool {

View File

@ -9,6 +9,7 @@ import SessionMessagingKit
import SessionUtilitiesKit
import SignalUtilitiesKit
import SignalCoreKit
import SessionSnodeKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
@ -522,7 +523,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
startPollersIfNeeded()
if CurrentAppContext().isMainApp {
syncConfigurationIfNeeded()
handleAppActivatedWithOngoingCallIfNeeded()
}
}
@ -868,36 +868,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
presentingVC.present(callVC, animated: true, completion: nil)
}
// MARK: - Config Sync
func syncConfigurationIfNeeded() {
// FIXME: Remove this once `useSharedUtilForUserConfig` is permanent
guard !SessionUtil.userConfigsEnabled else { return }
let lastSync: Date = (UserDefaults.standard[.lastConfigurationSync] ?? .distantPast)
guard Date().timeIntervalSince(lastSync) > (7 * 24 * 60 * 60) else { return } // Sync every 2 days
Storage.shared
.writeAsync(
updates: { db in
ConfigurationSyncJob.enqueue(db, publicKey: getUserHexEncodedPublicKey(db))
},
completion: { _, result in
switch result {
case .failure: break
case .success:
// Only update the 'lastConfigurationSync' timestamp if we have done the
// first sync (Don't want a new device config sync to override config
// syncs from other devices)
if UserDefaults.standard[.hasSyncedInitialConfiguration] {
UserDefaults.standard[.lastConfigurationSync] = Date()
}
}
}
)
}
}
// MARK: - LifecycleMethod

View File

@ -4,6 +4,7 @@ import Foundation
import SessionUtilitiesKit
import SignalUtilitiesKit
import SignalCoreKit
import SessionMessagingKit
public class AppEnvironment {

View File

@ -1,17 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import <SessionUtilitiesKit/AppContext.h>
NS_ASSUME_NONNULL_BEGIN
extern NSString *const ReportedApplicationStateDidChangeNotification;
@interface MainAppContext : NSObject <AppContext>
- (instancetype)init;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,314 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "MainAppContext.h"
#import "Session-Swift.h"
#import <SignalCoreKit/OWSAsserts.h>
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
NS_ASSUME_NONNULL_BEGIN
NSString *const ReportedApplicationStateDidChangeNotification = @"ReportedApplicationStateDidChangeNotification";
@interface MainAppContext ()
@property (atomic) UIApplicationState reportedApplicationState;
@property (nonatomic, nullable) NSMutableArray<AppActiveBlock> *appActiveBlocks;
@end
#pragma mark -
@implementation MainAppContext
@synthesize mainWindow = _mainWindow;
@synthesize appLaunchTime = _appLaunchTime;
@synthesize wasWokenUpByPushNotification = _wasWokenUpByPushNotification;
- (instancetype)init
{
self = [super init];
if (!self) {
return self;
}
self.reportedApplicationState = UIApplicationStateInactive;
_appLaunchTime = [NSDate new];
_wasWokenUpByPushNotification = false;
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillEnterForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillResignActive:)
name:UIApplicationWillResignActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationWillTerminate:)
name:UIApplicationWillTerminateNotification
object:nil];
self.appActiveBlocks = [NSMutableArray new];
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
#pragma mark - Notifications
- (void)setReportedApplicationState:(UIApplicationState)reportedApplicationState
{
OWSAssertIsOnMainThread();
if (_reportedApplicationState == reportedApplicationState) {
return;
}
_reportedApplicationState = reportedApplicationState;
[[NSNotificationCenter defaultCenter] postNotificationName:ReportedApplicationStateDidChangeNotification
object:nil
userInfo:nil];
}
- (void)applicationWillEnterForeground:(NSNotification *)notification
{
OWSAssertIsOnMainThread();
self.reportedApplicationState = UIApplicationStateInactive;
OWSLogInfo(@"");
[NSNotificationCenter.defaultCenter postNotificationName:OWSApplicationWillEnterForegroundNotification object:nil];
}
- (void)applicationDidEnterBackground:(NSNotification *)notification
{
OWSAssertIsOnMainThread();
self.reportedApplicationState = UIApplicationStateBackground;
OWSLogInfo(@"");
[DDLog flushLog];
[NSNotificationCenter.defaultCenter postNotificationName:OWSApplicationDidEnterBackgroundNotification object:nil];
}
- (void)applicationWillResignActive:(NSNotification *)notification
{
OWSAssertIsOnMainThread();
self.reportedApplicationState = UIApplicationStateInactive;
OWSLogInfo(@"");
[DDLog flushLog];
[NSNotificationCenter.defaultCenter postNotificationName:OWSApplicationWillResignActiveNotification object:nil];
}
- (void)applicationDidBecomeActive:(NSNotification *)notification
{
OWSAssertIsOnMainThread();
self.reportedApplicationState = UIApplicationStateActive;
OWSLogInfo(@"");
[NSNotificationCenter.defaultCenter postNotificationName:OWSApplicationDidBecomeActiveNotification object:nil];
[self runAppActiveBlocks];
}
- (void)applicationWillTerminate:(NSNotification *)notification
{
OWSAssertIsOnMainThread();
OWSLogInfo(@"");
[DDLog flushLog];
}
#pragma mark -
- (BOOL)isMainApp
{
return YES;
}
- (BOOL)isMainAppAndActive
{
return [UIApplication sharedApplication].applicationState == UIApplicationStateActive;
}
- (BOOL)isShareExtension {
return NO;
}
- (BOOL)isRTL
{
// FIXME: We should try to remove this as we've had to add a hack to ensure the first call to this runs on the main thread
static BOOL isRTL = NO;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
isRTL = [[UIApplication sharedApplication] userInterfaceLayoutDirection]
== UIUserInterfaceLayoutDirectionRightToLeft;
});
return isRTL;
}
- (void)setStatusBarHidden:(BOOL)isHidden animated:(BOOL)isAnimated
{
[[UIApplication sharedApplication] setStatusBarHidden:isHidden animated:isAnimated];
}
- (CGFloat)statusBarHeight
{
return [UIApplication sharedApplication].statusBarFrame.size.height;
}
- (BOOL)isInBackground
{
return self.reportedApplicationState == UIApplicationStateBackground;
}
- (BOOL)isAppForegroundAndActive
{
return self.reportedApplicationState == UIApplicationStateActive;
}
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:
(BackgroundTaskExpirationHandler)expirationHandler
{
return [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:expirationHandler];
}
- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)backgroundTaskIdentifier
{
[UIApplication.sharedApplication endBackgroundTask:backgroundTaskIdentifier];
}
- (void)ensureSleepBlocking:(BOOL)shouldBeBlocking blockingObjects:(NSArray<id> *)blockingObjects
{
if (UIApplication.sharedApplication.isIdleTimerDisabled != shouldBeBlocking) {
if (shouldBeBlocking) {
NSMutableString *logString =
[NSMutableString stringWithFormat:@"Blocking sleep because of: %@", blockingObjects.firstObject];
if (blockingObjects.count > 1) {
[logString appendString:[NSString stringWithFormat:@"(and %lu others)", blockingObjects.count - 1]];
}
OWSLogInfo(@"%@", logString);
} else {
OWSLogInfo(@"Unblocking Sleep.");
}
}
UIApplication.sharedApplication.idleTimerDisabled = shouldBeBlocking;
}
- (void)setMainAppBadgeNumber:(NSInteger)value
{
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:value];
[[NSUserDefaults sharedLokiProject] setInteger:value forKey:@"currentBadgeNumber"];
[[NSUserDefaults sharedLokiProject] synchronize];
}
- (nullable UIViewController *)frontmostViewController
{
return UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts;
}
- (nullable UIAlertAction *)openSystemSettingsAction
{
return [UIAlertAction actionWithTitle:CommonStrings.openSettingsButton
accessibilityIdentifier:[NSString stringWithFormat:@"%@.%@", self.class, @"system_settings"]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
[UIApplication.sharedApplication openSystemSettings];
}];
}
- (void)setNetworkActivityIndicatorVisible:(BOOL)value
{
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:value];
}
#pragma mark -
- (void)runNowOrWhenMainAppIsActive:(AppActiveBlock)block
{
OWSAssertDebug(block);
[Threading dispatchMainThreadSafe:^{
if (self.isMainAppAndActive) {
// App active blocks typically will be used to safely access the
// shared data container, so use a background task to protect this
// work.
OWSBackgroundTask *_Nullable backgroundTask =
[OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
block();
OWSAssertDebug(backgroundTask);
backgroundTask = nil;
return;
}
[self.appActiveBlocks addObject:block];
}];
}
- (void)runAppActiveBlocks
{
OWSAssertIsOnMainThread();
OWSAssertDebug(self.isMainAppAndActive);
// App active blocks typically will be used to safely access the
// shared data container, so use a background task to protect this
// work.
OWSBackgroundTask *_Nullable backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
NSArray<AppActiveBlock> *appActiveBlocks = [self.appActiveBlocks copy];
[self.appActiveBlocks removeAllObjects];
for (AppActiveBlock block in appActiveBlocks) {
block();
}
OWSAssertDebug(backgroundTask);
backgroundTask = nil;
}
- (NSString *)appDocumentDirectoryPath
{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *documentDirectoryURL =
[[fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
return [documentDirectoryURL path];
}
- (NSString *)appSharedDataDirectoryPath
{
NSURL *groupContainerDirectoryURL =
[[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:SignalApplicationGroup];
return [groupContainerDirectoryURL path];
}
- (NSUserDefaults *)appUserDefaults
{
return [[NSUserDefaults alloc] initWithSuiteName:SignalApplicationGroup];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,253 @@
// Copyright © 2023 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import SignalCoreKit
import SessionUtilitiesKit
final class MainAppContext: NSObject, AppContext {
var reportedApplicationState: UIApplication.State
let appLaunchTime = Date()
let isMainApp: Bool = true
var isMainAppAndActive: Bool { UIApplication.shared.applicationState == .active }
var isShareExtension: Bool = false
var appActiveBlocks: [AppActiveBlock] = []
var mainWindow: UIWindow?
var wasWokenUpByPushNotification: Bool = false
private static var _isRTL: Bool = {
return (UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft)
}()
var isRTL: Bool { return MainAppContext._isRTL }
var statusBarHeight: CGFloat { UIApplication.shared.statusBarFrame.size.height }
var openSystemSettingsAction: UIAlertAction? {
let result = UIAlertAction(
title: "OPEN_SETTINGS_BUTTON".localized(),
style: .default
) { _ in UIApplication.shared.openSystemSettings() }
result.accessibilityIdentifier = "\(type(of: self)).system_settings"
return result
}
// MARK: - Initialization
override init() {
self.reportedApplicationState = .inactive
super.init()
NotificationCenter.default.addObserver(
self,
selector: #selector(applicationWillEnterForeground(notification:)),
name: UIApplication.willEnterForegroundNotification,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(applicationDidEnterBackground(notification:)),
name: UIApplication.didEnterBackgroundNotification,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(applicationWillResignActive(notification:)),
name: UIApplication.willResignActiveNotification,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(applicationDidBecomeActive(notification:)),
name: UIApplication.didBecomeActiveNotification,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(applicationWillTerminate(notification:)),
name: UIApplication.willTerminateNotification,
object: nil
)
}
deinit {
NotificationCenter.default.removeObserver(self)
}
// MARK: - Notifications
@objc private func applicationWillEnterForeground(notification: NSNotification) {
AssertIsOnMainThread()
self.reportedApplicationState = .inactive
OWSLogger.info("")
NotificationCenter.default.post(
name: .OWSApplicationWillEnterForeground,
object: nil
)
}
@objc private func applicationDidEnterBackground(notification: NSNotification) {
AssertIsOnMainThread()
self.reportedApplicationState = .background
OWSLogger.info("")
DDLog.flushLog()
NotificationCenter.default.post(
name: .OWSApplicationDidEnterBackground,
object: nil
)
}
@objc private func applicationWillResignActive(notification: NSNotification) {
AssertIsOnMainThread()
self.reportedApplicationState = .inactive
OWSLogger.info("")
DDLog.flushLog()
NotificationCenter.default.post(
name: .OWSApplicationWillResignActive,
object: nil
)
}
@objc private func applicationDidBecomeActive(notification: NSNotification) {
AssertIsOnMainThread()
self.reportedApplicationState = .active
OWSLogger.info("")
NotificationCenter.default.post(
name: .OWSApplicationDidBecomeActive,
object: nil
)
self.runAppActiveBlocks()
}
@objc private func applicationWillTerminate(notification: NSNotification) {
AssertIsOnMainThread()
OWSLogger.info("")
DDLog.flushLog()
}
// MARK: - AppContext Functions
func setStatusBarHidden(_ isHidden: Bool, animated isAnimated: Bool) {
UIApplication.shared.setStatusBarHidden(isHidden, with: (isAnimated ? .slide : .none))
}
func isAppForegroundAndActive() -> Bool {
return (reportedApplicationState == .active)
}
func isInBackground() -> Bool {
return (reportedApplicationState == .background)
}
func beginBackgroundTask(expirationHandler: @escaping BackgroundTaskExpirationHandler) -> UIBackgroundTaskIdentifier {
return UIApplication.shared.beginBackgroundTask(expirationHandler: expirationHandler)
}
func endBackgroundTask(_ backgroundTaskIdentifier: UIBackgroundTaskIdentifier) {
UIApplication.shared.endBackgroundTask(backgroundTaskIdentifier)
}
func ensureSleepBlocking(_ shouldBeBlocking: Bool, blockingObjects: [Any]) {
if UIApplication.shared.isIdleTimerDisabled != shouldBeBlocking {
if shouldBeBlocking {
var logString: String = "Blocking sleep because of: \(String(describing: blockingObjects.first))"
if blockingObjects.count > 1 {
logString = "\(logString) (and \(blockingObjects.count - 1) others)"
}
OWSLogger.info(logString)
}
else {
OWSLogger.info("Unblocking Sleep.")
}
}
UIApplication.shared.isIdleTimerDisabled = shouldBeBlocking
}
func setMainAppBadgeNumber(_ value: Int) {
UIApplication.shared.applicationIconBadgeNumber = value
UserDefaults.sharedLokiProject?.setValue(value, forKey: "currentBadgeNumber")
}
func frontmostViewController() -> UIViewController? {
UIApplication.shared.frontmostViewControllerIgnoringAlerts
}
func setNetworkActivityIndicatorVisible(_ value: Bool) {
UIApplication.shared.isNetworkActivityIndicatorVisible = value
}
// MARK: -
func runNowOr(whenMainAppIsActive block: @escaping AppActiveBlock) {
Threading.dispatchMainThreadSafe { [weak self] in
if self?.isMainAppAndActive == true {
// App active blocks typically will be used to safely access the
// shared data container, so use a background task to protect this
// work.
var backgroundTask: OWSBackgroundTask? = OWSBackgroundTask(label: #function)
block()
if backgroundTask != nil { backgroundTask = nil }
return
}
self?.appActiveBlocks.append(block)
}
}
func runAppActiveBlocks() {
// App active blocks typically will be used to safely access the
// shared data container, so use a background task to protect this
// work.
var backgroundTask: OWSBackgroundTask? = OWSBackgroundTask(label: #function)
let appActiveBlocks: [AppActiveBlock] = self.appActiveBlocks
self.appActiveBlocks.removeAll()
appActiveBlocks.forEach { $0() }
if backgroundTask != nil { backgroundTask = nil }
}
func appDocumentDirectoryPath() -> String {
let targetPath: String? = FileManager.default
.urls(
for: .documentDirectory,
in: .userDomainMask
)
.last?
.path
owsAssertDebug(targetPath != nil)
return (targetPath ?? "")
}
func appSharedDataDirectoryPath() -> String {
let targetPath: String? = FileManager.default
.containerURL(forSecurityApplicationGroupIdentifier: UserDefaults.applicationGroup)?
.path
owsAssertDebug(targetPath != nil)
return (targetPath ?? "")
}
func appUserDefaults() -> UserDefaults {
owsAssertDebug(UserDefaults.sharedLokiProject != nil)
return (UserDefaults.sharedLokiProject ?? UserDefaults.standard)
}
}

View File

@ -7,4 +7,3 @@
#import "OWSBezierPathView.h"
#import "OWSMessageTimerView.h"
#import "OWSWindowManager.h"
#import "MainAppContext.h"

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Bildschirmschutz";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Lesebestätigungen";
"PRIVACY_READ_RECEIPTS_TITLE" = "Lesebestätigungen";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Screen Security";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts";
"PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Protección de pantalla";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Notificaciones de lectura";
"PRIVACY_READ_RECEIPTS_TITLE" = "Notificaciones de lectura";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "امنیت صفحه";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "قفل Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = " برای باز کردن قفل Session به شناسه لمسی، شناسه صورت و یا رمز عبوری ضرورت است.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "رسیدهای خواندن";
"PRIVACY_READ_RECEIPTS_TITLE" = "رسیدهای خواندن";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "رسیدهای خواندن در چت‌های یک به یک روان شود.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Näytön suojaus";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Lukukuittaukset";
"PRIVACY_READ_RECEIPTS_TITLE" = "Lukukuittaukset";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Sécurité de lécran";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Verrouiller Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Requiert Touch ID, Face ID ou votre code pour déverrouiller Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Accusés de lecture";
"PRIVACY_READ_RECEIPTS_TITLE" = "Accusés de lecture";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Envoyer un accusé réception dans les conversations 1 à 1.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Screen Security";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts";
"PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Sigurnost zaslona";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Potvrda o čitanju";
"PRIVACY_READ_RECEIPTS_TITLE" = "Potvrda o čitanju";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Layar Aman";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Pesan terbaca diterima";
"PRIVACY_READ_RECEIPTS_TITLE" = "Pesan terbaca diterima";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Sicurezza schermo";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Ricevute di lettura";
"PRIVACY_READ_RECEIPTS_TITLE" = "Ricevute di lettura";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "スクリーン・セキュリティ";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "既読確認";
"PRIVACY_READ_RECEIPTS_TITLE" = "既読確認";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Scherm beveiliging";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Leesbevestigingen";
"PRIVACY_READ_RECEIPTS_TITLE" = "Leesbevestigingen";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Ochrona ekranu";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Potwierdzenia odczytania";
"PRIVACY_READ_RECEIPTS_TITLE" = "Potwierdzenia odczytania";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Segurança de Tela";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Confirmações de Leitura";
"PRIVACY_READ_RECEIPTS_TITLE" = "Confirmações de Leitura";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Защита экрана";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Уведомления о прочтении";
"PRIVACY_READ_RECEIPTS_TITLE" = "Уведомления о прочтении";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "තිරයේ ආරක්ෂාව";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "කියවූ බවට ලදුපත්";
"PRIVACY_READ_RECEIPTS_TITLE" = "කියවූ බවට ලදුපත්";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Zabezpečenie obrazovky";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Potvrdenia o prečítaní";
"PRIVACY_READ_RECEIPTS_TITLE" = "Potvrdenia o prečítaní";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Skärmsäkerhet";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Läskvittenser";
"PRIVACY_READ_RECEIPTS_TITLE" = "Läskvittenser";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "ความปลอดภัยหน้าจอ";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "แจ้งการอ่านข้อความ";
"PRIVACY_READ_RECEIPTS_TITLE" = "แจ้งการอ่านข้อความ";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "Screen Security";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "Read Receipts";
"PRIVACY_READ_RECEIPTS_TITLE" = "Read Receipts";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "螢幕顯示安全";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "已讀回條";
"PRIVACY_READ_RECEIPTS_TITLE" = "已讀回條";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -483,6 +483,9 @@
"PRIVACY_SECTION_SCREEN_SECURITY" = "屏幕安全";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE" = "Lock Session";
"PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION" = "Require Touch ID, Face ID or your passcode to unlock Session.";
"PRIVACY_SECTION_MESSAGE_REQUESTS" = "Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE" = "Community Message Requests";
"PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION" = "Allow message requests from Community conversations.";
"PRIVACY_SECTION_READ_RECEIPTS" = "已读回执";
"PRIVACY_READ_RECEIPTS_TITLE" = "已读回执";
"PRIVACY_READ_RECEIPTS_DESCRIPTION" = "Send read receipts in one-to-one chats.";
@ -645,6 +648,8 @@
"CONVERSATION_EMPTY_STATE" = "You have no messages from %@. Send a message to start the conversation!";
"CONVERSATION_EMPTY_STATE_READ_ONLY" = "There are no messages in %@.";
"CONVERSATION_EMPTY_STATE_NOTE_TO_SELF" = "You have no messages in %@.";
"COMMUNITY_MESSAGE_REQUEST_DISABLED_EMPTY_STATE" = "%@ has message requests from Community conversations turned off, so you cannot send them a message.";
"USER_CONFIG_OUTDATED_WARNING" = "Some of your devices are using outdated versions. Syncing may be unreliable until they are updated.";
"LOAD_RECOVERY_PASSWORD_ERROR" = "An error occurred when trying to load your recovery password.\n\nPlease export your logs, then upload the file though Session's Help Desk to help resolve this issue.";
"FAILED_TO_STORE_OUTGOING_MESSAGE" = "An error occurred when trying to store the outgoing message for sending, you may need to restart the app before you can send messages.";
"database_inaccessible_error" = "There is an issue opening the database. Please restart the app and try again.";

View File

@ -6,6 +6,8 @@ import GRDB
import SessionMessagingKit
import SignalUtilitiesKit
import SignalCoreKit
import SessionUtilitiesKit
import SessionSnodeKit
/// There are two primary components in our system notification integration:
///

View File

@ -4,8 +4,10 @@ import Foundation
import Combine
import PushKit
import GRDB
import SessionMessagingKit
import SignalUtilitiesKit
import SignalCoreKit
import SessionUtilitiesKit
public enum PushRegistrationError: Error {
case assertionError(description: String)
@ -53,8 +55,6 @@ public enum PushRegistrationError: Error {
Logger.info("")
return registerUserNotificationSettings()
.subscribe(on: DispatchQueue.global(qos: .default))
.receive(on: DispatchQueue.main) // MUST be on main thread
.setFailureType(to: Error.self)
.tryFlatMap { _ -> AnyPublisher<(pushToken: String, voipToken: String), Error> in
#if targetEnvironment(simulator)
@ -75,24 +75,27 @@ public enum PushRegistrationError: Error {
// MARK: Vanilla push token
// Vanilla push token is obtained from the system via AppDelegate
public func didReceiveVanillaPushToken(_ tokenData: Data) {
public func didReceiveVanillaPushToken(_ tokenData: Data, using dependencies: Dependencies = Dependencies()) {
guard let vanillaTokenResolver = self.vanillaTokenResolver else {
owsFailDebug("publisher completion in \(#function) unexpectedly nil")
return
}
vanillaTokenResolver(Result.success(tokenData))
DispatchQueue.global(qos: .default).async(using: dependencies) {
vanillaTokenResolver(Result.success(tokenData))
}
}
// Vanilla push token is obtained from the system via AppDelegate
@objc
public func didFailToReceiveVanillaPushToken(error: Error) {
public func didFailToReceiveVanillaPushToken(error: Error, using dependencies: Dependencies = Dependencies()) {
guard let vanillaTokenResolver = self.vanillaTokenResolver else {
owsFailDebug("publisher completion in \(#function) unexpectedly nil")
return
}
vanillaTokenResolver(Result.failure(error))
DispatchQueue.global(qos: .default).async(using: dependencies) {
vanillaTokenResolver(Result.failure(error))
}
}
// MARK: helpers
@ -111,9 +114,8 @@ public enum PushRegistrationError: Error {
* in this case we've verified that we *have* properly registered notification settings.
*/
private var isSusceptibleToFailedPushRegistration: Bool {
// Only affects users who have disabled both: background refresh *and* notifications
guard UIApplication.shared.backgroundRefreshStatus == .denied else {
guard DispatchQueue.main.sync(execute: { UIApplication.shared.backgroundRefreshStatus }) == .denied else {
return false
}
@ -128,10 +130,7 @@ public enum PushRegistrationError: Error {
return true
}
// FIXME: Might be nice to try to avoid having this required to run on the main thread (follow a similar approach to the 'SyncPushTokensJob' & `Atomic<T>`?)
private func registerForVanillaPushToken() -> AnyPublisher<String, Error> {
AssertIsOnMainThread()
// Use the existing publisher if it exists
if let vanillaTokenPublisher: AnyPublisher<Data, Error> = self.vanillaTokenPublisher {
return vanillaTokenPublisher
@ -139,19 +138,23 @@ public enum PushRegistrationError: Error {
.eraseToAnyPublisher()
}
UIApplication.shared.registerForRemoteNotifications()
// No pending vanilla token yet; create a new publisher
let publisher: AnyPublisher<Data, Error> = Deferred {
Future<Data, Error> { self.vanillaTokenResolver = $0 }
Future<Data, Error> {
self.vanillaTokenResolver = $0
// Tell the device to register for remote notifications
DispatchQueue.main.sync { UIApplication.shared.registerForRemoteNotifications() }
}
}
.shareReplay(1)
.eraseToAnyPublisher()
self.vanillaTokenPublisher = publisher
return publisher
.timeout(
.seconds(10),
scheduler: DispatchQueue.main,
scheduler: DispatchQueue.global(qos: .default),
customError: { PushRegistrationError.timeout }
)
.catch { error -> AnyPublisher<Data, Error> in
@ -200,9 +203,8 @@ public enum PushRegistrationError: Error {
}
public func createVoipRegistryIfNecessary() {
AssertIsOnMainThread()
guard voipRegistry == nil else { return }
let voipRegistry = PKPushRegistry(queue: nil)
self.voipRegistry = voipRegistry
voipRegistry.desiredPushTypes = [.voIP]
@ -210,8 +212,6 @@ public enum PushRegistrationError: Error {
}
private func registerForVoipPushToken() -> AnyPublisher<String?, Error> {
AssertIsOnMainThread()
// Use the existing publisher if it exists
if let voipTokenPublisher: AnyPublisher<Data?, Error> = self.voipTokenPublisher {
return voipTokenPublisher

View File

@ -31,59 +31,39 @@ public enum SyncPushTokensJob: JobExecutor {
return deferred(job, dependencies)
}
// We need to check a UIApplication setting which needs to run on the main thread so synchronously
// retrieve the value so we can continue
let isRegisteredForRemoteNotifications: Bool = {
guard !Thread.isMainThread else {
return UIApplication.shared.isRegisteredForRemoteNotifications
}
return DispatchQueue.main.sync {
return UIApplication.shared.isRegisteredForRemoteNotifications
}
}()
// Apple's documentation states that we should re-register for notifications on every launch:
// https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/HandlingRemoteNotifications.html#//apple_ref/doc/uid/TP40008194-CH6-SW1
guard job.behaviour == .runOnce || !isRegisteredForRemoteNotifications else {
SNLog("[SyncPushTokensJob] Deferred due to Fast Mode disabled")
deferred(job, dependencies) // Don't need to do anything if push notifications are already registered
return
}
// Determine if the device has 'Fast Mode' (APNS) enabled
let isUsingFullAPNs: Bool = UserDefaults.standard[.isUsingFullAPNs]
// If the job is running and 'Fast Mode' is disabled then we should try to unregister the existing
// token
guard isUsingFullAPNs else {
Just(Storage.shared[.lastRecordedPushToken])
Just(dependencies.storage[.lastRecordedPushToken])
.setFailureType(to: Error.self)
.flatMap { lastRecordedPushToken in
.flatMap { lastRecordedPushToken -> AnyPublisher<Void, Error> in
// Tell the device to unregister for remote notifications (essentially try to invalidate
// the token if needed - we do this first to avoid wrid race conditions which could be
// triggered by the user immediately re-registering)
DispatchQueue.main.sync { UIApplication.shared.unregisterForRemoteNotifications() }
// Clear the old token
dependencies.storage.write(using: dependencies) { db in
db[.lastRecordedPushToken] = nil
}
// Unregister from our server
if let existingToken: String = lastRecordedPushToken {
SNLog("[SyncPushTokensJob] Unregister using last recorded push token: \(redact(existingToken))")
return Just(existingToken)
.setFailureType(to: Error.self)
return PushNotificationAPI.unsubscribe(token: Data(hex: existingToken))
.map { _ in () }
.eraseToAnyPublisher()
}
SNLog("[SyncPushTokensJob] Unregister using live token provided from device")
return PushRegistrationManager.shared.requestPushTokens()
.map { token, _ in token }
SNLog("[SyncPushTokensJob] No previous token stored just triggering device unregister")
return Just(())
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
.flatMap { pushToken in PushNotificationAPI.unregister(Data(hex: pushToken)) }
.map {
// Tell the device to unregister for remote notifications (essentially try to invalidate
// the token if needed
DispatchQueue.main.sync { UIApplication.shared.unregisterForRemoteNotifications() }
Storage.shared.write { db in
db[.lastRecordedPushToken] = nil
}
return ()
}
.subscribe(on: queue)
.subscribe(on: queue, using: dependencies)
.sinkUntilComplete(
receiveCompletion: { result in
switch result {
@ -98,17 +78,20 @@ public enum SyncPushTokensJob: JobExecutor {
return
}
// Perform device registration
/// Perform device registration
///
/// **Note:** Apple's documentation states that we should re-register for notifications on every launch:
/// https://developer.apple.com/library/archive/documentation/NetworkingInternet/Conceptual/RemoteNotificationsPG/HandlingRemoteNotifications.html#//apple_ref/doc/uid/TP40008194-CH6-SW1
Logger.info("Re-registering for remote notifications.")
PushRegistrationManager.shared.requestPushTokens()
.flatMap { (pushToken: String, voipToken: String) -> AnyPublisher<Void, Error> in
PushNotificationAPI
.register(
with: Data(hex: pushToken),
publicKey: getUserHexEncodedPublicKey(),
isForcedUpdate: true
.subscribe(
token: Data(hex: pushToken),
isForcedUpdate: true,
using: dependencies
)
.retry(3)
.retry(3, using: dependencies)
.handleEvents(
receiveCompletion: { result in
switch result {
@ -118,9 +101,9 @@ public enum SyncPushTokensJob: JobExecutor {
case .finished:
Logger.warn("Recording push tokens locally. pushToken: \(redact(pushToken)), voipToken: \(redact(voipToken))")
SNLog("[SyncPushTokensJob] Completed")
UserDefaults.standard[.lastPushNotificationSync] = Date()
dependencies.standardUserDefaults[.lastPushNotificationSync] = dependencies.dateNow
Storage.shared.write { db in
dependencies.storage.write(using: dependencies) { db in
db[.lastRecordedPushToken] = pushToken
db[.lastRecordedVoipToken] = voipToken
}
@ -130,7 +113,7 @@ public enum SyncPushTokensJob: JobExecutor {
.map { _ in () }
.eraseToAnyPublisher()
}
.subscribe(on: queue)
.subscribe(on: queue, using: dependencies)
.sinkUntilComplete(
// We want to complete this job regardless of success or failure
receiveCompletion: { _ in success(job, false, dependencies) }
@ -168,5 +151,9 @@ extension SyncPushTokensJob {
// MARK: - Convenience
private func redact(_ string: String) -> String {
return OWSIsDebugBuild() ? string : "[ READACTED \(string.prefix(2))...\(string.suffix(2)) ]"
#if DEBUG
return string
#else
return "[ READACTED \(string.prefix(2))...\(string.suffix(2)) ]"
#endif
}

View File

@ -6,6 +6,7 @@ import UserNotifications
import SessionMessagingKit
import SignalCoreKit
import SignalUtilitiesKit
import SessionUtilitiesKit
class UserNotificationConfig {

View File

@ -30,13 +30,6 @@ enum Onboarding {
_ requestId: UUID,
using dependencies: Dependencies = Dependencies()
) -> AnyPublisher<String?, Error> {
// FIXME: Remove this once `useSharedUtilForUserConfig` is permanent
guard SessionUtil.userConfigsEnabled else {
return Just(nil)
.setFailureType(to: Error.self)
.eraseToAnyPublisher()
}
let userPublicKey: String = getUserHexEncodedPublicKey()
return SnodeAPI.getSwarm(for: userPublicKey)
@ -258,9 +251,9 @@ enum Onboarding {
// Notify the app that registration is complete
Identity.didRegister()
// Now that we have registered get the Snode pool and sync push tokens
// Now that we have registered get the Snode pool (just in case) - other non-blocking
// launch jobs will automatically be run because the app activation was triggered
GetSnodePoolJob.run()
SyncPushTokensJob.run(uploadOnlyIfStale: false)
}
}
}

View File

@ -6,6 +6,7 @@ import SessionUIKit
import SessionMessagingKit
import SessionSnodeKit
import SignalUtilitiesKit
import SessionUtilitiesKit
final class PNModeVC: BaseVC, OptionViewDelegate {
private let flow: Onboarding.Flow

View File

@ -4,6 +4,7 @@ import UIKit
import Sodium
import SessionUIKit
import SignalUtilitiesKit
import SessionUtilitiesKit
final class RegisterVC : BaseVC {
private var seed: Data! { didSet { updateKeyPair() } }

View File

@ -3,6 +3,7 @@
import UIKit
import SessionUIKit
import SignalUtilitiesKit
import SessionUtilitiesKit
final class AppearanceViewController: BaseVC {
// MARK: - Components

View File

@ -6,6 +6,7 @@ import GRDB
import DifferenceKit
import SessionUIKit
import SignalUtilitiesKit
import SessionUtilitiesKit
class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsViewModel.Section, Profile> {
// MARK: - Section
@ -257,11 +258,12 @@ class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsView
// MARK: - DataModel
public struct DataModel: FetchableRecordWithRowId, Decodable, Equatable, Hashable, Identifiable, Differentiable {
public static let rowIdKey: SQL = SQL(stringLiteral: CodingKeys.rowId.stringValue)
public static let profileKey: SQL = SQL(stringLiteral: CodingKeys.profile.stringValue)
public static let profileString: String = CodingKeys.profile.stringValue
public struct DataModel: FetchableRecordWithRowId, Decodable, Equatable, Hashable, Identifiable, Differentiable, ColumnExpressible {
public typealias Columns = CodingKeys
public enum CodingKeys: String, CodingKey, ColumnExpression, CaseIterable {
case rowId
case profile
}
public var differenceIdentifier: String { profile.id }
public var id: String { profile.id }
@ -285,11 +287,11 @@ class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsView
let request: SQLRequest<DataModel> = """
SELECT
\(profile.alias[Column.rowID]) AS \(DataModel.rowIdKey),
\(DataModel.profileKey).*
\(profile[.rowId]) AS \(DataModel.Columns.rowId),
\(profile.allColumns)
FROM \(Profile.self)
WHERE \(profile.alias[Column.rowID]) IN \(rowIds)
WHERE \(profile[.rowId]) IN \(rowIds)
ORDER BY \(orderSQL)
"""
@ -299,8 +301,8 @@ class BlockedContactsViewModel: SessionTableViewModel<NoNav, BlockedContactsView
Profile.numberOfSelectedColumns(db)
])
return ScopeAdapter([
DataModel.profileString: adapters[1]
return ScopeAdapter.with(DataModel.self, [
.profile: adapters[1]
])
}
}

View File

@ -33,6 +33,11 @@ class ConversationSettingsViewModel: SessionTableViewModel<NoNav, ConversationSe
// MARK: - Content
private struct State: Equatable {
let trimOpenGroupMessagesOlderThanSixMonths: Bool
let shouldAutoPlayConsecutiveAudioMessages: Bool
}
override var title: String { "CONVERSATION_SETTINGS_TITLE".localized() }
public override var observableTableData: ObservableData { _observableTableData }
@ -45,7 +50,17 @@ class ConversationSettingsViewModel: SessionTableViewModel<NoNav, ConversationSe
/// fetch (after the ones in `ValueConcurrentObserver.asyncStart`/`ValueConcurrentObserver.syncStart`)
/// just in case the database has changed between the two reads - unfortunately it doesn't look like there is a way to prevent this
private lazy var _observableTableData: ObservableData = ValueObservation
.trackingConstantRegion { db -> [SectionModel] in
.trackingConstantRegion { [weak self] db -> State in
State(
trimOpenGroupMessagesOlderThanSixMonths: db[.trimOpenGroupMessagesOlderThanSixMonths],
shouldAutoPlayConsecutiveAudioMessages: db[.shouldAutoPlayConsecutiveAudioMessages]
)
}
.removeDuplicates()
.handleEvents(didFail: { SNLog("[ConversationSettingsViewModel] Observation failed with error: \($0)") })
.publisher(in: Storage.shared)
.withPrevious()
.map { (previous: State?, current: State) -> [SectionModel] in
return [
SectionModel(
model: .messageTrimming,
@ -55,7 +70,11 @@ class ConversationSettingsViewModel: SessionTableViewModel<NoNav, ConversationSe
title: "CONVERSATION_SETTINGS_MESSAGE_TRIMMING_TITLE".localized(),
subtitle: "CONVERSATION_SETTINGS_MESSAGE_TRIMMING_DESCRIPTION".localized(),
rightAccessory: .toggle(
.settingBool(key: .trimOpenGroupMessagesOlderThanSixMonths)
.boolValue(
key: .trimOpenGroupMessagesOlderThanSixMonths,
value: current.trimOpenGroupMessagesOlderThanSixMonths,
oldValue: (previous ?? current).trimOpenGroupMessagesOlderThanSixMonths
)
),
onTap: {
Storage.shared.write { db in
@ -73,7 +92,11 @@ class ConversationSettingsViewModel: SessionTableViewModel<NoNav, ConversationSe
title: "CONVERSATION_SETTINGS_AUDIO_MESSAGES_AUTOPLAY_TITLE".localized(),
subtitle: "CONVERSATION_SETTINGS_AUDIO_MESSAGES_AUTOPLAY_DESCRIPTION".localized(),
rightAccessory: .toggle(
.settingBool(key: .shouldAutoPlayConsecutiveAudioMessages)
.boolValue(
key: .shouldAutoPlayConsecutiveAudioMessages,
value: current.shouldAutoPlayConsecutiveAudioMessages,
oldValue: (previous ?? current).shouldAutoPlayConsecutiveAudioMessages
)
),
onTap: {
Storage.shared.write { db in
@ -103,8 +126,5 @@ class ConversationSettingsViewModel: SessionTableViewModel<NoNav, ConversationSe
)
]
}
.removeDuplicates()
.handleEvents(didFail: { SNLog("[ConversationSettingsViewModel] Observation failed with error: \($0)") })
.publisher(in: Storage.shared)
.mapToSessionTableViewData(for: self)
}

View File

@ -1,6 +1,7 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import SessionUtilitiesKit
class ImagePickerHandler: NSObject, UIImagePickerControllerDelegate & UINavigationControllerDelegate {
private let onTransition: (UIViewController, TransitionType) -> Void

View File

@ -7,7 +7,7 @@ import SessionUIKit
import SessionMessagingKit
import SessionUtilitiesKit
class NotificationSettingsViewModel: SessionTableViewModel<NoNav, NotificationSettingsViewModel.Section, NotificationSettingsViewModel.Setting> {
class NotificationSettingsViewModel: SessionTableViewModel<NoNav, NotificationSettingsViewModel.Section, NotificationSettingsViewModel.Item> {
// MARK: - Config
public enum Section: SessionTableSection {
@ -31,7 +31,7 @@ class NotificationSettingsViewModel: SessionTableViewModel<NoNav, NotificationSe
}
}
public enum Setting: Differentiable {
public enum Item: Differentiable {
case strategyUseFastMode
case strategyDeviceSettings
case styleSound
@ -41,6 +41,13 @@ class NotificationSettingsViewModel: SessionTableViewModel<NoNav, NotificationSe
// MARK: - Content
private struct State: Equatable {
let isUsingFullAPNs: Bool
let notificationSound: Preferences.Sound
let playNotificationSoundInForeground: Bool
let previewType: Preferences.NotificationPreviewType
}
override var title: String { "NOTIFICATIONS_TITLE".localized() }
public override var observableTableData: ObservableData { _observableTableData }
@ -53,12 +60,30 @@ class NotificationSettingsViewModel: SessionTableViewModel<NoNav, NotificationSe
/// fetch (after the ones in `ValueConcurrentObserver.asyncStart`/`ValueConcurrentObserver.syncStart`)
/// just in case the database has changed between the two reads - unfortunately it doesn't look like there is a way to prevent this
private lazy var _observableTableData: ObservableData = ValueObservation
.trackingConstantRegion { db -> [SectionModel] in
let notificationSound: Preferences.Sound = db[.defaultNotificationSound]
.defaulting(to: Preferences.Sound.defaultNotificationSound)
let previewType: Preferences.NotificationPreviewType = db[.preferencesNotificationPreviewType]
.defaulting(to: Preferences.NotificationPreviewType.defaultPreviewType)
.trackingConstantRegion { db -> State in
State(
isUsingFullAPNs: false, // Set later the the data flow
notificationSound: db[.defaultNotificationSound]
.defaulting(to: Preferences.Sound.defaultNotificationSound),
playNotificationSoundInForeground: db[.playNotificationSoundInForeground],
previewType: db[.preferencesNotificationPreviewType]
.defaulting(to: Preferences.NotificationPreviewType.defaultPreviewType)
)
}
.removeDuplicates()
.handleEvents(didFail: { SNLog("[NotificationSettingsViewModel] Observation failed with error: \($0)") })
.publisher(in: Storage.shared)
.manualRefreshFrom(forcedRefresh)
.map { dbState -> State in
State(
isUsingFullAPNs: UserDefaults.standard[.isUsingFullAPNs],
notificationSound: dbState.notificationSound,
playNotificationSoundInForeground: dbState.playNotificationSoundInForeground,
previewType: dbState.previewType
)
}
.withPrevious()
.map { (previous: State?, current: State) -> [SectionModel] in
return [
SectionModel(
model: .strategy,
@ -68,20 +93,24 @@ class NotificationSettingsViewModel: SessionTableViewModel<NoNav, NotificationSe
title: "NOTIFICATIONS_STRATEGY_FAST_MODE_TITLE".localized(),
subtitle: "NOTIFICATIONS_STRATEGY_FAST_MODE_DESCRIPTION".localized(),
rightAccessory: .toggle(
.userDefaults(UserDefaults.standard, key: "isUsingFullAPNs")
.boolValue(
current.isUsingFullAPNs,
oldValue: (previous ?? current).isUsingFullAPNs
)
),
styling: SessionCell.StyleInfo(
allowedSeparators: [.top],
customPadding: SessionCell.Padding(bottom: Values.verySmallSpacing)
),
onTap: {
onTap: { [weak self] in
UserDefaults.standard.set(
!UserDefaults.standard.bool(forKey: "isUsingFullAPNs"),
forKey: "isUsingFullAPNs"
)
// Force sync the push tokens on change
SyncPushTokensJob.run(uploadOnlyIfStale: false)
self?.forceRefresh()
}
),
SessionCell.Info(
@ -106,7 +135,7 @@ class NotificationSettingsViewModel: SessionTableViewModel<NoNav, NotificationSe
id: .styleSound,
title: "NOTIFICATIONS_STYLE_SOUND_TITLE".localized(),
rightAccessory: .dropDown(
.dynamicString { notificationSound.displayName }
.dynamicString { current.notificationSound.displayName }
),
onTap: { [weak self] in
self?.transitionToScreen(
@ -117,7 +146,13 @@ class NotificationSettingsViewModel: SessionTableViewModel<NoNav, NotificationSe
SessionCell.Info(
id: .styleSoundWhenAppIsOpen,
title: "NOTIFICATIONS_STYLE_SOUND_WHEN_OPEN_TITLE".localized(),
rightAccessory: .toggle(.settingBool(key: .playNotificationSoundInForeground)),
rightAccessory: .toggle(
.boolValue(
key: .playNotificationSoundInForeground,
value: current.playNotificationSoundInForeground,
oldValue: (previous ?? current).playNotificationSoundInForeground
)
),
onTap: {
Storage.shared.write { db in
db[.playNotificationSoundInForeground] = !db[.playNotificationSoundInForeground]
@ -134,7 +169,7 @@ class NotificationSettingsViewModel: SessionTableViewModel<NoNav, NotificationSe
title: "NOTIFICATIONS_STYLE_CONTENT_TITLE".localized(),
subtitle: "NOTIFICATIONS_STYLE_CONTENT_DESCRIPTION".localized(),
rightAccessory: .dropDown(
.dynamicString { previewType.name }
.dynamicString { current.previewType.name }
),
onTap: { [weak self] in
self?.transitionToScreen(
@ -146,8 +181,5 @@ class NotificationSettingsViewModel: SessionTableViewModel<NoNav, NotificationSe
)
]
}
.removeDuplicates()
.handleEvents(didFail: { SNLog("[NotificationSettingsViewModel] Observation failed with error: \($0)") })
.publisher(in: Storage.shared)
.mapToSessionTableViewData(for: self)
}

View File

@ -5,6 +5,7 @@ import SessionUIKit
import SessionSnodeKit
import SessionMessagingKit
import SignalUtilitiesKit
import SessionUtilitiesKit
final class NukeDataModal: Modal {
// MARK: - Initialization
@ -226,8 +227,9 @@ final class NukeDataModal: Modal {
let maybeDeviceToken: String? = UserDefaults.standard[.deviceToken]
if isUsingFullAPNs, let deviceToken: String = maybeDeviceToken {
let data: Data = Data(hex: deviceToken)
PushNotificationAPI.unregister(data).sinkUntilComplete()
PushNotificationAPI
.unsubscribe(token: Data(hex: deviceToken))
.sinkUntilComplete()
}
/// Stop and cancel all current jobs (don't want to inadvertantly have a job store data after it's table has already been cleared)

View File

@ -28,6 +28,7 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
public enum Section: SessionTableSection {
case screenSecurity
case messageRequests
case readReceipts
case typingIndicators
case linkPreviews
@ -36,6 +37,7 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
var title: String? {
switch self {
case .screenSecurity: return "PRIVACY_SECTION_SCREEN_SECURITY".localized()
case .messageRequests: return "PRIVACY_SECTION_MESSAGE_REQUESTS".localized()
case .readReceipts: return "PRIVACY_SECTION_READ_RECEIPTS".localized()
case .typingIndicators: return "PRIVACY_SECTION_TYPING_INDICATORS".localized()
case .linkPreviews: return "PRIVACY_SECTION_LINK_PREVIEWS".localized()
@ -48,6 +50,7 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
public enum Item: Differentiable {
case screenLock
case communityMessageRequests
case screenshotNotifications
case readReceipts
case typingIndicators
@ -75,6 +78,15 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
// MARK: - Content
private struct State: Equatable {
let isScreenLockEnabled: Bool
let checkForCommunityMessageRequests: Bool
let areReadReceiptsEnabled: Bool
let typingIndicatorsEnabled: Bool
let areLinkPreviewsEnabled: Bool
let areCallsEnabled: Bool
}
override var title: String { "PRIVACY_TITLE".localized() }
public override var observableTableData: ObservableData { _observableTableData }
@ -87,7 +99,21 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
/// fetch (after the ones in `ValueConcurrentObserver.asyncStart`/`ValueConcurrentObserver.syncStart`)
/// just in case the database has changed between the two reads - unfortunately it doesn't look like there is a way to prevent this
private lazy var _observableTableData: ObservableData = ValueObservation
.trackingConstantRegion { db -> [SectionModel] in
.trackingConstantRegion { [weak self] db -> State in
State(
isScreenLockEnabled: db[.isScreenLockEnabled],
checkForCommunityMessageRequests: db[.checkForCommunityMessageRequests],
areReadReceiptsEnabled: db[.areReadReceiptsEnabled],
typingIndicatorsEnabled: db[.typingIndicatorsEnabled],
areLinkPreviewsEnabled: db[.areLinkPreviewsEnabled],
areCallsEnabled: db[.areCallsEnabled]
)
}
.removeDuplicates()
.handleEvents(didFail: { SNLog("[PrivacySettingsViewModel] Observation failed with error: \($0)") })
.publisher(in: Storage.shared)
.withPrevious()
.map { (previous: State?, current: State) -> [SectionModel] in
return [
SectionModel(
model: .screenSecurity,
@ -96,7 +122,13 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
id: .screenLock,
title: "PRIVACY_SCREEN_SECURITY_LOCK_SESSION_TITLE".localized(),
subtitle: "PRIVACY_SCREEN_SECURITY_LOCK_SESSION_DESCRIPTION".localized(),
rightAccessory: .toggle(.settingBool(key: .isScreenLockEnabled)),
rightAccessory: .toggle(
.boolValue(
key: .isScreenLockEnabled,
value: current.isScreenLockEnabled,
oldValue: (previous ?? current).isScreenLockEnabled
)
),
onTap: { [weak self] in
// Make sure the device has a passcode set before allowing screen lock to
// be enabled (Note: This will always return true on a simulator)
@ -115,7 +147,32 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
}
Storage.shared.write { db in
db[.isScreenLockEnabled] = !db[.isScreenLockEnabled]
try db.setAndUpdateConfig(.isScreenLockEnabled, to: !db[.isScreenLockEnabled])
}
}
)
]
),
SectionModel(
model: .messageRequests,
elements: [
SessionCell.Info(
id: .communityMessageRequests,
title: "PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_TITLE".localized(),
subtitle: "PRIVACY_SCREEN_MESSAGE_REQUESTS_COMMUNITY_DESCRIPTION".localized(),
rightAccessory: .toggle(
.boolValue(
key: .checkForCommunityMessageRequests,
value: current.checkForCommunityMessageRequests,
oldValue: (previous ?? current).checkForCommunityMessageRequests
)
),
onTap: { [weak self] in
Storage.shared.write { db in
try db.setAndUpdateConfig(
.checkForCommunityMessageRequests,
to: !db[.checkForCommunityMessageRequests]
)
}
}
)
@ -128,10 +185,16 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
id: .readReceipts,
title: "PRIVACY_READ_RECEIPTS_TITLE".localized(),
subtitle: "PRIVACY_READ_RECEIPTS_DESCRIPTION".localized(),
rightAccessory: .toggle(.settingBool(key: .areReadReceiptsEnabled)),
rightAccessory: .toggle(
.boolValue(
key: .areReadReceiptsEnabled,
value: current.areReadReceiptsEnabled,
oldValue: (previous ?? current).areReadReceiptsEnabled
)
),
onTap: {
Storage.shared.write { db in
db[.areReadReceiptsEnabled] = !db[.areReadReceiptsEnabled]
try db.setAndUpdateConfig(.areReadReceiptsEnabled, to: !db[.areReadReceiptsEnabled])
}
}
)
@ -176,10 +239,16 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
return result
}
),
rightAccessory: .toggle(.settingBool(key: .typingIndicatorsEnabled)),
rightAccessory: .toggle(
.boolValue(
key: .typingIndicatorsEnabled,
value: current.typingIndicatorsEnabled,
oldValue: (previous ?? current).typingIndicatorsEnabled
)
),
onTap: {
Storage.shared.write { db in
db[.typingIndicatorsEnabled] = !db[.typingIndicatorsEnabled]
try db.setAndUpdateConfig(.typingIndicatorsEnabled, to: !db[.typingIndicatorsEnabled])
}
}
)
@ -192,10 +261,16 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
id: .linkPreviews,
title: "PRIVACY_LINK_PREVIEWS_TITLE".localized(),
subtitle: "PRIVACY_LINK_PREVIEWS_DESCRIPTION".localized(),
rightAccessory: .toggle(.settingBool(key: .areLinkPreviewsEnabled)),
rightAccessory: .toggle(
.boolValue(
key: .areLinkPreviewsEnabled,
value: current.areLinkPreviewsEnabled,
oldValue: (previous ?? current).areLinkPreviewsEnabled
)
),
onTap: {
Storage.shared.write { db in
db[.areLinkPreviewsEnabled] = !db[.areLinkPreviewsEnabled]
try db.setAndUpdateConfig(.areLinkPreviewsEnabled, to: !db[.areLinkPreviewsEnabled])
}
}
)
@ -208,7 +283,13 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
id: .calls,
title: "PRIVACY_CALLS_TITLE".localized(),
subtitle: "PRIVACY_CALLS_DESCRIPTION".localized(),
rightAccessory: .toggle(.settingBool(key: .areCallsEnabled)),
rightAccessory: .toggle(
.boolValue(
key: .areCallsEnabled,
value: current.areCallsEnabled,
oldValue: (previous ?? current).areCallsEnabled
)
),
accessibility: Accessibility(
label: "Allow voice and video calls"
),
@ -223,7 +304,7 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
),
onTap: {
Storage.shared.write { db in
db[.areCallsEnabled] = !db[.areCallsEnabled]
try db.setAndUpdateConfig(.areCallsEnabled, to: !db[.areCallsEnabled])
}
}
)
@ -231,8 +312,5 @@ class PrivacySettingsViewModel: SessionTableViewModel<PrivacySettingsViewModel.N
)
]
}
.removeDuplicates()
.handleEvents(didFail: { SNLog("[PrivacySettingsViewModel] Observation failed with error: \($0)") })
.publisher(in: Storage.shared)
.mapToSessionTableViewData(for: self)
}

View File

@ -2,6 +2,7 @@
import UIKit
import SessionUIKit
import SessionUtilitiesKit
public protocol CaptionContainerViewDelegate: AnyObject {
func captionContainerViewDidUpdateText(_ captionContainerView: CaptionContainerView)

View File

@ -4,6 +4,7 @@ import UIKit
import SessionUIKit
import SignalUtilitiesKit
import SessionMessagingKit
import SessionUtilitiesKit
public final class FullConversationCell: UITableViewCell, SwipeActionOptimisticCell {
public static let mutePrefix: String = "\u{e067} "

View File

@ -262,7 +262,7 @@ class SessionTableViewController<NavItemId: Equatable, Section: SessionTableSect
reloadSectionsAnimation: .none,
deleteRowsAnimation: .fade,
insertRowsAnimation: .fade,
reloadRowsAnimation: .fade,
reloadRowsAnimation: .none,
interrupt: { $0.changeCount > 100 } // Prevent too many changes from causing performance issues
) { [weak self] updatedData in
self?.viewModel.updateTableData(updatedData)
@ -339,6 +339,7 @@ class SessionTableViewController<NavItemId: Equatable, Section: SessionTableSect
.store(in: &disposables)
viewModel.leftNavItems
.receive(on: DispatchQueue.main)
.sink { [weak self] maybeItems in
self?.navigationItem.setLeftBarButtonItems(
maybeItems.map { items in
@ -360,6 +361,7 @@ class SessionTableViewController<NavItemId: Equatable, Section: SessionTableSect
.store(in: &disposables)
viewModel.rightNavItems
.receive(on: DispatchQueue.main)
.sink { [weak self] maybeItems in
self?.navigationItem.setRightBarButtonItems(
maybeItems.map { items in
@ -381,18 +383,21 @@ class SessionTableViewController<NavItemId: Equatable, Section: SessionTableSect
.store(in: &disposables)
viewModel.emptyStateTextPublisher
.receive(on: DispatchQueue.main)
.sink { [weak self] text in
self?.emptyStateLabel.text = text
}
.store(in: &disposables)
viewModel.footerView
.receive(on: DispatchQueue.main)
.sink { [weak self] footerView in
self?.tableView.tableFooterView = footerView
}
.store(in: &disposables)
viewModel.footerButtonInfo
.receive(on: DispatchQueue.main)
.sink { [weak self] buttonInfo in
if let buttonInfo: SessionButton.Info = buttonInfo {
self?.footerButton.setTitle(buttonInfo.title, for: .normal)
@ -627,7 +632,7 @@ class SessionTableViewController<NavItemId: Equatable, Section: SessionTableSect
) {
// Try update the existing cell to have a nice animation instead of reloading the cell
if let existingCell: SessionCell = tableView.cellForRow(at: indexPath) as? SessionCell {
existingCell.update(with: info)
existingCell.update(with: info, isManualReload: true)
}
else {
tableView.reloadRows(at: [indexPath], with: .none)

View File

@ -27,6 +27,9 @@ class SessionTableViewModel<NavItemId: Equatable, Section: SessionTableSection,
open var leftNavItems: AnyPublisher<[NavItem]?, Never> { Just(nil).eraseToAnyPublisher() }
open var rightNavItems: AnyPublisher<[NavItem]?, Never> { Just(nil).eraseToAnyPublisher() }
private let _forcedRefresh: PassthroughSubject<Void, Never> = PassthroughSubject()
lazy var forcedRefresh: AnyPublisher<Void, Never> = _forcedRefresh
.shareReplay(0)
private let _showToast: PassthroughSubject<(String, ThemeValue), Never> = PassthroughSubject()
lazy var showToast: AnyPublisher<(String, ThemeValue), Never> = _showToast
.shareReplay(0)
@ -62,6 +65,10 @@ class SessionTableViewModel<NavItemId: Equatable, Section: SessionTableSection,
// MARK: - Functions
func forceRefresh() {
_forcedRefresh.send(())
}
func setIsEditing(_ isEditing: Bool) {
_isEditing.send(isEditing)
}
@ -101,7 +108,7 @@ extension Array {
}
}
extension AnyPublisher {
extension Publisher {
func mapToSessionTableViewData<Nav, Section, Item>(
for viewModel: SessionTableViewModel<Nav, Section, Item>
) -> AnyPublisher<(Output, StagedChangeset<Output>), Failure> where Output == [ArraySection<Section, SessionCell.Info<Item>>] {

View File

@ -394,19 +394,30 @@ extension SessionCell.Accessory {
extension SessionCell.Accessory {
public enum DataSource: Hashable, Equatable {
case boolValue(Bool)
case boolValue(key: String, value: Bool, oldValue: Bool)
case dynamicString(() -> String?)
case userDefaults(UserDefaults, key: String)
case settingBool(key: Setting.BoolKey)
static func boolValue(_ value: Bool, oldValue: Bool) -> DataSource {
return .boolValue(key: "", value: value, oldValue: oldValue)
}
static func boolValue(key: Setting.BoolKey, value: Bool, oldValue: Bool) -> DataSource {
return .boolValue(key: key.rawValue, value: value, oldValue: oldValue)
}
// MARK: - Convenience
public var currentBoolValue: Bool {
switch self {
case .boolValue(let value): return value
case .boolValue(_, let value, _): return value
case .dynamicString: return false
case .userDefaults(let defaults, let key): return defaults.bool(forKey: key)
case .settingBool(let key): return Storage.shared[key]
}
}
public var oldBoolValue: Bool {
switch self {
case .boolValue(_, _, let oldValue): return oldValue
default: return false
}
}
@ -421,27 +432,27 @@ extension SessionCell.Accessory {
public func hash(into hasher: inout Hasher) {
switch self {
case .boolValue(let value): value.hash(into: &hasher)
case .boolValue(let key, let value, let oldValue):
key.hash(into: &hasher)
value.hash(into: &hasher)
oldValue.hash(into: &hasher)
case .dynamicString(let generator): generator().hash(into: &hasher)
case .userDefaults(_, let key): key.hash(into: &hasher)
case .settingBool(let key): key.hash(into: &hasher)
}
}
public static func == (lhs: DataSource, rhs: DataSource) -> Bool {
switch (lhs, rhs) {
case (.boolValue(let lhsValue), .boolValue(let rhsValue)):
return (lhsValue == rhsValue)
case (.boolValue(let lhsKey, let lhsValue, let lhsOldValue), .boolValue(let rhsKey, let rhsValue, let rhsOldValue)):
return (
lhsKey == rhsKey &&
lhsValue == rhsValue &&
lhsOldValue == rhsOldValue
)
case (.dynamicString(let lhsGenerator), .dynamicString(let rhsGenerator)):
return (lhsGenerator() == rhsGenerator())
case (.userDefaults(_, let lhsKey), .userDefaults(_, let rhsKey)):
return (lhsKey == rhsKey)
case (.settingBool(let lhsKey), .settingBool(let rhsKey)):
return (lhsKey == rhsKey)
default: return false
}
}

View File

@ -1,6 +1,6 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import UIKit
import SessionUIKit
// MARK: - Main Types

View File

@ -277,7 +277,8 @@ extension SessionCell {
public func update(
with accessory: Accessory?,
tintColor: ThemeValue,
isEnabled: Bool
isEnabled: Bool,
isManualReload: Bool
) {
guard let accessory: Accessory = accessory else { return }
@ -356,10 +357,15 @@ extension SessionCell {
fixedWidthConstraint.isActive = true
toggleSwitchConstraints.forEach { $0.isActive = true }
let newValue: Bool = dataSource.currentBoolValue
if newValue != toggleSwitch.isOn {
toggleSwitch.setOn(newValue, animated: true)
if !isManualReload {
toggleSwitch.setOn(dataSource.oldBoolValue, animated: false)
// Dispatch so the cell reload doesn't conflict with the setting change animation
if dataSource.oldBoolValue != dataSource.currentBoolValue {
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(10)) { [weak toggleSwitch] in
toggleSwitch?.setOn(dataSource.currentBoolValue, animated: true)
}
}
}
case .dropDown(let dataSource, let accessibility):

View File

@ -313,7 +313,7 @@ public class SessionCell: UITableViewCell {
botSeparator.isHidden = true
}
public func update<ID: Hashable & Differentiable>(with info: Info<ID>) {
public func update<ID: Hashable & Differentiable>(with info: Info<ID>, isManualReload: Bool = false) {
interactionMode = (info.title?.interaction ?? .none)
shouldHighlightTitle = (info.title?.interaction != .copy)
titleExtraView = info.title?.extraViewGenerator?()
@ -332,7 +332,8 @@ public class SessionCell: UITableViewCell {
leftAccessoryView.update(
with: info.leftAccessory,
tintColor: info.styling.tintColor,
isEnabled: info.isEnabled
isEnabled: info.isEnabled,
isManualReload: isManualReload
)
titleStackView.isHidden = (info.title == nil && info.subtitle == nil)
titleLabel.isUserInteractionEnabled = (info.title?.interaction == .copy)
@ -356,7 +357,8 @@ public class SessionCell: UITableViewCell {
rightAccessoryView.update(
with: info.rightAccessory,
tintColor: info.styling.tintColor,
isEnabled: info.isEnabled
isEnabled: info.isEnabled,
isManualReload: isManualReload
)
contentStackViewLeadingConstraint.isActive = (info.styling.alignment == .leading)

View File

@ -5,6 +5,9 @@ import SessionUtilitiesKit
public extension Date {
var formattedForDisplay: String {
// If we don't have a date then
guard self.timeIntervalSince1970 > 0 else { return "" }
let dateNow: Date = Date()
guard Calendar.current.isDate(self, equalTo: dateNow, toGranularity: .year) else {

View File

@ -1,6 +1,7 @@
import Foundation
import GRDB
import SessionSnodeKit
import SessionUtilitiesKit
final class IP2Country {
static var isInitialized = false
@ -12,16 +13,16 @@ final class IP2Country {
/// the **lower** bound of an IP range and the "registered_country_geoname_id" column contains the ID of the country corresponding
/// to that range. We look up an IP by finding the first index in the network column where the value is greater than the IP we're looking
/// up (converted to an integer). The IP we're looking up must then be in the range **before** that range.
private lazy var ipv4Table: [String:[Int]] = {
private lazy var ipv4Table: [String: [Int]] = {
let url = Bundle.main.url(forResource: "GeoLite2-Country-Blocks-IPv4", withExtension: nil)!
let data = try! Data(contentsOf: url)
return try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! [String:[Int]]
return try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! [String: [Int]]
}()
private lazy var countryNamesTable: [String:[String]] = {
private lazy var countryNamesTable: [String: [String]] = {
let url = Bundle.main.url(forResource: "GeoLite2-Country-Locations-English", withExtension: nil)!
let data = try! Data(contentsOf: url)
return try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! [String:[String]]
return try! NSKeyedUnarchiver.unarchiveTopLevelObjectWithData(data) as! [String: [String]]
}()
// MARK: Lifecycle

View File

@ -4,6 +4,7 @@ import Foundation
import GRDB
import Curve25519Kit
import SessionMessagingKit
import SessionUtilitiesKit
enum MockDataGenerator {
// MARK: - Generation
@ -99,7 +100,8 @@ enum MockDataGenerator {
.compactMap { _ in stringContent.randomElement(using: &dmThreadRandomGenerator) }
.joined(),
lastNameUpdate: Date().timeIntervalSince1970,
lastProfilePictureUpdate: Date().timeIntervalSince1970
lastProfilePictureUpdate: Date().timeIntervalSince1970,
lastBlocksCommunityMessageRequests: 0
)
.saved(db)
@ -180,7 +182,8 @@ enum MockDataGenerator {
.compactMap { _ in stringContent.randomElement(using: &cgThreadRandomGenerator) }
.joined(),
lastNameUpdate: Date().timeIntervalSince1970,
lastProfilePictureUpdate: Date().timeIntervalSince1970
lastProfilePictureUpdate: Date().timeIntervalSince1970,
lastBlocksCommunityMessageRequests: 0
)
.saved(db)
@ -310,7 +313,8 @@ enum MockDataGenerator {
.compactMap { _ in stringContent.randomElement(using: &ogThreadRandomGenerator) }
.joined(),
lastNameUpdate: Date().timeIntervalSince1970,
lastProfilePictureUpdate: Date().timeIntervalSince1970
lastProfilePictureUpdate: Date().timeIntervalSince1970,
lastBlocksCommunityMessageRequests: 0
)
.saved(db)

View File

@ -3,6 +3,7 @@
import UIKit
import SessionMessagingKit
import SessionUIKit
import SessionUtilitiesKit
protocol SwipeActionOptimisticCell {
func optimisticUpdate(isMuted: Bool?, isBlocked: Bool?, isPinned: Bool?, hasUnread: Bool?)

View File

@ -31,14 +31,9 @@ public enum SNMessagingKit: MigratableTarget { // Just to make the external API
_011_AddPendingReadReceipts.self,
_012_AddFTSIfNeeded.self,
_013_SessionUtilChanges.self,
// Wait until the feature is turned on before doing the migration that generates
// the config dump data
// FIXME: Remove this once `useSharedUtilForUserConfig` is permanent
(Features.useSharedUtilForUserConfig(db) ?
_014_GenerateInitialUserConfigDumps.self :
(nil as Migration.Type?)
)
].compactMap { $0 }
_014_GenerateInitialUserConfigDumps.self,
_015_BlockCommunityMessageRequests.self
]
]
)
}

View File

@ -649,23 +649,18 @@ public enum SMKLegacy {
@objc(SNConfigurationMessage)
internal final class _ConfigurationMessage: _ControlMessage {
internal var closedGroups: Set<_CMClosedGroup> = []
internal var openGroups: Set<String> = []
internal var displayName: String?
internal var profilePictureURL: String?
internal var profileKey: Data?
internal var contacts: Set<_CMContact> = []
// MARK: NSCoding
public required init?(coder: NSCoder) {
super.init(coder: coder)
if let closedGroups = coder.decodeObject(forKey: "closedGroups") as! Set<_CMClosedGroup>? { self.closedGroups = closedGroups }
if let openGroups = coder.decodeObject(forKey: "openGroups") as! Set<String>? { self.openGroups = openGroups }
if let displayName = coder.decodeObject(forKey: "displayName") as! String? { self.displayName = displayName }
if let profilePictureURL = coder.decodeObject(forKey: "profilePictureURL") as! String? { self.profilePictureURL = profilePictureURL }
if let profileKey = coder.decodeObject(forKey: "profileKey") as! Data? { self.profileKey = profileKey }
if let contacts = coder.decodeObject(forKey: "contacts") as! Set<_CMContact>? { self.contacts = contacts }
}
public override func encode(with coder: NSCoder) {
@ -679,126 +674,12 @@ public enum SMKLegacy {
ConfigurationMessage(
displayName: displayName,
profilePictureUrl: profilePictureURL,
profileKey: profileKey,
closedGroups: closedGroups
.map { $0.toNonLegacy() }
.asSet(),
openGroups: openGroups,
contacts: contacts
.map { $0.toNonLegacy() }
.asSet()
profileKey: profileKey
)
)
}
}
// MARK: - Config Message Closed Group
@objc(CMClosedGroup)
internal final class _CMClosedGroup: NSObject, NSCoding {
internal let publicKey: String
internal let name: String
internal let encryptionKeyPair: SUKLegacy.KeyPair
internal let members: Set<String>
internal let admins: Set<String>
internal let expirationTimer: UInt32
// MARK: NSCoding
public required init?(coder: NSCoder) {
guard
let publicKey = coder.decodeObject(forKey: "publicKey") as! String?,
let name = coder.decodeObject(forKey: "name") as! String?,
let encryptionKeyPair = coder.decodeObject(forKey: "encryptionKeyPair") as! SUKLegacy.KeyPair?,
let members = coder.decodeObject(forKey: "members") as! Set<String>?,
let admins = coder.decodeObject(forKey: "admins") as! Set<String>?
else { return nil }
self.publicKey = publicKey
self.name = name
self.encryptionKeyPair = encryptionKeyPair
self.members = members
self.admins = admins
self.expirationTimer = (coder.decodeObject(forKey: "expirationTimer") as? UInt32 ?? 0)
}
public func encode(with coder: NSCoder) {
fatalError("encode(with:) should never be called for legacy types")
}
// MARK: Non-Legacy Conversion
internal func toNonLegacy() -> ConfigurationMessage.CMClosedGroup {
return ConfigurationMessage.CMClosedGroup(
publicKey: publicKey,
name: name,
encryptionKeyPublicKey: encryptionKeyPair.publicKey,
encryptionKeySecretKey: encryptionKeyPair.privateKey,
members: members,
admins: admins,
expirationTimer: expirationTimer
)
}
}
// MARK: - Config Message Contact
@objc(SNConfigurationMessageContact)
internal final class _CMContact: NSObject, NSCoding {
internal var publicKey: String?
internal var displayName: String?
internal var profilePictureURL: String?
internal var profileKey: Data?
internal var hasIsApproved: Bool
internal var isApproved: Bool
internal var hasIsBlocked: Bool
internal var isBlocked: Bool
internal var hasDidApproveMe: Bool
internal var didApproveMe: Bool
// MARK: NSCoding
public required init?(coder: NSCoder) {
guard
let publicKey = coder.decodeObject(forKey: "publicKey") as! String?,
let displayName = coder.decodeObject(forKey: "displayName") as! String?
else { return nil }
self.publicKey = publicKey
self.displayName = displayName
self.profilePictureURL = coder.decodeObject(forKey: "profilePictureURL") as! String?
self.profileKey = coder.decodeObject(forKey: "profileKey") as! Data?
self.hasIsApproved = (coder.decodeObject(forKey: "hasIsApproved") as? Bool ?? false)
self.isApproved = (coder.decodeObject(forKey: "isApproved") as? Bool ?? false)
self.hasIsBlocked = (coder.decodeObject(forKey: "hasIsBlocked") as? Bool ?? false)
self.isBlocked = (coder.decodeObject(forKey: "isBlocked") as? Bool ?? false)
self.hasDidApproveMe = (coder.decodeObject(forKey: "hasDidApproveMe") as? Bool ?? false)
self.didApproveMe = (coder.decodeObject(forKey: "didApproveMe") as? Bool ?? false)
}
public func encode(with coder: NSCoder) {
fatalError("encode(with:) should never be called for legacy types")
}
// MARK: Non-Legacy Conversion
internal func toNonLegacy() -> ConfigurationMessage.CMContact {
return ConfigurationMessage.CMContact(
publicKey: publicKey,
displayName: displayName,
profilePictureUrl: profilePictureURL,
profileKey: profileKey,
hasIsApproved: hasIsApproved,
isApproved: isApproved,
hasIsBlocked: hasIsBlocked,
isBlocked: isBlocked,
hasDidApproveMe: hasDidApproveMe,
didApproveMe: didApproveMe
)
}
}
// MARK: - Unsend Request
@objc(SNUnsendRequest)

View File

@ -422,7 +422,8 @@ enum _003_YDBToGRDBMigration: Migration {
profilePictureUrl: legacyContact.profilePictureURL,
profilePictureFileName: legacyContact.profilePictureFileName,
profileEncryptionKey: legacyContact.profileEncryptionKey?.keyData,
lastProfilePictureUpdate: 0
lastProfilePictureUpdate: 0,
lastBlocksCommunityMessageRequests: 0
).migrationSafeInsert(db)
/// **Note:** The blow "shouldForce" flags are here to allow us to avoid having to run legacy migrations they
@ -645,7 +646,8 @@ enum _003_YDBToGRDBMigration: Migration {
id: profileId,
name: profileId,
lastNameUpdate: 0,
lastProfilePictureUpdate: 0
lastProfilePictureUpdate: 0,
lastBlocksCommunityMessageRequests: 0
).migrationSafeSave(db)
}
@ -1059,7 +1061,8 @@ enum _003_YDBToGRDBMigration: Migration {
id: quotedMessage.authorId,
name: quotedMessage.authorId,
lastNameUpdate: 0,
lastProfilePictureUpdate: 0
lastProfilePictureUpdate: 0,
lastBlocksCommunityMessageRequests: 0
).migrationSafeSave(db)
}
@ -1851,14 +1854,6 @@ enum _003_YDBToGRDBMigration: Migration {
SMKLegacy._ConfigurationMessage.self,
forClassName: "SNConfigurationMessage"
)
NSKeyedUnarchiver.setClass(
SMKLegacy._CMClosedGroup.self,
forClassName: "SNClosedGroup"
)
NSKeyedUnarchiver.setClass(
SMKLegacy._CMContact.self,
forClassName: "SNConfigurationMessage.SNConfigurationMessageContact"
)
NSKeyedUnarchiver.setClass(
SMKLegacy._UnsendRequest.self,
forClassName: "SNUnsendRequest"

View File

@ -9,7 +9,7 @@ enum _005_FixDeletedMessageReadState: Migration {
static let target: TargetMigrations.Identifier = .messagingKit
static let identifier: String = "FixDeletedMessageReadState"
static let needsConfigSync: Bool = false
static let minExpectedRunDuration: TimeInterval = 0.1
static let minExpectedRunDuration: TimeInterval = 0.01
static func migrate(_ db: Database) throws {
_ = try Interaction

View File

@ -10,7 +10,7 @@ enum _006_FixHiddenModAdminSupport: Migration {
static let target: TargetMigrations.Identifier = .messagingKit
static let identifier: String = "FixHiddenModAdminSupport"
static let needsConfigSync: Bool = false
static let minExpectedRunDuration: TimeInterval = 0.1
static let minExpectedRunDuration: TimeInterval = 0.01
static func migrate(_ db: Database) throws {
try db.alter(table: GroupMember.self) { t in

View File

@ -9,7 +9,7 @@ enum _007_HomeQueryOptimisationIndexes: Migration {
static let target: TargetMigrations.Identifier = .messagingKit
static let identifier: String = "HomeQueryOptimisationIndexes"
static let needsConfigSync: Bool = false
static let minExpectedRunDuration: TimeInterval = 0.1
static let minExpectedRunDuration: TimeInterval = 0.01
static func migrate(_ db: Database) throws {
try db.create(

Some files were not shown because too many files have changed in this diff Show More