Merge branch 'remove-OWSBlockingManager' into voice-calls-2

This commit is contained in:
Ryan Zhao 2022-03-31 11:09:09 +11:00
commit 49d6a64194
63 changed files with 507 additions and 2594 deletions

View File

@ -180,6 +180,8 @@
7BD477A827EC39F5004E2822 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD477A727EC39F5004E2822 /* Atomic.swift */; };
7BD477AA27F15F24004E2822 /* OpenGroupServerIdLookup.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD477A927F15F24004E2822 /* OpenGroupServerIdLookup.swift */; };
7BD477AC27F15F41004E2822 /* OpenGroupServerIdLookupMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD477AB27F15F41004E2822 /* OpenGroupServerIdLookupMigration.swift */; };
7BD477AE27F526E3004E2822 /* BlockingManagerRemovalMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD477AD27F526E3004E2822 /* BlockingManagerRemovalMigration.swift */; };
7BD477B027F526FF004E2822 /* BlockListUIUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD477AF27F526FF004E2822 /* BlockListUIUtils.swift */; };
7BDCFC08242186E700641C39 /* NotificationServiceExtensionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */; };
7BDCFC0B2421EB7600641C39 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B6F509951AA53F760068F56A /* Localizable.strings */; };
7BFD1A8A2745C4F000FB91B9 /* Permissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFD1A892745C4F000FB91B9 /* Permissions.swift */; };
@ -318,8 +320,6 @@
B8DE1FB626C22FCB0079C9CE /* CallMessage.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8DE1FB526C22FCB0079C9CE /* CallMessage.swift */; };
B8EB20EE2640F28000773E52 /* VisibleMessage+OpenGroupInvitation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8EB20ED2640F28000773E52 /* VisibleMessage+OpenGroupInvitation.swift */; };
B8EB20F02640F7F000773E52 /* OpenGroupInvitationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8EB20EF2640F7F000773E52 /* OpenGroupInvitationView.swift */; };
B8F5F52925EC4F8A003BF8D4 /* BlockListUIUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = B8F5F52825EC4F8A003BF8D4 /* BlockListUIUtils.m */; };
B8F5F54E25EC50A5003BF8D4 /* BlockListUIUtils.h in Headers */ = {isa = PBXBuildFile; fileRef = B8F5F52725EC4F6A003BF8D4 /* BlockListUIUtils.h */; settings = {ATTRIBUTES = (Public, ); }; };
B8F5F56525EC8453003BF8D4 /* Notification+Contacts.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F5F56425EC8453003BF8D4 /* Notification+Contacts.swift */; };
B8F5F58325EC94A6003BF8D4 /* Collection+Subscripting.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F5F58225EC94A6003BF8D4 /* Collection+Subscripting.swift */; };
B8F5F60325EDE16F003BF8D4 /* DataExtractionNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8F5F60225EDE16F003BF8D4 /* DataExtractionNotification.swift */; };
@ -402,8 +402,6 @@
C32C5B6B256DC357003C73A2 /* OWSDisappearingConfigurationUpdateInfoMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDADA255A580400E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.h */; settings = {ATTRIBUTES = (Public, ); }; };
C32C5B84256DC54F003C73A2 /* SSKEnvironment.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDAF4255A580600E217F9 /* SSKEnvironment.m */; };
C32C5B8D256DC565003C73A2 /* SSKEnvironment.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB31255A580A00E217F9 /* SSKEnvironment.h */; settings = {ATTRIBUTES = (Public, ); }; };
C32C5B9F256DC739003C73A2 /* OWSBlockingManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */; };
C32C5BB0256DC73D003C73A2 /* OWSBlockingManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */; settings = {ATTRIBUTES = (Public, ); }; };
C32C5BBA256DC7E3003C73A2 /* ProfileManagerProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDBB9255A581600E217F9 /* ProfileManagerProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; };
C32C5BCC256DC830003C73A2 /* Storage+ClosedGroups.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D8F1372566120F0092EF10 /* Storage+ClosedGroups.swift */; };
C32C5BDD256DC88D003C73A2 /* OWSReadReceiptManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA71255A57FA00E217F9 /* OWSReadReceiptManager.m */; };
@ -570,7 +568,6 @@
C374EEEB25DA3CA70073A857 /* ConversationTitleView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C374EEEA25DA3CA70073A857 /* ConversationTitleView.swift */; };
C374EEF425DB31D40073A857 /* VoiceMessageRecordingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C374EEF325DB31D40073A857 /* VoiceMessageRecordingView.swift */; };
C379DCF4256735770002D4EB /* VisibleMessage+Attachment.swift in Sources */ = {isa = PBXBuildFile; fileRef = C379DCF3256735770002D4EB /* VisibleMessage+Attachment.swift */; };
C37F5385255B94F6002AEA92 /* SelectRecipientViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF34E255B6DC8007E1867 /* SelectRecipientViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
C37F5396255B95BD002AEA92 /* OWSAnyTouchGestureRecognizer.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF302255B6DBE007E1867 /* OWSAnyTouchGestureRecognizer.h */; settings = {ATTRIBUTES = (Public, ); }; };
C37F5414255BAFA7002AEA92 /* SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; };
C37F54DC255BB84A002AEA92 /* SessionSnodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */; };
@ -624,20 +621,14 @@
C38EF32F255B6DBF007E1867 /* OWSFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF305255B6DBE007E1867 /* OWSFormat.m */; };
C38EF331255B6DBF007E1867 /* UIGestureRecognizer+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */; };
C38EF334255B6DBF007E1867 /* UIUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF30A255B6DBE007E1867 /* UIUtil.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF335255B6DBF007E1867 /* BlockListCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF30B255B6DBE007E1867 /* BlockListCache.swift */; };
C38EF359255B6DCC007E1867 /* SheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF33F255B6DC5007E1867 /* SheetViewController.swift */; };
C38EF35B255B6DCC007E1867 /* SelectThreadViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF341255B6DC5007E1867 /* SelectThreadViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF35C255B6DCC007E1867 /* SelectThreadViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF342255B6DC5007E1867 /* SelectThreadViewController.m */; };
C38EF35D255B6DCC007E1867 /* OWSNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF343255B6DC5007E1867 /* OWSNavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF35E255B6DCC007E1867 /* OWSViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF344255B6DC5007E1867 /* OWSViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF35F255B6DCC007E1867 /* SelectRecipientViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF345255B6DC6007E1867 /* SelectRecipientViewController.m */; };
C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF349255B6DC7007E1867 /* ModalActivityIndicatorViewController.swift */; };
C38EF365255B6DCC007E1867 /* OWSTableViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF34B255B6DC8007E1867 /* OWSTableViewController.m */; };
C38EF366255B6DCC007E1867 /* ScreenLockViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF34C255B6DC8007E1867 /* ScreenLockViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF367255B6DCC007E1867 /* OWSTableViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF34D255B6DC8007E1867 /* OWSTableViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF36B255B6DCC007E1867 /* ScreenLockViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF351255B6DC9007E1867 /* ScreenLockViewController.m */; };
C38EF36C255B6DCC007E1867 /* SharingThreadPickerViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF352255B6DC9007E1867 /* SharingThreadPickerViewController.m */; };
C38EF36D255B6DCC007E1867 /* SharingThreadPickerViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF353255B6DCB007E1867 /* SharingThreadPickerViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF36F255B6DCC007E1867 /* OWSViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF355255B6DCB007E1867 /* OWSViewController.m */; };
C38EF370255B6DCC007E1867 /* OWSNavigationController.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF356255B6DCB007E1867 /* OWSNavigationController.m */; };
C38EF371255B6DCC007E1867 /* MessageApprovalViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF357255B6DCC007E1867 /* MessageApprovalViewController.swift */; };
@ -1204,6 +1195,8 @@
7BD477A727EC39F5004E2822 /* Atomic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = "<group>"; };
7BD477A927F15F24004E2822 /* OpenGroupServerIdLookup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenGroupServerIdLookup.swift; sourceTree = "<group>"; };
7BD477AB27F15F41004E2822 /* OpenGroupServerIdLookupMigration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenGroupServerIdLookupMigration.swift; sourceTree = "<group>"; };
7BD477AD27F526E3004E2822 /* BlockingManagerRemovalMigration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockingManagerRemovalMigration.swift; sourceTree = "<group>"; };
7BD477AF27F526FF004E2822 /* BlockListUIUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockListUIUtils.swift; sourceTree = "<group>"; };
7BDCFC0424206E7300641C39 /* SessionNotificationServiceExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SessionNotificationServiceExtension.entitlements; sourceTree = "<group>"; };
7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtensionContext.swift; sourceTree = "<group>"; };
7BFD1A892745C4F000FB91B9 /* Permissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Permissions.swift; sourceTree = "<group>"; };
@ -1359,8 +1352,6 @@
B8EB20E6263F7E4B00773E52 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
B8EB20ED2640F28000773E52 /* VisibleMessage+OpenGroupInvitation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+OpenGroupInvitation.swift"; sourceTree = "<group>"; };
B8EB20EF2640F7F000773E52 /* OpenGroupInvitationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupInvitationView.swift; sourceTree = "<group>"; };
B8F5F52725EC4F6A003BF8D4 /* BlockListUIUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BlockListUIUtils.h; sourceTree = "<group>"; };
B8F5F52825EC4F8A003BF8D4 /* BlockListUIUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BlockListUIUtils.m; sourceTree = "<group>"; };
B8F5F56425EC8453003BF8D4 /* Notification+Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+Contacts.swift"; sourceTree = "<group>"; };
B8F5F58225EC94A6003BF8D4 /* Collection+Subscripting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+Subscripting.swift"; sourceTree = "<group>"; };
B8F5F60225EDE16F003BF8D4 /* DataExtractionNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataExtractionNotification.swift; sourceTree = "<group>"; };
@ -1410,7 +1401,6 @@
C33FD9AD255A548A00E217F9 /* SignalUtilitiesKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SignalUtilitiesKit.h; sourceTree = "<group>"; };
C33FD9AE255A548A00E217F9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSPrimaryStorage.h; sourceTree = "<group>"; };
C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBlockingManager.m; sourceTree = "<group>"; };
C33FDA69255A57F900E217F9 /* SSKPreferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKPreferences.swift; sourceTree = "<group>"; };
C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingConfigurationUpdateInfoMessage.m; sourceTree = "<group>"; };
C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProtoUtils.m; sourceTree = "<group>"; };
@ -1565,7 +1555,6 @@
C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushNotificationAPI.swift; sourceTree = "<group>"; };
C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LKGroupUtilities.m; sourceTree = "<group>"; };
C33FDBE9255A581A00E217F9 /* TSInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInteraction.m; sourceTree = "<group>"; };
C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBlockingManager.h; sourceTree = "<group>"; };
C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSRecipientIdentity.m; sourceTree = "<group>"; };
C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSStorageKeys.h; sourceTree = "<group>"; };
C33FDBF1255A581B00E217F9 /* OWSIdentityManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSIdentityManager.h; sourceTree = "<group>"; };
@ -1687,21 +1676,14 @@
C38EF308255B6DBE007E1867 /* OWSPreferences.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSPreferences.m; path = SessionMessagingKit/Utilities/OWSPreferences.m; sourceTree = SOURCE_ROOT; };
C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DeviceSleepManager.swift; path = SessionMessagingKit/Utilities/DeviceSleepManager.swift; sourceTree = SOURCE_ROOT; };
C38EF30A255B6DBE007E1867 /* UIUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UIUtil.h; path = SignalUtilitiesKit/Utilities/UIUtil.h; sourceTree = SOURCE_ROOT; };
C38EF30B255B6DBE007E1867 /* BlockListCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BlockListCache.swift; path = SignalUtilitiesKit/Messaging/BlockListCache.swift; sourceTree = SOURCE_ROOT; };
C38EF33F255B6DC5007E1867 /* SheetViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SheetViewController.swift; path = "SignalUtilitiesKit/Shared View Controllers/SheetViewController.swift"; sourceTree = SOURCE_ROOT; };
C38EF341255B6DC5007E1867 /* SelectThreadViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SelectThreadViewController.h; path = SignalUtilitiesKit/Sharing/SelectThreadViewController.h; sourceTree = SOURCE_ROOT; };
C38EF342255B6DC5007E1867 /* SelectThreadViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SelectThreadViewController.m; path = SignalUtilitiesKit/Sharing/SelectThreadViewController.m; sourceTree = SOURCE_ROOT; };
C38EF343255B6DC5007E1867 /* OWSNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSNavigationController.h; path = "SignalUtilitiesKit/Shared View Controllers/OWSNavigationController.h"; sourceTree = SOURCE_ROOT; };
C38EF344255B6DC5007E1867 /* OWSViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSViewController.h; path = "SignalUtilitiesKit/Shared View Controllers/OWSViewController.h"; sourceTree = SOURCE_ROOT; };
C38EF345255B6DC6007E1867 /* SelectRecipientViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SelectRecipientViewController.m; path = SignalUtilitiesKit/Sharing/SelectRecipientViewController.m; sourceTree = SOURCE_ROOT; };
C38EF349255B6DC7007E1867 /* ModalActivityIndicatorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModalActivityIndicatorViewController.swift; path = "SignalUtilitiesKit/Shared View Controllers/ModalActivityIndicatorViewController.swift"; sourceTree = SOURCE_ROOT; };
C38EF34B255B6DC8007E1867 /* OWSTableViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSTableViewController.m; path = "SignalUtilitiesKit/Shared View Controllers/OWSTableViewController.m"; sourceTree = SOURCE_ROOT; };
C38EF34C255B6DC8007E1867 /* ScreenLockViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ScreenLockViewController.h; path = "SignalUtilitiesKit/Screen Lock/ScreenLockViewController.h"; sourceTree = SOURCE_ROOT; };
C38EF34D255B6DC8007E1867 /* OWSTableViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSTableViewController.h; path = "SignalUtilitiesKit/Shared View Controllers/OWSTableViewController.h"; sourceTree = SOURCE_ROOT; };
C38EF34E255B6DC8007E1867 /* SelectRecipientViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SelectRecipientViewController.h; path = SignalUtilitiesKit/Sharing/SelectRecipientViewController.h; sourceTree = SOURCE_ROOT; };
C38EF351255B6DC9007E1867 /* ScreenLockViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = ScreenLockViewController.m; path = "SignalUtilitiesKit/Screen Lock/ScreenLockViewController.m"; sourceTree = SOURCE_ROOT; };
C38EF352255B6DC9007E1867 /* SharingThreadPickerViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = SharingThreadPickerViewController.m; path = SignalUtilitiesKit/Sharing/SharingThreadPickerViewController.m; sourceTree = SOURCE_ROOT; };
C38EF353255B6DCB007E1867 /* SharingThreadPickerViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SharingThreadPickerViewController.h; path = SignalUtilitiesKit/Sharing/SharingThreadPickerViewController.h; sourceTree = SOURCE_ROOT; };
C38EF355255B6DCB007E1867 /* OWSViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSViewController.m; path = "SignalUtilitiesKit/Shared View Controllers/OWSViewController.m"; sourceTree = SOURCE_ROOT; };
C38EF356255B6DCB007E1867 /* OWSNavigationController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSNavigationController.m; path = "SignalUtilitiesKit/Shared View Controllers/OWSNavigationController.m"; sourceTree = SOURCE_ROOT; };
C38EF357255B6DCC007E1867 /* MessageApprovalViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MessageApprovalViewController.swift; path = "SignalUtilitiesKit/Media Viewing & Editing/MessageApprovalViewController.swift"; sourceTree = SOURCE_ROOT; };
@ -2617,7 +2599,6 @@
isa = PBXGroup;
children = (
C3D9E3B52567685D0040E4F3 /* Attachments */,
C32C5B9E256DC720003C73A2 /* Blocking */,
B8F5F61925EDE4B0003BF8D4 /* Data Extraction */,
C32C5B01256DC054003C73A2 /* Expiration */,
C32C5D22256DD496003C73A2 /* Link Previews */,
@ -2784,15 +2765,6 @@
path = Quotes;
sourceTree = "<group>";
};
C32C5B9E256DC720003C73A2 /* Blocking */ = {
isa = PBXGroup;
children = (
C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */,
C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */,
);
path = Blocking;
sourceTree = "<group>";
};
C32C5BB9256DC7C4003C73A2 /* To Do */ = {
isa = PBXGroup;
children = (
@ -2924,7 +2896,6 @@
C36096EE25AD21BC008B62B2 /* Screen Lock */,
C3851CD225624B060061EEB0 /* Shared Views */,
C360970125AD22D3008B62B2 /* Shared View Controllers */,
C36096F025AD227E008B62B2 /* Sharing */,
C3851CE3256250FA0061EEB0 /* To Do */,
C3CA3B11255CF17200F4C6D4 /* Utilities */,
);
@ -3152,19 +3123,6 @@
path = "Profile Pictures";
sourceTree = "<group>";
};
C36096F025AD227E008B62B2 /* Sharing */ = {
isa = PBXGroup;
children = (
C38EF34E255B6DC8007E1867 /* SelectRecipientViewController.h */,
C38EF345255B6DC6007E1867 /* SelectRecipientViewController.m */,
C38EF341255B6DC5007E1867 /* SelectThreadViewController.h */,
C38EF342255B6DC5007E1867 /* SelectThreadViewController.m */,
C38EF353255B6DCB007E1867 /* SharingThreadPickerViewController.h */,
C38EF352255B6DC9007E1867 /* SharingThreadPickerViewController.m */,
);
path = Sharing;
sourceTree = "<group>";
};
C360970125AD22D3008B62B2 /* Shared View Controllers */ = {
isa = PBXGroup;
children = (
@ -3192,6 +3150,7 @@
C379DCE82567330E0002D4EB /* Migrations */ = {
isa = PBXGroup;
children = (
7BD477AD27F526E3004E2822 /* BlockingManagerRemovalMigration.swift */,
7BD477AB27F15F41004E2822 /* OpenGroupServerIdLookupMigration.swift */,
7B93D07227CF19C800811CB6 /* MessageRequestsMigration.swift */,
B8B32044258C117C0020074B /* ContactsMigration.swift */,
@ -3284,8 +3243,7 @@
C38BBA0D255E321C0041B9A3 /* Messaging */ = {
isa = PBXGroup;
children = (
B8F5F52725EC4F6A003BF8D4 /* BlockListUIUtils.h */,
B8F5F52825EC4F8A003BF8D4 /* BlockListUIUtils.m */,
7BD477AF27F526FF004E2822 /* BlockListUIUtils.swift */,
C38EF2FC255B6DBD007E1867 /* ConversationStyle.swift */,
C38EF3D4255B6DEE007E1867 /* DisappearingTimerConfigurationView.swift */,
C33FDA72255A57FA00E217F9 /* OWSFailedAttachmentDownloadsJob.h */,
@ -3293,7 +3251,6 @@
C33FDADB255A580400E217F9 /* OWSFailedMessagesJob.h */,
C33FDAB7255A580100E217F9 /* OWSFailedMessagesJob.m */,
C38EF397255B6DD9007E1867 /* ThreadViewModel.swift */,
C38EF30B255B6DBE007E1867 /* BlockListCache.swift */,
C38EF2E4255B6DB9007E1867 /* FullTextSearcher.swift */,
C38EF2E9255B6DBA007E1867 /* OWSUnreadIndicator.h */,
C38EF2E3255B6DB9007E1867 /* OWSUnreadIndicator.m */,
@ -3796,7 +3753,6 @@
C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */,
C33FDDBD255A582000E217F9 /* ByteParser.h in Headers */,
C38EF243255B6D67007E1867 /* UIViewController+OWS.h in Headers */,
C38EF36D255B6DCC007E1867 /* SharingThreadPickerViewController.h in Headers */,
C38EF35D255B6DCC007E1867 /* OWSNavigationController.h in Headers */,
C38EF249255B6D67007E1867 /* UIColor+OWS.h in Headers */,
C38EF216255B6D3B007E1867 /* Theme.h in Headers */,
@ -3809,7 +3765,6 @@
C38EF3F5255B6DF7007E1867 /* OWSTextField.h in Headers */,
C38EF275255B6D7A007E1867 /* OWSDatabaseMigrationRunner.h in Headers */,
C38EF366255B6DCC007E1867 /* ScreenLockViewController.h in Headers */,
C38EF35B255B6DCC007E1867 /* SelectThreadViewController.h in Headers */,
C33FDDD3255A582000E217F9 /* OWSQueues.h in Headers */,
C33FDC96255A582000E217F9 /* NSObject+Casting.h in Headers */,
C33FDDB3255A582000E217F9 /* OWSError.h in Headers */,
@ -3821,7 +3776,6 @@
C33FDDB2255A582000E217F9 /* NSArray+OWS.h in Headers */,
C38EF2D7255B6DAF007E1867 /* OWSProfileManager.h in Headers */,
C38EF290255B6D86007E1867 /* AppSetup.h in Headers */,
C37F5385255B94F6002AEA92 /* SelectRecipientViewController.h in Headers */,
C38EF367255B6DCC007E1867 /* OWSTableViewController.h in Headers */,
C38EF246255B6D67007E1867 /* UIFont+OWS.h in Headers */,
C33FD9AF255A548A00E217F9 /* SignalUtilitiesKit.h in Headers */,
@ -3829,7 +3783,6 @@
C33FDD06255A582000E217F9 /* AppVersion.h in Headers */,
C33FDD5A255A582000E217F9 /* TSStorageHeaders.h in Headers */,
C33FDCA2255A582000E217F9 /* OWSMessageUtils.h in Headers */,
B8F5F54E25EC50A5003BF8D4 /* BlockListUIUtils.h in Headers */,
C38EF28F255B6D86007E1867 /* VersionMigrations.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
@ -3914,7 +3867,6 @@
C32C5EA0256DE0D6003C73A2 /* OWSPrimaryStorage.h in Headers */,
C3A3A111256E1A93004D228D /* OWSIncomingMessageFinder.h in Headers */,
C32C5AAC256DBE8F003C73A2 /* TSInfoMessage.h in Headers */,
C32C5BB0256DC73D003C73A2 /* OWSBlockingManager.h in Headers */,
C3A3A15F256E1BB4004D228D /* ProtoUtils.h in Headers */,
C3A3A145256E1B49004D228D /* OWSMediaGalleryFinder.h in Headers */,
B8856E33256F18D5001CE70E /* OWSStorage+Subclass.h in Headers */,
@ -4609,10 +4561,10 @@
C38EF317255B6DBF007E1867 /* DisplayableText.swift in Sources */,
C38EF30F255B6DBF007E1867 /* AppPreferences.swift in Sources */,
C38EF3C3255B6DE7007E1867 /* ImageEditorTextItem.swift in Sources */,
7BD477AE27F526E3004E2822 /* BlockingManagerRemovalMigration.swift in Sources */,
C33FDC7D255A582000E217F9 /* OWSDispatch.m in Sources */,
C38EF247255B6D67007E1867 /* NSAttributedString+OWS.m in Sources */,
C33FDD49255A582000E217F9 /* ParamParser.swift in Sources */,
C38EF35F255B6DCC007E1867 /* SelectRecipientViewController.m in Sources */,
C38EF3C5255B6DE7007E1867 /* OWSViewController+ImageEditor.swift in Sources */,
C38EF39B255B6DDA007E1867 /* ThreadViewModel.swift in Sources */,
C38EF2A5255B6D93007E1867 /* Identicon+ObjC.swift in Sources */,
@ -4620,7 +4572,6 @@
C33FDD12255A582000E217F9 /* OWSPrimaryStorage+Loki.m in Sources */,
C3D9E40C25676C100040E4F3 /* Storage+Conformances.swift in Sources */,
C38EF31A255B6DBF007E1867 /* OWSAnyTouchGestureRecognizer.m in Sources */,
C38EF36C255B6DCC007E1867 /* SharingThreadPickerViewController.m in Sources */,
C38EF385255B6DD2007E1867 /* AttachmentTextToolbar.swift in Sources */,
C33FDD23255A582000E217F9 /* FeatureFlags.swift in Sources */,
C38EF389255B6DD2007E1867 /* AttachmentTextView.swift in Sources */,
@ -4654,7 +4605,6 @@
C38EF38C255B6DD2007E1867 /* ApprovalRailCellView.swift in Sources */,
C38EF409255B6DF7007E1867 /* ContactTableViewCell.m in Sources */,
C38EF32A255B6DBF007E1867 /* UIUtil.m in Sources */,
C38EF335255B6DBF007E1867 /* BlockListCache.swift in Sources */,
C38EF2A6255B6D93007E1867 /* PlaceholderIcon.swift in Sources */,
C38EF371255B6DCC007E1867 /* MessageApprovalViewController.swift in Sources */,
C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */,
@ -4690,7 +4640,6 @@
C38EF365255B6DCC007E1867 /* OWSTableViewController.m in Sources */,
C38EF36B255B6DCC007E1867 /* ScreenLockViewController.m in Sources */,
C38EF40C255B6DF7007E1867 /* GradientView.swift in Sources */,
C38EF35C255B6DCC007E1867 /* SelectThreadViewController.m in Sources */,
C38EF30E255B6DBF007E1867 /* FullTextSearcher.swift in Sources */,
C38EF3FA255B6DF7007E1867 /* DirectionalPanGestureRecognizer.swift in Sources */,
C38EF3BB255B6DE7007E1867 /* ImageEditorStrokeItem.swift in Sources */,
@ -4707,6 +4656,7 @@
C38EF3F4255B6DF7007E1867 /* ContactCellView.m in Sources */,
C33FDC78255A582000E217F9 /* TSConstants.m in Sources */,
C38EF324255B6DBF007E1867 /* Bench.swift in Sources */,
7BD477B027F526FF004E2822 /* BlockListUIUtils.swift in Sources */,
C38EF292255B6D86007E1867 /* VersionMigrations.m in Sources */,
C38EF3F2255B6DF7007E1867 /* DisappearingTimerConfigurationView.swift in Sources */,
C38EF3F9255B6DF7007E1867 /* OWSLayerView.swift in Sources */,
@ -4725,7 +4675,6 @@
C38EF40B255B6DF7007E1867 /* TappableStackView.swift in Sources */,
C38EF31D255B6DBF007E1867 /* UIImage+OWS.swift in Sources */,
C38EF359255B6DCC007E1867 /* SheetViewController.swift in Sources */,
B8F5F52925EC4F8A003BF8D4 /* BlockListUIUtils.m in Sources */,
C38EF386255B6DD2007E1867 /* AttachmentApprovalInputAccessoryView.swift in Sources */,
B8C2B2C82563685C00551B4D /* CircleView.swift in Sources */,
C38EF331255B6DBF007E1867 /* UIGestureRecognizer+OWS.swift in Sources */,
@ -4868,7 +4817,6 @@
C32C59C1256DB41F003C73A2 /* TSGroupThread.m in Sources */,
C3A3A08F256E1728004D228D /* FullTextSearchFinder.swift in Sources */,
B8856D1A256F114D001CE70E /* ProximityMonitoringManager.swift in Sources */,
C32C5B9F256DC739003C73A2 /* OWSBlockingManager.m in Sources */,
C3D9E52725677DF20040E4F3 /* OWSThumbnailService.swift in Sources */,
C32C5E75256DE020003C73A2 /* YapDatabaseTransaction+OWS.m in Sources */,
C3BBE0802554CDD70050F1E3 /* Storage.swift in Sources */,

View File

@ -58,7 +58,6 @@ NSString *NSStringForBackupImportState(OWSBackupState state)
NSArray<NSString *> *MiscCollectionsToBackup(void)
{
return @[
kOWSBlockingManager_BlockListCollection,
OWSUserProfile.collection,
SSKIncrementingIdFinder.collectionName,
OWSPreferencesSignalDatabaseCollection,

View File

@ -622,7 +622,7 @@ NSString *const kOWSBackup_ImportDatabaseKeySpec = @"kOWSBackup_ImportDatabaseKe
// complete, they'll be run the next time the app launches.
AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
dispatch_async(dispatch_get_main_queue(), ^{
[[[OWSDatabaseMigrationRunner alloc] init] runAllOutstandingWithCompletion:^{
[[[OWSDatabaseMigrationRunner alloc] init] runAllOutstandingWithCompletion:^(BOOL successful, BOOL needsConfigSync){
resolve(@(1));
}];
});

View File

@ -174,8 +174,7 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat
promise = MessageSender.createClosedGroup(name: name, members: selectedContacts, transaction: transaction)
}
let _ = promise.done(on: DispatchQueue.main) { thread in
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.forceSyncConfigurationNowIfNeeded().retainUntilComplete() // FIXME: It's probably cleaner to do this inside createClosedGroup(...)
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete()
self?.presentingViewController?.dismiss(animated: true, completion: nil)
SignalApp.shared().presentConversation(for: thread, action: .compose, animated: false)
}

View File

@ -68,21 +68,25 @@ extension ConversationVC : InputViewDelegate, MessageCellDelegate, ContextMenuAc
self.blockedBanner.alpha = 0
}, completion: { _ in
if let contact: Contact = Storage.shared.getContact(with: publicKey) {
Storage.shared.write { transaction in
contact.isBlocked = false
Storage.shared.setContact(contact, using: transaction)
}
Storage.shared.write(
with: { transaction in
guard let transaction = transaction as? YapDatabaseReadWriteTransaction else { return }
contact.isBlocked = false
Storage.shared.setContact(contact, using: transaction)
},
completion: {
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete()
}
)
}
OWSBlockingManager.shared().removeBlockedPhoneNumber(publicKey)
})
}
func showBlockedModalIfNeeded() -> Bool {
guard let thread = thread as? TSContactThread else { return false }
let publicKey = thread.contactSessionID()
guard OWSBlockingManager.shared().isRecipientIdBlocked(publicKey) else { return false }
let blockedModal = BlockedModal(publicKey: publicKey)
guard let thread = thread as? TSContactThread, thread.isBlocked() else { return false }
let blockedModal = BlockedModal(publicKey: thread.contactSessionID())
blockedModal.modalPresentationStyle = .overFullScreen
blockedModal.modalTransitionStyle = .crossDissolve
present(blockedModal, animated: true, completion: nil)
@ -1178,6 +1182,9 @@ extension ConversationVC {
Storage.shared.setContact(contact, using: transaction)
}
// Send a sync message with the details of the contact
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete()
// Hide the 'messageRequestView' since the request has been approved and force a config
// sync to propagate the contact approval state (both must run on the main thread)
DispatchQueue.main.async { [weak self] in
@ -1211,11 +1218,6 @@ extension ConversationVC {
newViewControllers.remove(at: messageRequestsIndex)
self?.navigationController?.setViewControllers(newViewControllers, animated: false)
}
// Send a sync message with the details of the contact
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.forceSyncConfigurationNowIfNeeded().retainUntilComplete()
}
}
}
}
@ -1252,6 +1254,12 @@ extension ConversationVC {
let sessionId: String = contactThread.contactSessionID()
if let contact: Contact = Storage.shared.getContact(with: sessionId) {
// Stop observing the `BlockListDidChange` notification (we are about to pop the screen
// so showing the banner just looks buggy)
if let strongSelf = self {
NotificationCenter.default.removeObserver(strongSelf, name: .contactBlockedStateChanged, object: nil)
}
contact.isApproved = false
contact.isBlocked = true
@ -1269,24 +1277,10 @@ extension ConversationVC {
self?.thread.remove(with: transaction)
},
completion: { [weak self] in
// Block the contact
if let sessionId: String = (self?.thread as? TSContactThread)?.contactSessionID(), !OWSBlockingManager.shared().isRecipientIdBlocked(sessionId) {
// Stop observing the `BlockListDidChange` notification (we are about to pop the screen
// so showing the banner just looks buggy)
if let strongSelf = self {
NotificationCenter.default.removeObserver(strongSelf, name: NSNotification.Name(rawValue: kNSNotificationName_BlockListDidChange), object: nil)
}
OWSBlockingManager.shared().addBlockedPhoneNumber(sessionId)
}
// Force a config sync and pop to the previous screen
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete()
// Force a config sync and pop to the previous screen (both must run on the main thread)
DispatchQueue.main.async {
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.forceSyncConfigurationNowIfNeeded().retainUntilComplete()
}
self?.navigationController?.popViewController(animated: true)
}
}

View File

@ -354,7 +354,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
notificationCenter.addObserver(self, selector: #selector(handleKeyboardWillChangeFrameNotification(_:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(handleKeyboardWillHideNotification(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(handleAudioDidFinishPlayingNotification(_:)), name: .SNAudioDidFinishPlaying, object: nil)
notificationCenter.addObserver(self, selector: #selector(addOrRemoveBlockedBanner), name: NSNotification.Name(rawValue: kNSNotificationName_BlockListDidChange), object: nil)
notificationCenter.addObserver(self, selector: #selector(addOrRemoveBlockedBanner), name: .contactBlockedStateChanged, object: nil)
notificationCenter.addObserver(self, selector: #selector(handleGroupUpdatedNotification), name: .groupThreadUpdated, object: nil)
notificationCenter.addObserver(self, selector: #selector(sendScreenshotNotificationIfNeeded), name: UIApplication.userDidTakeScreenshotNotification, object: nil)
notificationCenter.addObserver(self, selector: #selector(handleMessageSentStatusChanged), name: .messageSentStatusDidChange, object: nil)
@ -722,10 +722,11 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
blockedBanner.removeFromSuperview()
}
guard let thread = thread as? TSContactThread else { return detach() }
if OWSBlockingManager.shared().isRecipientIdBlocked(thread.contactSessionID()) {
if thread.isBlocked() {
view.addSubview(blockedBanner)
blockedBanner.pin([ UIView.HorizontalEdge.left, UIView.VerticalEdge.top, UIView.HorizontalEdge.right ], to: view)
} else {
}
else {
detach()
}
}

View File

@ -10,7 +10,6 @@
#import <SignalCoreKit/NSDate+OWS.h>
#import <SignalUtilitiesKit/OWSUnreadIndicator.h>
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
#import <SessionMessagingKit/OWSBlockingManager.h>
#import <SessionMessagingKit/OWSPrimaryStorage.h>
#import <SessionMessagingKit/SSKEnvironment.h>
#import <SessionMessagingKit/TSDatabaseView.h>
@ -247,11 +246,6 @@ NS_ASSUME_NONNULL_BEGIN
return self.primaryStorage.dbReadWriteConnection;
}
- (OWSBlockingManager *)blockingManager
{
return OWSBlockingManager.sharedManager;
}
- (id<OWSTypingIndicators>)typingIndicators
{
return SSKEnvironment.shared.typingIndicators;
@ -287,7 +281,7 @@ NS_ASSUME_NONNULL_BEGIN
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(blockListDidChange:)
name:kNSNotificationName_BlockListDidChange
name:NSNotification.contactBlockedStateChanged
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(localProfileDidChange:)
@ -492,7 +486,6 @@ NS_ASSUME_NONNULL_BEGIN
ThreadDynamicInteractions *dynamicInteractions =
[ThreadUtil ensureDynamicInteractionsForThread:self.thread
blockingManager:self.blockingManager
dbConnection:self.editingDatabaseConnection
hideUnreadMessagesIndicator:self.hasClearedUnreadMessagesIndicator
lastUnreadIndicator:self.dynamicInteractions.unreadIndicator

View File

@ -3,7 +3,6 @@
//
#import "OWSConversationSettingsViewController.h"
#import "OWSBlockingManager.h"
#import "OWSSoundSettingsViewController.h"
#import "Session-Swift.h"
#import "UIFont+OWS.h"
@ -37,7 +36,6 @@ CGFloat kIconViewLength = 24;
@property (nonatomic) NSArray<NSNumber *> *disappearingMessagesDurations;
@property (nonatomic) OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration;
@property (nullable, nonatomic) MediaGallery *mediaGallery;
@property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper;
@property (nonatomic, readonly) UIImageView *avatarView;
@property (nonatomic, readonly) UILabel *disappearingMessagesDurationLabel;
@property (nonatomic) UILabel *displayNameLabel;
@ -107,11 +105,6 @@ CGFloat kIconViewLength = 24;
return SSKEnvironment.shared.tsAccountManager;
}
- (OWSBlockingManager *)blockingManager
{
return [OWSBlockingManager sharedManager];
}
- (OWSProfileManager *)profileManager
{
return [OWSProfileManager sharedManager];
@ -601,7 +594,7 @@ CGFloat kIconViewLength = 24;
cell.selectionStyle = UITableViewCellSelectionStyleNone;
UISwitch *blockConversationSwitch = [UISwitch new];
blockConversationSwitch.on = [strongSelf.blockingManager isThreadBlocked:strongSelf.thread];
blockConversationSwitch.on = strongSelf.thread.isBlocked;
[blockConversationSwitch addTarget:strongSelf action:@selector(blockConversationSwitchDidChange:)
forControlEvents:UIControlEventValueChanged];
cell.accessoryView = blockConversationSwitch;
@ -868,9 +861,13 @@ CGFloat kIconViewLength = 24;
if (![sender isKindOfClass:[UISwitch class]]) {
OWSFailDebug(@"Unexpected sender for block user switch: %@", sender);
}
if (![self.thread isKindOfClass:[TSContactThread class]]) {
OWSFailDebug(@"unexpected thread type: %@", self.thread.class);
}
UISwitch *blockConversationSwitch = (UISwitch *)sender;
TSContactThread *contactThread = (TSContactThread *)self.thread;
BOOL isCurrentlyBlocked = [self.blockingManager isThreadBlocked:self.thread];
BOOL isCurrentlyBlocked = contactThread.isBlocked;
__weak OWSConversationSettingsViewController *weakSelf = self;
if (blockConversationSwitch.isOn) {
@ -878,12 +875,16 @@ CGFloat kIconViewLength = 24;
if (isCurrentlyBlocked) {
return;
}
[BlockListUIUtils showBlockThreadActionSheet:self.thread
fromViewController:self
blockingManager:self.blockingManager
[BlockListUIUtils showBlockThreadActionSheet:contactThread
from:self
completionBlock:^(BOOL isBlocked) {
// Update switch state if user cancels action.
blockConversationSwitch.on = isBlocked;
// If we successfully blocked then force a config sync
if (isBlocked) {
[SNMessageSender forceSyncConfigurationNow];
}
[weakSelf updateTableContents];
}];
@ -893,12 +894,16 @@ CGFloat kIconViewLength = 24;
if (!isCurrentlyBlocked) {
return;
}
[BlockListUIUtils showUnblockThreadActionSheet:self.thread
fromViewController:self
blockingManager:self.blockingManager
[BlockListUIUtils showUnblockThreadActionSheet:contactThread
from:self
completionBlock:^(BOOL isBlocked) {
// Update switch state if user cancels action.
blockConversationSwitch.on = isBlocked;
// If we successfully unblocked then force a config sync
if (!isBlocked) {
[SNMessageSender forceSyncConfigurationNow];
}
[weakSelf updateTableContents];
}];

View File

@ -1,5 +1,6 @@
import SessionMessagingKit
final class BlockedModal : Modal {
final class BlockedModal: Modal {
private let publicKey: String
// MARK: Lifecycle
@ -68,7 +69,22 @@ final class BlockedModal : Modal {
// MARK: Interaction
@objc private func unblock() {
OWSBlockingManager.shared().removeBlockedPhoneNumber(publicKey)
let publicKey: String = self.publicKey
Storage.shared.write(
with: { transaction in
guard let transaction = transaction as? YapDatabaseReadWriteTransaction, let contact: Contact = Storage.shared.getContact(with: publicKey, using: transaction) else {
return
}
contact.isBlocked = false
Storage.shared.setContact(contact, using: transaction as Any)
},
completion: {
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete()
}
)
presentingViewController?.dismiss(animated: true, completion: nil)
}
}

View File

@ -77,8 +77,7 @@ final class JoinOpenGroupModal : Modal {
Storage.shared.write { [presentingViewController = self.presentingViewController!] transaction in
OpenGroupManagerV2.shared.add(room: room, server: server, publicKey: publicKey, using: transaction)
.done(on: DispatchQueue.main) { _ in
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.forceSyncConfigurationNowIfNeeded().retainUntilComplete() // FIXME: It's probably cleaner to do this inside addOpenGroup(...)
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete() // FIXME: It's probably cleaner to do this inside addOpenGroup(...)
}
.catch(on: DispatchQueue.main) { error in
let alert = UIAlertController(title: "Couldn't Join", message: error.localizedDescription, preferredStyle: .alert)

View File

@ -522,22 +522,52 @@ final class HomeVC : BaseVC, UITableViewDataSource, UITableViewDelegate, NewConv
}
unpin.backgroundColor = Colors.pathsBuilding
if let thread = thread as? TSContactThread {
if let thread = thread as? TSContactThread, !thread.isNoteToSelf() {
let publicKey = thread.contactSessionID()
let blockingManager = SSKEnvironment.shared.blockingManager
let isBlocked = blockingManager.isRecipientIdBlocked(publicKey)
let block = UITableViewRowAction(style: .normal, title: NSLocalizedString("BLOCK_LIST_BLOCK_BUTTON", comment: "")) { _, _ in
blockingManager.addBlockedPhoneNumber(publicKey)
tableView.reloadRows(at: [ indexPath ], with: UITableView.RowAnimation.fade)
Storage.shared.write(
with: { transaction in
guard let transaction = transaction as? YapDatabaseReadWriteTransaction, let contact: Contact = Storage.shared.getContact(with: publicKey, using: transaction) else {
return
}
contact.isBlocked = true
Storage.shared.setContact(contact, using: transaction as Any)
},
completion: {
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete()
DispatchQueue.main.async {
tableView.reloadRows(at: [ indexPath ], with: UITableView.RowAnimation.fade)
}
}
)
}
block.backgroundColor = Colors.unimportant
let unblock = UITableViewRowAction(style: .normal, title: NSLocalizedString("BLOCK_LIST_UNBLOCK_BUTTON", comment: "")) { _, _ in
blockingManager.removeBlockedPhoneNumber(publicKey)
tableView.reloadRows(at: [ indexPath ], with: UITableView.RowAnimation.fade)
Storage.shared.write(
with: { transaction in
guard let transaction = transaction as? YapDatabaseReadWriteTransaction, let contact: Contact = Storage.shared.getContact(with: publicKey, using: transaction) else {
return
}
contact.isBlocked = false
Storage.shared.setContact(contact, using: transaction as Any)
},
completion: {
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete()
DispatchQueue.main.async {
tableView.reloadRows(at: [ indexPath ], with: UITableView.RowAnimation.fade)
}
}
)
}
unblock.backgroundColor = Colors.unimportant
return [ delete, (isBlocked ? unblock : block), (isPinned ? unpin : pin) ]
} else {
return [ delete, (thread.isBlocked() ? unblock : block), (isPinned ? unpin : pin) ]
}
else {
return [ delete, (isPinned ? unpin : pin) ]
}
}

View File

@ -347,23 +347,23 @@ class MessageRequestsViewController: BaseVC, UITableViewDelegate, UITableViewDat
needsSync = true
}
}
// Block the contact
if
let sessionId: String = (thread as? TSContactThread)?.contactSessionID(),
!thread.isBlocked(),
let contact: Contact = Storage.shared.getContact(with: sessionId, using: transaction)
{
contact.isBlocked = true
Storage.shared.setContact(contact, using: transaction)
needsSync = true
}
}
},
completion: {
// Block all the contacts
threads.forEach { thread in
if let sessionId: String = (thread as? TSContactThread)?.contactSessionID(), !OWSBlockingManager.shared().isRecipientIdBlocked(sessionId) {
OWSBlockingManager.shared().addBlockedPhoneNumber(sessionId)
}
}
// Force a config sync (must run on the main thread)
// Force a config sync
if needsSync {
DispatchQueue.main.async {
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.forceSyncConfigurationNowIfNeeded().retainUntilComplete()
}
}
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete()
}
}
)
@ -381,19 +381,20 @@ class MessageRequestsViewController: BaseVC, UITableViewDelegate, UITableViewDat
with: { [weak self] transaction in
Storage.shared.cancelPendingMessageSendJobs(for: uniqueId, using: transaction)
self?.updateContactAndThread(thread: thread, with: transaction)
// Block the contact
if
let sessionId: String = (thread as? TSContactThread)?.contactSessionID(),
!thread.isBlocked(),
let contact: Contact = Storage.shared.getContact(with: sessionId, using: transaction)
{
contact.isBlocked = true
Storage.shared.setContact(contact, using: transaction)
}
},
completion: {
// Block the contact
if let sessionId: String = (thread as? TSContactThread)?.contactSessionID(), !OWSBlockingManager.shared().isRecipientIdBlocked(sessionId) {
OWSBlockingManager.shared().addBlockedPhoneNumber(sessionId)
}
// Force a config sync (must run on the main thread)
DispatchQueue.main.async {
if let appDelegate = UIApplication.shared.delegate as? AppDelegate {
appDelegate.forceSyncConfigurationNowIfNeeded().retainUntilComplete()
}
}
// Force a config sync
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete()
}
)
})

View File

@ -173,10 +173,10 @@ static NSTimeInterval launchStartedAt;
[AppEnvironment.shared setup];
[SignalApp.sharedApp setup];
}
migrationCompletion:^{
migrationCompletion:^(BOOL successful, BOOL needsConfigSync){
OWSAssertIsOnMainThread();
[self versionMigrationsDidComplete];
[self versionMigrationsDidCompleteNeedingConfigSync:needsConfigSync];
}];
[SNConfiguration performMainSetup];
@ -411,11 +411,16 @@ static NSTimeInterval launchStartedAt;
}
}
- (void)versionMigrationsDidComplete
- (void)versionMigrationsDidCompleteNeedingConfigSync:(BOOL)needsConfigSync
{
OWSAssertIsOnMainThread();
self.areVersionMigrationsComplete = YES;
// If we need a config sync then trigger it now
if (needsConfigSync) {
[SNMessageSender forceSyncConfigurationNow];
}
[self checkIfAppIsReady];
}

View File

@ -145,39 +145,16 @@ extension AppDelegate {
let userDefaults = UserDefaults.standard
let lastSync = userDefaults[.lastConfigurationSync] ?? .distantPast
guard Date().timeIntervalSince(lastSync) > 7 * 24 * 60 * 60 else { return } // Sync every 2 days
let destination = Message.Destination.contact(publicKey: getUserHexEncodedPublicKey())
Storage.write { transaction in
guard let configurationMessage = ConfigurationMessage.getCurrent(with: transaction) else { return }
let job = MessageSendJob(message: configurationMessage, destination: destination)
JobQueue.shared.add(job, using: transaction)
}
// 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[.hasSyncedInitialConfiguration] {
userDefaults[.lastConfigurationSync] = Date()
}
}
func forceSyncConfigurationNowIfNeeded() -> Promise<Void> {
let destination = Message.Destination.contact(publicKey: getUserHexEncodedPublicKey())
let (promise, seal) = Promise<Void>.pending()
// Note: SQLite only supports a single write thread so we can be sure this will retrieve the most up-to-date data
Storage.writeSync { transaction in
guard Storage.shared.getUser(using: transaction)?.name != nil, let configurationMessage = ConfigurationMessage.getCurrent(with: transaction) else {
seal.fulfill(())
return
MessageSender.syncConfiguration(forceSyncNow: false)
.done {
// 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[.hasSyncedInitialConfiguration] {
userDefaults[.lastConfigurationSync] = Date()
}
}
MessageSender.send(configurationMessage, to: destination, using: transaction).done {
seal.fulfill(())
}.catch { _ in
seal.fulfill(()) // Fulfill even if this failed; the configuration in the swarm should be at most 2 days old
}.retainUntilComplete()
}
return promise
.retainUntilComplete()
}
// MARK: Closed group poller

View File

@ -144,8 +144,7 @@ final class JoinOpenGroupVC : BaseVC, UIPageViewControllerDataSource, UIPageView
OpenGroupManagerV2.shared.add(room: room, server: server, publicKey: publicKey, using: transaction)
.done(on: DispatchQueue.main) { [weak self] _ in
self?.presentingViewController?.dismiss(animated: true, completion: nil)
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.forceSyncConfigurationNowIfNeeded().retainUntilComplete() // FIXME: It's probably cleaner to do this inside addOpenGroup(...)
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete() // FIXME: It's probably cleaner to do this inside addOpenGroup(...)
}
.catch(on: DispatchQueue.main) { [weak self] error in
self?.dismiss(animated: true, completion: nil) // Dismiss the loader

View File

@ -130,9 +130,8 @@ final class NukeDataModal : Modal {
}
@objc private func clearDeviceOnly() {
let appDelegate = UIApplication.shared.delegate as! AppDelegate
ModalActivityIndicatorViewController.present(fromViewController: self, canCancel: false) { [weak self] _ in
appDelegate.forceSyncConfigurationNowIfNeeded().ensure(on: DispatchQueue.main) {
MessageSender.syncConfiguration(forceSyncNow: true).ensure(on: DispatchQueue.main) {
self?.dismiss(animated: true, completion: nil) // Dismiss the loader
UserDefaults.removeAll() // Not done in the nuke data implementation as unlinking requires this to happen later
General.Cache.cachedEncodedPublicKey.mutate { $0 = nil } // Remove the cached key so it gets re-cached on next access

View File

@ -1,4 +1,5 @@
import UIKit
import SessionMessagingKit
final class SettingsVC : BaseVC, AvatarViewHelperDelegate {
private var profilePictureToBeUploaded: UIImage?
@ -373,8 +374,7 @@ final class SettingsVC : BaseVC, AvatarViewHelperDelegate {
if profilePictureToBeUploaded != nil {
userDefaults[.lastProfilePictureUpdate] = Date()
}
let appDelegate = UIApplication.shared.delegate as! AppDelegate
appDelegate.forceSyncConfigurationNowIfNeeded().retainUntilComplete()
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete()
DispatchQueue.main.async {
modalActivityIndicator.dismiss {
guard let self = self else { return }

View File

@ -286,16 +286,12 @@ final class ConversationCell : UITableViewCell {
AssertIsOnMainThread()
guard let thread = threadViewModel?.threadRecord else { return }
backgroundColor = threadViewModel.isPinned ? Colors.cellPinned : Colors.cellBackground
let isBlocked: Bool
if let thread = thread as? TSContactThread {
isBlocked = SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(thread.contactSessionID())
} else {
isBlocked = false
}
if isBlocked {
if thread.isBlocked() {
accentLineView.backgroundColor = Colors.destructive
accentLineView.alpha = 1
} else {
}
else {
accentLineView.backgroundColor = Colors.accent
accentLineView.alpha = threadViewModel.hasUnreadMessages ? 1 : 0.0001 // Setting the alpha to exactly 0 causes an issue on iOS 12
}

View File

@ -1,3 +1,4 @@
import Foundation
@objc(SNContact)
public class Contact : NSObject, NSCoding { // NSObject/NSCoding conformance is needed for YapDatabase compatibility
@ -15,9 +16,17 @@ public class Contact : NSObject, NSCoding { // NSObject/NSCoding conformance is
/// This flag is used to determine whether message requests from this contact are approved
@objc public var isApproved = false
/// This flag is used to determine whether message requests from this contact are blocked
@objc public var isBlocked = false
@objc public var isBlocked = false {
didSet {
if isBlocked {
hasBeenBlocked = true
}
}
}
/// This flag is used to determine whether this contact has approved the current users message request
@objc public var didApproveMe = false
/// This flag is used to determine whether this contact has ever been blocked (will be included in the config message if so)
@objc public var hasBeenBlocked = false
// MARK: Name
/// The name of the contact. Use this whenever you need the "real", underlying name of a user (e.g. when sending a message).
@ -72,9 +81,11 @@ public class Contact : NSObject, NSCoding { // NSObject/NSCoding conformance is
if let profileEncryptionKey = coder.decodeObject(forKey: "profilePictureEncryptionKey") as! OWSAES256Key? { self.profileEncryptionKey = profileEncryptionKey }
if let threadID = coder.decodeObject(forKey: "threadID") as! String? { self.threadID = threadID }
let isBlockedFlag: Bool = coder.decodeBool(forKey: "isBlocked")
isApproved = coder.decodeBool(forKey: "isApproved")
isBlocked = coder.decodeBool(forKey: "isBlocked")
isBlocked = isBlockedFlag
didApproveMe = coder.decodeBool(forKey: "didApproveMe")
hasBeenBlocked = (coder.decodeBool(forKey: "hasBeenBlocked") || isBlockedFlag)
}
public func encode(with coder: NSCoder) {
@ -89,6 +100,7 @@ public class Contact : NSObject, NSCoding { // NSObject/NSCoding conformance is
coder.encode(isApproved, forKey: "isApproved")
coder.encode(isBlocked, forKey: "isBlocked")
coder.encode(didApproveMe, forKey: "didApproveMe")
coder.encode(hasBeenBlocked, forKey: "hasBeenBlocked")
}
// MARK: Equality

View File

@ -2,9 +2,11 @@
public extension Notification.Name {
static let contactUpdated = Notification.Name("contactUpdated")
static let contactBlockedStateChanged = Notification.Name("contactBlockedStateChanged")
}
@objc public extension NSNotification {
@objc static let contactUpdated = Notification.Name.contactUpdated.rawValue as NSString
@objc static let contactBlockedStateChanged = Notification.Name.contactBlockedStateChanged.rawValue as NSString
}

View File

@ -43,12 +43,18 @@ extension Storage {
// Post notification
let notificationCenter = NotificationCenter.default
notificationCenter.post(name: .contactUpdated, object: contact.sessionID)
if contact.sessionID == getUserHexEncodedPublicKey() {
notificationCenter.post(name: Notification.Name(kNSNotificationName_LocalProfileDidChange), object: nil)
} else {
}
else {
let userInfo = [ kNSNotificationKey_ProfileRecipientId : contact.sessionID ]
notificationCenter.post(name: Notification.Name(kNSNotificationName_OtherUsersProfileDidChange), object: nil, userInfo: userInfo)
}
if contact.isBlocked != oldContact?.isBlocked {
notificationCenter.post(name: .contactBlockedStateChanged, object: contact.sessionID)
}
}
}

View File

@ -9,7 +9,6 @@
#import "TSIncomingMessage.h"
#import "TSOutgoingMessage.h"
#import "TSThread.h"
#import "OWSBlockingManager.h"
#import <YapDatabase/YapDatabaseAutoView.h>
#import <YapDatabase/YapDatabaseCrossProcessNotification.h>
#import <YapDatabase/YapDatabaseViewTypes.h>
@ -264,7 +263,7 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
if ([thread isMessageRequestUsingTransaction:transaction]) {
// Don't show blocked threads at all
if ([[OWSBlockingManager sharedManager] isThreadBlocked: thread]) {
if (thread.isBlocked) {
return nil;
}

View File

@ -44,7 +44,7 @@ extension ConfigurationMessage {
if let threadId: String = thread.uniqueId, let v2OpenGroup = storage.getV2OpenGroup(for: threadId) {
openGroups.insert("\(v2OpenGroup.server)/\(v2OpenGroup.room)?public_key=\(v2OpenGroup.publicKey)")
}
default: break
}
}
@ -66,7 +66,8 @@ extension ConfigurationMessage {
contact.didApproveMe ||
// Sync blocked contacts
SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(contact.sessionID)
contact.isBlocked ||
contact.hasBeenBlocked
)
else {
return nil
@ -85,7 +86,7 @@ extension ConfigurationMessage {
hasIsApproved: true,
isApproved: contact.isApproved,
hasIsBlocked: true,
isBlocked: SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(contact.sessionID),
isBlocked: contact.isBlocked,
hasDidApproveMe: true,
didApproveMe: contact.didApproveMe
)

View File

@ -10,7 +10,6 @@ FOUNDATION_EXPORT const unsigned char SessionMessagingKitVersionString[];
#import <SessionMessagingKit/OWSAudioPlayer.h>
#import <SessionMessagingKit/OWSBackgroundTask.h>
#import <SessionMessagingKit/OWSBackupFragment.h>
#import <SessionMessagingKit/OWSBlockingManager.h>
#import <SessionMessagingKit/OWSDisappearingConfigurationUpdateInfoMessage.h>
#import <SessionMessagingKit/OWSDisappearingMessagesConfiguration.h>
#import <SessionMessagingKit/OWSDisappearingMessagesFinder.h>

View File

@ -1,49 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class OWSPrimaryStorage;
@class TSGroupModel;
@class TSThread;
extern NSString *const kNSNotificationName_BlockListDidChange;
extern NSString *const kOWSBlockingManager_BlockListCollection;
// This class can be safely accessed and used from any thread.
@interface OWSBlockingManager : NSObject
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage NS_DESIGNATED_INITIALIZER;
+ (instancetype)sharedManager;
- (void)addBlockedPhoneNumber:(NSString *)phoneNumber;
- (void)removeBlockedPhoneNumber:(NSString *)phoneNumber;
// When updating the block list from a sync message, we don't
// want to fire a sync message.
- (void)setBlockedPhoneNumbers:(NSArray<NSString *> *)blockedPhoneNumbers sendSyncMessage:(BOOL)sendSyncMessage;
// TODO convert to property
- (NSArray<NSString *> *)blockedPhoneNumbers;
@property (readonly) NSArray<NSData *> *blockedGroupIds;
@property (readonly) NSArray<TSGroupModel *> *blockedGroups;
- (void)addBlockedGroup:(TSGroupModel *)group;
- (void)removeBlockedGroupId:(NSData *)groupId;
- (nullable TSGroupModel *)cachedGroupDetailsWithGroupId:(NSData *)groupId;
- (BOOL)isRecipientIdBlocked:(NSString *)recipientId;
- (BOOL)isGroupIdBlocked:(NSData *)groupId;
- (BOOL)isThreadBlocked:(TSThread *)thread;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,348 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import "OWSBlockingManager.h"
#import "AppContext.h"
#import "AppReadiness.h"
#import "NSNotificationCenter+OWS.h"
#import "OWSPrimaryStorage.h"
#import "SSKEnvironment.h"
#import "TSContactThread.h"
#import "TSGroupThread.h"
#import "YapDatabaseConnection+OWS.h"
#import <SessionMessagingKit/SessionMessagingKit-Swift.h>
#import <SessionUtilitiesKit/SessionUtilitiesKit-Swift.h>
NS_ASSUME_NONNULL_BEGIN
NSString *const kNSNotificationName_BlockListDidChange = @"kNSNotificationName_BlockListDidChange";
NSString *const kOWSBlockingManager_BlockListCollection = @"kOWSBlockingManager_BlockedPhoneNumbersCollection";
// These keys are used to persist the current local "block list" state.
NSString *const kOWSBlockingManager_BlockedPhoneNumbersKey = @"kOWSBlockingManager_BlockedPhoneNumbersKey";
NSString *const kOWSBlockingManager_BlockedGroupMapKey = @"kOWSBlockingManager_BlockedGroupMapKey";
// These keys are used to persist the most recently synced remote "block list" state.
NSString *const kOWSBlockingManager_SyncedBlockedPhoneNumbersKey = @"kOWSBlockingManager_SyncedBlockedPhoneNumbersKey";
NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingManager_SyncedBlockedGroupIdsKey";
@interface OWSBlockingManager ()
@property (nonatomic, readonly) YapDatabaseConnection *dbConnection;
// We don't store the phone numbers as instances of PhoneNumber to avoid
// consistency issues between clients, but these should all be valid e164
// phone numbers.
@property (atomic, readonly) NSMutableSet<NSString *> *blockedPhoneNumberSet;
@property (atomic, readonly) NSMutableDictionary<NSData *, TSGroupModel *> *blockedGroupMap;
@end
#pragma mark -
@implementation OWSBlockingManager
+ (instancetype)sharedManager
{
return SSKEnvironment.shared.blockingManager;
}
- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage
{
self = [super init];
if (!self) {
return self;
}
_dbConnection = primaryStorage.newDatabaseConnection;
return self;
}
- (void)dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (void)observeNotifications
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(applicationDidBecomeActive:)
name:OWSApplicationDidBecomeActiveNotification
object:nil];
}
#pragma mark -
- (BOOL)isThreadBlocked:(TSThread *)thread
{
if ([thread isKindOfClass:[TSContactThread class]]) {
TSContactThread *contactThread = (TSContactThread *)thread;
return [self isRecipientIdBlocked:contactThread.contactSessionID];
} else if ([thread isKindOfClass:[TSGroupThread class]]) {
TSGroupThread *groupThread = (TSGroupThread *)thread;
return [self isGroupIdBlocked:groupThread.groupModel.groupId];
} else {
return NO;
}
}
#pragma mark - Contact Blocking
- (void)addBlockedPhoneNumber:(NSString *)phoneNumber
{
@synchronized(self)
{
[self ensureLazyInitialization];
if ([_blockedPhoneNumberSet containsObject:phoneNumber]) {
// Ignore redundant changes.
return;
}
[_blockedPhoneNumberSet addObject:phoneNumber];
}
[self handleUpdate];
}
- (void)removeBlockedPhoneNumber:(NSString *)phoneNumber
{
@synchronized(self)
{
[self ensureLazyInitialization];
if (![_blockedPhoneNumberSet containsObject:phoneNumber]) {
// Ignore redundant changes.
return;
}
[_blockedPhoneNumberSet removeObject:phoneNumber];
}
[self handleUpdate];
}
- (void)setBlockedPhoneNumbers:(NSArray<NSString *> *)blockedPhoneNumbers sendSyncMessage:(BOOL)sendSyncMessage
{
@synchronized(self)
{
[self ensureLazyInitialization];
NSSet *newSet = [NSSet setWithArray:blockedPhoneNumbers];
if ([_blockedPhoneNumberSet isEqualToSet:newSet]) {
return;
}
_blockedPhoneNumberSet = [newSet mutableCopy];
}
[self handleUpdate:sendSyncMessage];
}
- (NSArray<NSString *> *)blockedPhoneNumbers
{
@synchronized(self)
{
[self ensureLazyInitialization];
return [_blockedPhoneNumberSet.allObjects sortedArrayUsingSelector:@selector(compare:)];
}
}
- (BOOL)isRecipientIdBlocked:(NSString *)recipientId
{
return [self.blockedPhoneNumbers containsObject:recipientId];
}
#pragma mark - Group Blocking
- (NSArray<NSData *> *)blockedGroupIds
{
@synchronized(self) {
[self ensureLazyInitialization];
return self.blockedGroupMap.allKeys;
}
}
- (NSArray<TSGroupModel *> *)blockedGroups
{
@synchronized(self) {
[self ensureLazyInitialization];
return self.blockedGroupMap.allValues;
}
}
- (BOOL)isGroupIdBlocked:(NSData *)groupId
{
return self.blockedGroupMap[groupId] != nil;
}
- (nullable TSGroupModel *)cachedGroupDetailsWithGroupId:(NSData *)groupId
{
@synchronized(self) {
return self.blockedGroupMap[groupId];
}
}
- (void)addBlockedGroup:(TSGroupModel *)groupModel
{
NSData *groupId = groupModel.groupId;
@synchronized(self) {
[self ensureLazyInitialization];
if ([self isGroupIdBlocked:groupId]) {
// Ignore redundant changes.
return;
}
self.blockedGroupMap[groupId] = groupModel;
}
[self handleUpdate];
}
- (void)removeBlockedGroupId:(NSData *)groupId
{
@synchronized(self) {
[self ensureLazyInitialization];
if (![self isGroupIdBlocked:groupId]) {
// Ignore redundant changes.
return;
}
[self.blockedGroupMap removeObjectForKey:groupId];
}
[self handleUpdate];
}
#pragma mark - Updates
// This should be called every time the block list changes.
- (void)handleUpdate
{
// By default, always send a sync message when the block list changes.
[self handleUpdate:YES];
}
// TODO label the `sendSyncMessage` param
- (void)handleUpdate:(BOOL)sendSyncMessage
{
NSArray<NSString *> *blockedPhoneNumbers = [self blockedPhoneNumbers];
[self.dbConnection setObject:blockedPhoneNumbers
forKey:kOWSBlockingManager_BlockedPhoneNumbersKey
inCollection:kOWSBlockingManager_BlockListCollection];
NSDictionary *blockedGroupMap;
@synchronized(self) {
blockedGroupMap = [self.blockedGroupMap copy];
}
NSArray<NSData *> *blockedGroupIds = blockedGroupMap.allKeys;
[self.dbConnection setObject:blockedGroupMap
forKey:kOWSBlockingManager_BlockedGroupMapKey
inCollection:kOWSBlockingManager_BlockListCollection];
// Update the contact blocked state (so sync'ing won't be busted)
NSMutableArray<SNContact *> *contactsToUpdate = [[NSMutableArray alloc] init];
[[[LKStorage shared] getAllContacts] enumerateObjectsUsingBlock:^(SNContact * _Nonnull obj, BOOL * _Nonnull stop) {
// If the blocked flag doesn't match then add it to the array to be saved
BOOL contactInBlockedList = [blockedPhoneNumbers containsObject:obj.sessionID];
if (obj.isBlocked != contactInBlockedList) {
obj.isBlocked = contactInBlockedList;
[contactsToUpdate addObject:obj];
}
}];
if ([contactsToUpdate count] > 0) {
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) {
[contactsToUpdate enumerateObjectsUsingBlock:^(SNContact * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
[[LKStorage shared] setContact:obj usingTransaction:transaction];
}];
}];
}
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if (sendSyncMessage) {
} else {
// If this update came from an incoming block list sync message,
// update the "synced blocked list" state immediately,
// since we're now in sync.
//
// There could be data loss if both clients modify the block list
// at the same time, but:
//
// a) Block list changes will be rare.
// b) Conflicting block list changes will be even rarer.
// c) It's unlikely a user will make conflicting changes on two
// devices around the same time.
// d) There isn't a good way to avoid this.
[self saveSyncedBlockListWithPhoneNumbers:blockedPhoneNumbers groupIds:blockedGroupIds];
}
[[NSNotificationCenter defaultCenter] postNotificationNameAsync:kNSNotificationName_BlockListDidChange
object:nil
userInfo:nil];
});
}
// This method should only be called from within a synchronized block.
- (void)ensureLazyInitialization
{
if (_blockedPhoneNumberSet) {
// already loaded
return;
}
NSArray<NSString *> *blockedPhoneNumbers =
[self.dbConnection objectForKey:kOWSBlockingManager_BlockedPhoneNumbersKey
inCollection:kOWSBlockingManager_BlockListCollection];
_blockedPhoneNumberSet = [[NSMutableSet alloc] initWithArray:(blockedPhoneNumbers ?: [NSArray new])];
NSDictionary<NSData *, TSGroupModel *> *storedBlockedGroupMap =
[self.dbConnection objectForKey:kOWSBlockingManager_BlockedGroupMapKey
inCollection:kOWSBlockingManager_BlockListCollection];
if ([storedBlockedGroupMap isKindOfClass:[NSDictionary class]]) {
_blockedGroupMap = [storedBlockedGroupMap mutableCopy];
} else {
_blockedGroupMap = [NSMutableDictionary new];
}
[self observeNotifications];
}
/// Records the last block list which we successfully synced.
- (void)saveSyncedBlockListWithPhoneNumbers:(NSArray<NSString *> *)blockedPhoneNumbers
groupIds:(NSArray<NSData *> *)blockedGroupIds
{
[self.dbConnection setObject:blockedPhoneNumbers
forKey:kOWSBlockingManager_SyncedBlockedPhoneNumbersKey
inCollection:kOWSBlockingManager_BlockListCollection];
[self.dbConnection setObject:blockedGroupIds
forKey:kOWSBlockingManager_SyncedBlockedGroupIdsKey
inCollection:kOWSBlockingManager_BlockListCollection];
}
#pragma mark - Notifications
- (void)applicationDidBecomeActive:(NSNotification *)notification
{
}
@end
NS_ASSUME_NONNULL_END

View File

@ -4,10 +4,6 @@ import WebRTC
extension MessageReceiver {
internal static func isBlocked(_ publicKey: String) -> Bool {
return SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(publicKey)
}
public static func handle(_ message: Message, associatedWithProto proto: SNProtoContent, openGroupID: String?, isBackgroundPoll: Bool, using transaction: Any) throws {
switch message {
case let message as ReadReceipt: handleReadReceipt(message, using: transaction)
@ -214,6 +210,7 @@ extension MessageReceiver {
for contactInfo in message.contacts {
let sessionID = contactInfo.publicKey!
let contact = (Storage.shared.getContact(with: sessionID, using: transaction) ?? Contact(sessionID: sessionID))
let contactWasBlocked: Bool = contact.isBlocked
if let profileKey = contactInfo.profileKey { contact.profileEncryptionKey = OWSAES256Key(data: profileKey) }
contact.profilePictureURL = contactInfo.profilePictureURL
contact.name = contactInfo.displayName
@ -239,7 +236,7 @@ extension MessageReceiver {
// associated with them that is a message request thread then delete it (assume
// that the current user had deleted that message request)
if
contactInfo.isBlocked != OWSBlockingManager.shared().isRecipientIdBlocked(sessionID),
contactInfo.isBlocked != contactWasBlocked,
let thread: TSContactThread = TSContactThread.fetch(for: sessionID, using: transaction),
thread.isMessageRequest(using: transaction)
{
@ -249,22 +246,6 @@ extension MessageReceiver {
}
}
// FIXME: 'OWSBlockingManager' manages it's own dbConnection and transactions so we have to dispatch this to prevent deadlocks
DispatchQueue.global().async {
for contactInfo in message.contacts {
let sessionID = contactInfo.publicKey!
if contactInfo.hasIsBlocked && contactInfo.isBlocked != OWSBlockingManager.shared().isRecipientIdBlocked(sessionID) {
if contactInfo.isBlocked {
OWSBlockingManager.shared().addBlockedPhoneNumber(sessionID)
}
else {
OWSBlockingManager.shared().removeBlockedPhoneNumber(sessionID)
}
}
}
}
// Closed groups
//
// Note: Only want to add these for initial sync to avoid re-adding closed groups the user
@ -875,23 +856,10 @@ extension MessageReceiver {
Storage.shared.setContact(contact, using: transaction)
}
// Force a config sync to ensure all devices know the contact approval state if desired (Note: This logic
// should match the behaviour in AppDelegate.forceSyncConfigurationNowIfNeeded())
// Force a config sync to ensure all devices know the contact approval state if desired
guard forceConfigSync else { return }
// Note: We MUST run this async as we need to ensure the database `transaction` has finished before we generate
// a new configuration message (otherwise the `contact` will be loaded direct from the database and the
// `didApproveMe` value won't have been updated)
DispatchQueue.global(qos: .background).async {
Storage.write { transaction in
guard Storage.shared.getUser()?.name != nil, let configurationMessage = ConfigurationMessage.getCurrent(with: transaction) else {
return
}
let destination: Message.Destination = Message.Destination.contact(publicKey: userPublicKey)
MessageSender.send(configurationMessage, to: destination, using: transaction).retainUntilComplete()
}
}
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete()
}
public static func handleMessageRequestResponse(_ message: MessageRequestResponse, using transaction: Any) {

View File

@ -110,8 +110,12 @@ public enum MessageReceiver {
default: throw Error.unknownEnvelopeType
}
}
// Don't process the envelope any further if the sender is blocked
guard !isBlocked(sender) else { throw Error.senderBlocked }
guard Storage.shared.getContact(with: sender, using: transaction)?.isBlocked != true else {
throw Error.senderBlocked
}
// Parse the proto
let proto: SNProtoContent
do {

View File

@ -83,6 +83,20 @@ NSString *const TSContactThreadPrefix = @"c";
);
}
- (BOOL)isBlocked {
NSString *sessionID = self.contactSessionID;
SNContact *contact = [LKStorage.shared getContactWithSessionID:sessionID];
return (contact.isBlocked == YES);
}
- (BOOL)isBlockedUsingTransaction:(YapDatabaseReadTransaction *)transaction {
NSString *sessionID = self.contactSessionID;
SNContact *contact = [LKStorage.shared getContactWithSessionID:sessionID using:transaction];
return (contact.isBlocked == YES);
}
- (BOOL)isGroupThread
{
return NO;

View File

@ -62,6 +62,9 @@ BOOL IsNoteToSelfEnabled(void);
- (BOOL)isMessageRequest;
- (BOOL)isMessageRequestUsingTransaction:(YapDatabaseReadTransaction *)transaction;
- (BOOL)isBlocked;
- (BOOL)isBlockedUsingTransaction:(YapDatabaseReadTransaction *)transaction;
#pragma mark Interactions
- (void)enumerateInteractionsWithTransaction:(YapDatabaseReadTransaction *)transaction usingBlock:(void (^)(TSInteraction *interaction, BOOL *stop))block;

View File

@ -142,6 +142,16 @@ BOOL IsNoteToSelfEnabled(void)
return NO;
}
// Override in ContactThread
- (BOOL)isBlocked {
return NO;
}
// Override in ContactThread
- (BOOL)isBlockedUsingTransaction:(YapDatabaseReadTransaction *)transaction {
return NO;
}
#pragma mark To be subclassed.
- (BOOL)isGroupThread {

View File

@ -11,7 +11,6 @@ NS_ASSUME_NONNULL_BEGIN
@class OWS2FAManager;
@class OWSAttachmentDownloads;
@class OWSBatchMessageProcessor;
@class OWSBlockingManager;
@class OWSDisappearingMessagesJob;
@class OWSIdentityManager;
@class OWSMessageDecrypter;
@ -39,7 +38,6 @@ NS_ASSUME_NONNULL_BEGIN
- (instancetype)initWithProfileManager:(id<ProfileManagerProtocol>)profileManager
primaryStorage:(OWSPrimaryStorage *)primaryStorage
blockingManager:(OWSBlockingManager *)blockingManager
identityManager:(OWSIdentityManager *)identityManager
tsAccountManager:(TSAccountManager *)tsAccountManager
disappearingMessagesJob:(OWSDisappearingMessagesJob *)disappearingMessagesJob
@ -61,7 +59,6 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) id<ProfileManagerProtocol> profileManager;
@property (nonatomic, readonly) OWSPrimaryStorage *primaryStorage;
@property (nonatomic, readonly) OWSBlockingManager *blockingManager;
@property (nonatomic, readonly) OWSIdentityManager *identityManager;
@property (nonatomic, readonly) TSAccountManager *tsAccountManager;
@property (nonatomic, readonly) OWSDisappearingMessagesJob *disappearingMessagesJob;

View File

@ -14,7 +14,6 @@ static SSKEnvironment *sharedSSKEnvironment;
@property (nonatomic) id<ProfileManagerProtocol> profileManager;
@property (nonatomic) OWSPrimaryStorage *primaryStorage;
@property (nonatomic) OWSBlockingManager *blockingManager;
@property (nonatomic) OWSIdentityManager *identityManager;
@property (nonatomic) TSAccountManager *tsAccountManager;
@property (nonatomic) OWSDisappearingMessagesJob *disappearingMessagesJob;
@ -37,7 +36,6 @@ static SSKEnvironment *sharedSSKEnvironment;
- (instancetype)initWithProfileManager:(id<ProfileManagerProtocol>)profileManager
primaryStorage:(OWSPrimaryStorage *)primaryStorage
blockingManager:(OWSBlockingManager *)blockingManager
identityManager:(OWSIdentityManager *)identityManager
tsAccountManager:(TSAccountManager *)tsAccountManager
disappearingMessagesJob:(OWSDisappearingMessagesJob *)disappearingMessagesJob
@ -54,7 +52,6 @@ static SSKEnvironment *sharedSSKEnvironment;
_profileManager = profileManager;
_primaryStorage = primaryStorage;
_blockingManager = blockingManager;
_identityManager = identityManager;
_tsAccountManager = tsAccountManager;
_disappearingMessagesJob = disappearingMessagesJob;

View File

@ -121,8 +121,8 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension
appSpecificSingletonBlock: {
SSKEnvironment.shared.notificationsManager = NSENotificationPresenter()
},
migrationCompletion: { [weak self] in
self?.versionMigrationsDidComplete()
migrationCompletion: { [weak self] _, needsConfigSync in
self?.versionMigrationsDidComplete(needsConfigSync: needsConfigSync)
completion()
}
)
@ -131,10 +131,15 @@ public final class NotificationServiceExtension : UNNotificationServiceExtension
}
@objc
private func versionMigrationsDidComplete() {
private func versionMigrationsDidComplete(needsConfigSync: Bool) {
AssertIsOnMainThread()
areVersionMigrationsComplete = true
// If we need a config sync then trigger it now
if needsConfigSync {
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete()
}
checkIsAppReady()
}

View File

@ -46,14 +46,12 @@ final class ShareVC : UINavigationController, ShareViewDelegate, AppModeManagerD
appSpecificSingletonBlock: {
SSKEnvironment.shared.notificationsManager = NoopNotificationsManager()
},
migrationCompletion: { [weak self] in
migrationCompletion: { [weak self] _, needsConfigSync in
AssertIsOnMainThread()
self?.versionMigrationsDidComplete()
// performUpdateCheck must be invoked after Environment has been initialized because
// upgrade process may depend on Environment.
self?.versionMigrationsDidComplete()
self?.versionMigrationsDidComplete(needsConfigSync: needsConfigSync)
}
)
@ -74,12 +72,17 @@ final class ShareVC : UINavigationController, ShareViewDelegate, AppModeManagerD
}
@objc
func versionMigrationsDidComplete() {
func versionMigrationsDidComplete(needsConfigSync: Bool) {
AssertIsOnMainThread()
Logger.debug("")
areVersionMigrationsComplete = true
// If we need a config sync then trigger it now
if needsConfigSync {
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete()
}
checkIsAppReady()
}

View File

@ -92,14 +92,7 @@ final class SimplifiedConversationCell : UITableViewCell {
guard let thread = threadViewModel?.threadRecord else { return }
let isBlocked: Bool
if let thread = thread as? TSContactThread {
isBlocked = SSKEnvironment.shared.blockingManager.isRecipientIdBlocked(thread.contactSessionID())
} else {
isBlocked = false
}
accentLineView.alpha = (isBlocked ? 1 : 0)
accentLineView.alpha = (thread.isBlocked() ? 1 : 0)
profilePictureView.update(for: thread)
displayNameLabel.text = getDisplayName()
}

View File

@ -0,0 +1,47 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
@objc(SNBlockingManagerRemovalMigration)
public class BlockingManagerRemovalMigration: OWSDatabaseMigration {
@objc
class func migrationId() -> String {
return "004"
}
override public func runUp(completion: @escaping OWSDatabaseMigrationCompletion) {
self.doMigrationAsync(completion: completion)
}
private func doMigrationAsync(completion: @escaping OWSDatabaseMigrationCompletion) {
// These are the legacy keys that were used to persist the "block list" state
let kOWSBlockingManager_BlockListCollection: String = "kOWSBlockingManager_BlockedPhoneNumbersCollection"
let kOWSBlockingManager_BlockedPhoneNumbersKey: String = "kOWSBlockingManager_BlockedPhoneNumbersKey"
let dbConnection: YapDatabaseConnection = primaryStorage.newDatabaseConnection()
let blockedSessionIds: Set<String> = Set(dbConnection.object(
forKey: kOWSBlockingManager_BlockedPhoneNumbersKey,
inCollection: kOWSBlockingManager_BlockListCollection
) as? [String] ?? [])
Storage.write(
with: { transaction in
Storage.shared.getAllContacts(with: transaction)
.filter { contact -> Bool in blockedSessionIds.contains(contact.sessionID) }
.forEach { contact in
contact.isBlocked = true
Storage.shared.setContact(contact, using: transaction)
}
// Now that the values have been migrated we can clear out the old collection
transaction.removeAllObjects(inCollection: kOWSBlockingManager_BlockListCollection)
self.save(with: transaction) // Intentionally capture self
},
completion: {
completion(true, true)
}
)
}
}

View File

@ -27,7 +27,7 @@ public class ContactsMigration : OWSDatabaseMigration {
}
self.save(with: transaction) // Intentionally capture self
}, completion: {
completion()
completion(true, false)
})
}
}

View File

@ -57,7 +57,7 @@ public class MessageRequestsMigration : OWSDatabaseMigration {
}
self.save(with: transaction) // Intentionally capture self
}, completion: {
completion()
completion(true, true)
})
}
}

View File

@ -6,7 +6,7 @@
NS_ASSUME_NONNULL_BEGIN
typedef void (^OWSDatabaseMigrationCompletion)(void);
typedef void (^OWSDatabaseMigrationCompletion)(BOOL success, BOOL requiresConfigurationSync);
@class OWSPrimaryStorage;

View File

@ -76,7 +76,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSLogInfo(@"Completed migration %@", self.uniqueId);
[self save];
completion();
completion(true, false);
}];
}

View File

@ -4,7 +4,7 @@
NS_ASSUME_NONNULL_BEGIN
typedef void (^OWSDatabaseMigrationCompletion)(void);
typedef void (^OWSDatabaseMigrationCompletion)(BOOL success, BOOL requiresConfigurationSync);
@interface OWSDatabaseMigrationRunner : NSObject

View File

@ -28,7 +28,8 @@ NS_ASSUME_NONNULL_BEGIN
return @[
[SNOpenGroupServerIdLookupMigration new],
[SNMessageRequestsMigration new],
[SNContactsMigration new]
[SNContactsMigration new],
[SNBlockingManagerRemovalMigration new]
];
}
@ -44,7 +45,10 @@ NS_ASSUME_NONNULL_BEGIN
{
[self removeUnknownMigrations];
[self runMigrations:[self.allMigrations mutableCopy] completion:completion];
[self runMigrations:[self.allMigrations mutableCopy]
prevWasSuccessful: true
prevNeedsConfigSync:false
completion:completion];
}
// Some users (especially internal users) will move back and forth between
@ -77,6 +81,8 @@ NS_ASSUME_NONNULL_BEGIN
// * Ensure predictable ordering.
// * Prevent them from interfering with each other (e.g. deadlock).
- (void)runMigrations:(NSMutableArray<OWSDatabaseMigration *> *)migrations
prevWasSuccessful:(BOOL)prevWasSuccessful
prevNeedsConfigSync:(BOOL)prevNeedsConfigSync
completion:(OWSDatabaseMigrationCompletion)completion
{
OWSAssertDebug(migrations);
@ -85,7 +91,7 @@ NS_ASSUME_NONNULL_BEGIN
// If there are no more migrations to run, complete.
if (migrations.count < 1) {
dispatch_async(dispatch_get_main_queue(), ^{
completion();
completion(prevWasSuccessful, prevNeedsConfigSync);
});
return;
}
@ -96,14 +102,20 @@ NS_ASSUME_NONNULL_BEGIN
// If migration has already been run, skip it.
if ([OWSDatabaseMigration fetchObjectWithUniqueID:migration.uniqueId] != nil) {
[self runMigrations:migrations completion:completion];
[self runMigrations:migrations
prevWasSuccessful:prevWasSuccessful
prevNeedsConfigSync:prevNeedsConfigSync
completion:completion];
return;
}
OWSLogInfo(@"Running migration: %@", migration);
[migration runUpWithCompletion:^{
[migration runUpWithCompletion:^(BOOL successful, BOOL needsConfigSync){
OWSLogInfo(@"Migration complete: %@", migration);
[self runMigrations:migrations completion:completion];
[self runMigrations:migrations
prevWasSuccessful:(prevWasSuccessful && successful)
prevNeedsConfigSync:(prevNeedsConfigSync || needsConfigSync)
completion:completion];
}];
}

View File

@ -48,7 +48,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSLogVerbose(@"%lu", (unsigned long)recordIds.count);
if (recordIds.count < 1) {
completion();
completion(true, false);
return;
}

View File

@ -42,7 +42,7 @@ public class OpenGroupServerIdLookupMigration: OWSDatabaseMigration {
}
self.save(with: transaction) // Intentionally capture self
}, completion: {
completion()
completion(true, false)
})
}
}

View File

@ -1,122 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
@objc(OWSBlockListCacheDelegate)
public protocol BlockListCacheDelegate: class {
func blockListCacheDidUpdate(_ blocklistCache: BlockListCache)
}
/// A performant cache for which contacts/groups are blocked.
///
/// The source of truth for which contacts and groups are blocked is the `blockingManager`, but because
/// those accessors are made to be thread safe, they can be slow in tight loops, e.g. when rendering table
/// view cells.
///
/// Typically you'll want to create a Cache, update it to the latest state while simultaneously being informed
/// of any future changes to block list state.
///
/// class SomeViewController: BlockListCacheDelegate {
/// let blockListCache = BlockListCache()
/// func viewDidLoad() {
/// super.viewDidLoad()
/// blockListCache.startObservingAndSyncState(delegate: self)
/// self.updateAnyViewsWhichDepondOnBlockListCache()
/// }
///
/// func blockListCacheDidUpdate(_ blocklistCache: BlockListCache) {
/// self.updateAnyViewsWhichDepondOnBlockListCache()
/// }
///
/// ...
/// }
///
@objc(OWSBlockListCache)
public class BlockListCache: NSObject {
private var blockedRecipientIds: Set<String> = Set()
private var blockedGroupIds: Set<Data> = Set()
private let serialQueue: DispatchQueue = DispatchQueue(label: "BlockListCache")
weak var delegate: BlockListCacheDelegate?
private var blockingManager: OWSBlockingManager {
return OWSBlockingManager.shared()
}
/// Generally something which wants to use this cache wants to do 3 things
/// 1. get the cache on the latest state
/// 2. update the cache whenever the blockingManager's state changes
/// 3. be notified when the cache updates
/// This method does all three.
@objc
public func startObservingAndSyncState(delegate: BlockListCacheDelegate) {
self.delegate = delegate
NotificationCenter.default.addObserver(self,
selector: #selector(blockListDidChange),
name: NSNotification.Name(rawValue: kNSNotificationName_BlockListDidChange),
object: nil)
updateWithoutNotifyingDelegate()
}
// MARK: -
@objc
func blockListDidChange() {
self.update()
}
@objc(isRecipientIdBlocked:)
public func isBlocked(recipientId: String) -> Bool {
return serialQueue.sync {
blockedRecipientIds.contains(recipientId)
}
}
@objc(isGroupIdBlocked:)
public func isBlocked(groupId: Data) -> Bool {
return serialQueue.sync {
blockedGroupIds.contains(groupId)
}
}
@objc(isThreadBlocked:)
public func isBlocked(thread: TSThread) -> Bool {
switch thread {
case let contactThread as TSContactThread:
return serialQueue.sync {
blockedRecipientIds.contains(contactThread.contactSessionID())
}
case let groupThread as TSGroupThread:
return serialQueue.sync {
blockedGroupIds.contains(groupThread.groupModel.groupId)
}
default:
owsFailDebug("\(self.logTag) in \(#function) unexpected thread type: \(type(of: thread))")
return false
}
}
// MARK: -
public func update() {
updateWithoutNotifyingDelegate()
DispatchQueue.main.async {
self.delegate?.blockListCacheDidUpdate(self)
}
}
private func updateWithoutNotifyingDelegate() {
let blockedRecipientIds = Set(blockingManager.blockedPhoneNumbers())
let blockedGroupIds = Set(blockingManager.blockedGroupIds)
update(blockedRecipientIds: blockedRecipientIds, blockedGroupIds: blockedGroupIds)
}
private func update(blockedRecipientIds: Set<String>, blockedGroupIds: Set<Data>) {
serialQueue.sync {
self.blockedRecipientIds = blockedRecipientIds
self.blockedGroupIds = blockedGroupIds
}
}
}

View File

@ -1,68 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class Contact;
@class OWSBlockingManager;
@class SignalAccount;
@class TSGroupModel;
@class TSThread;
typedef void (^BlockActionCompletionBlock)(BOOL isBlocked);
@interface BlockListUIUtils : NSObject
- (instancetype)init NS_UNAVAILABLE;
#pragma mark - Block
+ (void)showBlockThreadActionSheet:(TSThread *)thread
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
+ (void)showBlockPhoneNumberActionSheet:(NSString *)phoneNumber
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
+ (void)showBlockSignalAccountActionSheet:(SignalAccount *)signalAccount
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
#pragma mark - Unblock
+ (void)showUnblockThreadActionSheet:(TSThread *)thread
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
+ (void)showUnblockPhoneNumberActionSheet:(NSString *)phoneNumber
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
+ (void)showUnblockSignalAccountActionSheet:(SignalAccount *)signalAccount
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
+ (void)showUnblockGroupActionSheet:(TSGroupModel *)groupModel
displayName:(NSString *)displayName
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
#pragma mark - UI Utils
+ (NSString *)formatDisplayNameForAlertTitle:(NSString *)displayName;
+ (NSString *)formatDisplayNameForAlertMessage:(NSString *)displayName;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,494 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "BlockListUIUtils.h"
#import "TSContactThread.h"
#import <SessionMessagingKit/OWSBlockingManager.h>
#import <SignalUtilitiesKit/SignalAccount.h>
#import <SessionMessagingKit/TSAccountManager.h>
#import <SessionMessagingKit/TSGroupThread.h>
#import <SignalUtilitiesKit/UIUtil.h>
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
#import "UIView+OWS.h"
NS_ASSUME_NONNULL_BEGIN
typedef void (^BlockAlertCompletionBlock)(UIAlertAction *action);
@implementation BlockListUIUtils
#pragma mark - Block
+ (void)showBlockThreadActionSheet:(TSThread *)thread
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
{
if ([thread isKindOfClass:[TSContactThread class]]) {
TSContactThread *contactThread = (TSContactThread *)thread;
[self showBlockPhoneNumberActionSheet:contactThread.contactSessionID
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:completionBlock];
} else if ([thread isKindOfClass:[TSGroupThread class]]) {
TSGroupThread *groupThread = (TSGroupThread *)thread;
[self showBlockGroupActionSheet:groupThread
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:completionBlock];
} else {
OWSFailDebug(@"unexpected thread type: %@", thread.class);
}
}
+ (void)showBlockPhoneNumberActionSheet:(NSString *)phoneNumber
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
{
NSString *displayName = [[LKStorage.shared getContactWithSessionID:phoneNumber] displayNameFor:SNContactContextRegular] ?: phoneNumber;
[self showBlockPhoneNumbersActionSheet:@[ phoneNumber ]
displayName:displayName
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:completionBlock];
}
+ (void)showBlockSignalAccountActionSheet:(SignalAccount *)signalAccount
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
{
NSString *displayName = [[LKStorage.shared getContactWithSessionID:signalAccount.recipientId] displayNameFor:SNContactContextRegular] ?: signalAccount.recipientId;
[self showBlockPhoneNumbersActionSheet:@[ signalAccount.recipientId ]
displayName:displayName
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:completionBlock];
}
+ (void)showBlockPhoneNumbersActionSheet:(NSArray<NSString *> *)phoneNumbers
displayName:(NSString *)displayName
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
{
OWSAssertDebug(phoneNumbers.count > 0);
OWSAssertDebug(displayName.length > 0);
OWSAssertDebug(fromViewController);
OWSAssertDebug(blockingManager);
NSString *localContactId = [TSAccountManager localNumber];
OWSAssertDebug(localContactId.length > 0);
for (NSString *phoneNumber in phoneNumbers) {
OWSAssertDebug(phoneNumber.length > 0);
if ([localContactId isEqualToString:phoneNumber]) {
[self showOkAlertWithTitle:NSLocalizedString(@"BLOCK_LIST_VIEW_CANT_BLOCK_SELF_ALERT_TITLE",
@"The title of the 'You can't block yourself' alert.")
message:NSLocalizedString(@"BLOCK_LIST_VIEW_CANT_BLOCK_SELF_ALERT_MESSAGE",
@"The message of the 'You can't block yourself' alert.")
fromViewController:fromViewController
completionBlock:^(UIAlertAction *action) {
if (completionBlock) {
completionBlock(NO);
}
}];
return;
}
}
NSString *title = [NSString stringWithFormat:NSLocalizedString(@"BLOCK_LIST_BLOCK_USER_TITLE_FORMAT",
@"A format for the 'block user' action sheet title. Embeds {{the "
@"blocked user's name or phone number}}."),
[self formatDisplayNameForAlertTitle:displayName]];
UIAlertController *actionSheet =
[UIAlertController alertControllerWithTitle:title
message:NSLocalizedString(@"BLOCK_USER_BEHAVIOR_EXPLANATION",
@"An explanation of the consequences of blocking another user.")
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *blockAction = [UIAlertAction
actionWithTitle:NSLocalizedString(@"BLOCK_LIST_BLOCK_BUTTON", @"Button label for the 'block' button")
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"block")
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *_Nonnull action) {
[self blockPhoneNumbers:phoneNumbers
displayName:displayName
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:^(UIAlertAction *ignore) {
if (completionBlock) {
completionBlock(YES);
}
}];
}];
[actionSheet addAction:blockAction];
UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:CommonStrings.cancelButton
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"dismiss")
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
if (completionBlock) {
completionBlock(NO);
}
}];
[actionSheet addAction:dismissAction];
[fromViewController presentAlert:actionSheet];
}
+ (void)showBlockGroupActionSheet:(TSGroupThread *)groupThread
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
{
OWSAssertDebug(groupThread);
OWSAssertDebug(fromViewController);
OWSAssertDebug(blockingManager);
NSString *groupName = groupThread.name.length > 0 ? groupThread.name : TSGroupThread.defaultGroupName;
NSString *title = [NSString
stringWithFormat:NSLocalizedString(@"BLOCK_LIST_BLOCK_GROUP_TITLE_FORMAT",
@"A format for the 'block group' action sheet title. Embeds the {{group name}}."),
[self formatDisplayNameForAlertTitle:groupName]];
UIAlertController *actionSheet =
[UIAlertController alertControllerWithTitle:title
message:NSLocalizedString(@"BLOCK_GROUP_BEHAVIOR_EXPLANATION",
@"An explanation of the consequences of blocking a group.")
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *blockAction = [UIAlertAction
actionWithTitle:NSLocalizedString(@"BLOCK_LIST_BLOCK_BUTTON", @"Button label for the 'block' button")
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"block")
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *_Nonnull action) {
[self blockGroup:groupThread
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:^(UIAlertAction *ignore) {
if (completionBlock) {
completionBlock(YES);
}
}];
}];
[actionSheet addAction:blockAction];
UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:CommonStrings.cancelButton
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"dismiss")
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
if (completionBlock) {
completionBlock(NO);
}
}];
[actionSheet addAction:dismissAction];
[fromViewController presentAlert:actionSheet];
}
+ (void)blockPhoneNumbers:(NSArray<NSString *> *)phoneNumbers
displayName:(NSString *)displayName
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(BlockAlertCompletionBlock)completionBlock
{
OWSAssertDebug(phoneNumbers.count > 0);
OWSAssertDebug(displayName.length > 0);
OWSAssertDebug(fromViewController);
OWSAssertDebug(blockingManager);
for (NSString *phoneNumber in phoneNumbers) {
OWSAssertDebug(phoneNumber.length > 0);
[blockingManager addBlockedPhoneNumber:phoneNumber];
}
[self showOkAlertWithTitle:NSLocalizedString(
@"BLOCK_LIST_VIEW_BLOCKED_ALERT_TITLE", @"The title of the 'user blocked' alert.")
message:[NSString
stringWithFormat:NSLocalizedString(@"BLOCK_LIST_VIEW_BLOCKED_ALERT_MESSAGE_FORMAT",
@"The message format of the 'conversation blocked' alert. "
@"Embeds the {{conversation title}}."),
[self formatDisplayNameForAlertMessage:displayName]]
fromViewController:fromViewController
completionBlock:completionBlock];
}
+ (void)blockGroup:(TSGroupThread *)groupThread
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(BlockAlertCompletionBlock)completionBlock
{
OWSAssertDebug(groupThread);
OWSAssertDebug(fromViewController);
OWSAssertDebug(blockingManager);
// block the group regardless of the ability to deliver the "leave group" message.
[blockingManager addBlockedGroup:groupThread.groupModel];
// blockingManager.addBlocked* creates sneaky transactions, so we can't pass in a transaction
// via params and instead have to create our own sneaky transaction here.
[groupThread leaveGroupWithSneakyTransaction];
// TODO: If we ever start using this again we should make sure to send a group leave message here
NSString *groupName = groupThread.name.length > 0 ? groupThread.name : TSGroupThread.defaultGroupName;
NSString *alertTitle
= NSLocalizedString(@"BLOCK_LIST_VIEW_BLOCKED_GROUP_ALERT_TITLE", @"The title of the 'group blocked' alert.");
NSString *alertBodyFormat = NSLocalizedString(@"BLOCK_LIST_VIEW_BLOCKED_ALERT_MESSAGE_FORMAT",
@"The message format of the 'conversation blocked' alert. Embeds the {{conversation title}}.");
NSString *alertBody =
[NSString stringWithFormat:alertBodyFormat, [self formatDisplayNameForAlertMessage:groupName]];
[self showOkAlertWithTitle:alertTitle
message:alertBody
fromViewController:fromViewController
completionBlock:completionBlock];
}
#pragma mark - Unblock
+ (void)showUnblockThreadActionSheet:(TSThread *)thread
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
{
if ([thread isKindOfClass:[TSContactThread class]]) {
TSContactThread *contactThread = (TSContactThread *)thread;
[self showUnblockPhoneNumberActionSheet:contactThread.contactSessionID
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:completionBlock];
} else if ([thread isKindOfClass:[TSGroupThread class]]) {
TSGroupThread *groupThread = (TSGroupThread *)thread;
NSString *groupName = groupThread.name.length > 0 ? groupThread.name : TSGroupThread.defaultGroupName;
[self showUnblockGroupActionSheet:groupThread.groupModel
displayName:groupName
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:completionBlock];
} else {
OWSFailDebug(@"unexpected thread type: %@", thread.class);
}
}
+ (void)showUnblockPhoneNumberActionSheet:(NSString *)phoneNumber
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
{
NSString *displayName = [[LKStorage.shared getContactWithSessionID:phoneNumber] displayNameFor:SNContactContextRegular] ?: phoneNumber;
[self showUnblockPhoneNumbersActionSheet:@[ phoneNumber ]
displayName:displayName
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:completionBlock];
}
+ (void)showUnblockSignalAccountActionSheet:(SignalAccount *)signalAccount
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
{
NSString *displayName = [[LKStorage.shared getContactWithSessionID:signalAccount.recipientId] displayNameFor:SNContactContextRegular] ?: signalAccount.recipientId;
[self showUnblockPhoneNumbersActionSheet:@[ signalAccount.recipientId ]
displayName:displayName
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:completionBlock];
}
+ (void)showUnblockPhoneNumbersActionSheet:(NSArray<NSString *> *)phoneNumbers
displayName:(NSString *)displayName
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
{
OWSAssertDebug(phoneNumbers.count > 0);
OWSAssertDebug(displayName.length > 0);
OWSAssertDebug(fromViewController);
OWSAssertDebug(blockingManager);
NSString *title = [NSString
stringWithFormat:
NSLocalizedString(@"BLOCK_LIST_UNBLOCK_TITLE_FORMAT",
@"A format for the 'unblock conversation' action sheet title. Embeds the {{conversation title}}."),
[self formatDisplayNameForAlertTitle:displayName]];
UIAlertController *actionSheet =
[UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *unblockAction =
[UIAlertAction actionWithTitle:NSLocalizedString(
@"BLOCK_LIST_UNBLOCK_BUTTON", @"Button label for the 'unblock' button")
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"unblock")
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *_Nonnull action) {
[BlockListUIUtils unblockPhoneNumbers:phoneNumbers
displayName:displayName
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:^(UIAlertAction *ignore) {
if (completionBlock) {
completionBlock(NO);
}
}];
}];
[actionSheet addAction:unblockAction];
UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:CommonStrings.cancelButton
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"dismiss")
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
if (completionBlock) {
completionBlock(YES);
}
}];
[actionSheet addAction:dismissAction];
[fromViewController presentAlert:actionSheet];
}
+ (void)unblockPhoneNumbers:(NSArray<NSString *> *)phoneNumbers
displayName:(NSString *)displayName
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(BlockAlertCompletionBlock)completionBlock
{
OWSAssertDebug(phoneNumbers.count > 0);
OWSAssertDebug(displayName.length > 0);
OWSAssertDebug(fromViewController);
OWSAssertDebug(blockingManager);
for (NSString *phoneNumber in phoneNumbers) {
OWSAssertDebug(phoneNumber.length > 0);
[blockingManager removeBlockedPhoneNumber:phoneNumber];
}
NSString *titleFormat = NSLocalizedString(@"BLOCK_LIST_VIEW_UNBLOCKED_ALERT_TITLE_FORMAT",
@"Alert title after unblocking a group or 1:1 chat. Embeds the {{conversation title}}.");
NSString *title = [NSString stringWithFormat:titleFormat, [self formatDisplayNameForAlertMessage:displayName]];
[self showOkAlertWithTitle:title message:nil fromViewController:fromViewController completionBlock:completionBlock];
}
+ (void)showUnblockGroupActionSheet:(TSGroupModel *)groupModel
displayName:(NSString *)displayName
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
{
OWSAssertDebug(displayName.length > 0);
OWSAssertDebug(fromViewController);
OWSAssertDebug(blockingManager);
NSString *title =
[NSString stringWithFormat:NSLocalizedString(@"BLOCK_LIST_UNBLOCK_GROUP_TITLE",
@"Action sheet title when confirming you want to unblock a group.")];
NSString *message = NSLocalizedString(
@"BLOCK_LIST_UNBLOCK_GROUP_BODY", @"Action sheet body when confirming you want to unblock a group");
UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:title
message:message
preferredStyle:UIAlertControllerStyleActionSheet];
UIAlertAction *unblockAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"BLOCK_LIST_UNBLOCK_BUTTON",
@"Button label for the 'unblock' button")
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"unblock")
style:UIAlertActionStyleDestructive
handler:^(UIAlertAction *_Nonnull action) {
[BlockListUIUtils unblockGroup:groupModel
displayName:displayName
fromViewController:fromViewController
blockingManager:blockingManager
completionBlock:^(UIAlertAction *ignore) {
if (completionBlock) {
completionBlock(NO);
}
}];
}];
[actionSheet addAction:unblockAction];
UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:CommonStrings.cancelButton
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"dismiss")
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
if (completionBlock) {
completionBlock(YES);
}
}];
[actionSheet addAction:dismissAction];
[fromViewController presentAlert:actionSheet];
}
+ (void)unblockGroup:(TSGroupModel *)groupModel
displayName:(NSString *)displayName
fromViewController:(UIViewController *)fromViewController
blockingManager:(OWSBlockingManager *)blockingManager
completionBlock:(BlockAlertCompletionBlock)completionBlock
{
OWSAssertDebug(displayName.length > 0);
OWSAssertDebug(fromViewController);
OWSAssertDebug(blockingManager);
[blockingManager removeBlockedGroupId:groupModel.groupId];
NSString *titleFormat = NSLocalizedString(@"BLOCK_LIST_VIEW_UNBLOCKED_ALERT_TITLE_FORMAT",
@"Alert title after unblocking a group or 1:1 chat. Embeds the {{conversation title}}.");
NSString *title = [NSString stringWithFormat:titleFormat, [self formatDisplayNameForAlertMessage:displayName]];
NSString *message
= NSLocalizedString(@"BLOCK_LIST_VIEW_UNBLOCKED_GROUP_ALERT_BODY", @"Alert body after unblocking a group.");
[self showOkAlertWithTitle:title
message:message
fromViewController:fromViewController
completionBlock:completionBlock];
}
#pragma mark - UI
+ (void)showOkAlertWithTitle:(NSString *)title
message:(nullable NSString *)message
fromViewController:(UIViewController *)fromViewController
completionBlock:(BlockAlertCompletionBlock)completionBlock
{
OWSAssertDebug(title.length > 0);
OWSAssertDebug(fromViewController);
UIAlertController *alert =
[UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_OK", nil)
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"ok")
style:UIAlertActionStyleDefault
handler:completionBlock];
[alert addAction:okAction];
[fromViewController presentAlert:alert];
}
+ (NSString *)formatDisplayNameForAlertTitle:(NSString *)displayName
{
return [self formatDisplayName:displayName withMaxLength:20];
}
+ (NSString *)formatDisplayNameForAlertMessage:(NSString *)displayName
{
return [self formatDisplayName:displayName withMaxLength:127];
}
+ (NSString *)formatDisplayName:(NSString *)displayName withMaxLength:(NSUInteger)maxLength
{
OWSAssertDebug(displayName.length > 0);
if (displayName.length > maxLength) {
return [[displayName substringToIndex:maxLength] stringByAppendingString:@"…"];
}
return displayName;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,144 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import SessionMessagingKit
@objc public class BlockListUIUtils: NSObject {
// MARK: - Block
/// This method shows an alert to unblock a contact in a ContactThread and will update the `isBlocked` flag of the contact if the user decides to continue
///
/// **Note:** Make sure to force a config sync in the `completionBlock` if the blocked state was successfully changed
@objc public static func showBlockThreadActionSheet(_ thread: TSContactThread, from viewController: UIViewController, completionBlock: ((Bool) -> ())? = nil) {
let userPublicKey = getUserHexEncodedPublicKey()
guard thread.contactSessionID() != userPublicKey, let contact: Contact = Storage.shared.getContact(with: thread.contactSessionID()) else {
completionBlock?(false)
return
}
let displayName: String = (contact.displayName(for: .regular) ?? thread.contactSessionID())
let actionSheet: UIAlertController = UIAlertController(
title: String(
format: "BLOCK_LIST_BLOCK_USER_TITLE_FORMAT".localized(),
self.formatForAlertTitle(displayName: displayName)
),
message: "BLOCK_USER_BEHAVIOR_EXPLANATION".localized(),
preferredStyle: .actionSheet
)
actionSheet.addAction(UIAlertAction(
title: "BLOCK_LIST_BLOCK_BUTTON".localized(),
accessibilityIdentifier: "\(type(of: self).self).block",
style: .destructive,
handler: { _ in
Storage.write(
with: { transaction in
contact.isBlocked = true
Storage.shared.setContact(contact, using: transaction)
},
completion: {
self.showOkAlert(
title: "BLOCK_LIST_VIEW_BLOCKED_ALERT_TITLE".localized(),
message: String(
format: "BLOCK_LIST_VIEW_BLOCKED_ALERT_MESSAGE_FORMAT".localized(),
self.formatForAlertMessage(displayName: displayName)
),
from: viewController,
completionBlock: { _ in completionBlock?(true) }
)
})
}
))
actionSheet.addAction(UIAlertAction(
title: CommonStrings.cancelButton,
accessibilityIdentifier: "\(type(of: self).self).dismiss",
style: .cancel,
handler: { _ in completionBlock?(false) }
))
viewController.presentAlert(actionSheet)
}
// MARK: - Unblock
/// This method shows an alert to unblock a contact in a ContactThread and will update the `isBlocked` flag of the contact if the user decides to continue
///
/// **Note:** Make sure to force a config sync in the `completionBlock` if the blocked state was successfully changed
@objc public static func showUnblockThreadActionSheet(_ thread: TSContactThread, from viewController: UIViewController, completionBlock: ((Bool) -> ())? = nil) {
guard let contact: Contact = Storage.shared.getContact(with: thread.contactSessionID()) else {
completionBlock?(true)
return
}
let displayName: String = (contact.displayName(for: .regular) ?? thread.contactSessionID())
let actionSheet: UIAlertController = UIAlertController(
title: String(
format: "BLOCK_LIST_UNBLOCK_TITLE_FORMAT".localized(),
self.formatForAlertTitle(displayName: displayName)
),
message: nil,
preferredStyle: .actionSheet
)
actionSheet.addAction(UIAlertAction(
title: "BLOCK_LIST_UNBLOCK_BUTTON".localized(),
accessibilityIdentifier: "\(type(of: self).self).unblock",
style: .destructive,
handler: { _ in
Storage.write(
with: { transaction in
contact.isBlocked = false
Storage.shared.setContact(contact, using: transaction)
},
completion: {
self.showOkAlert(
title: String(
format: "BLOCK_LIST_VIEW_UNBLOCKED_ALERT_TITLE_FORMAT".localized(),
self.formatForAlertMessage(displayName: displayName)
),
message: nil,
from: viewController,
completionBlock: { _ in completionBlock?(false) }
)
})
}
))
actionSheet.addAction(UIAlertAction(
title: CommonStrings.cancelButton,
accessibilityIdentifier: "\(type(of: self).self).dismiss",
style: .cancel,
handler: { _ in completionBlock?(true) }
))
viewController.presentAlert(actionSheet)
}
// MARK: - UI
@objc public static func showOkAlert(title: String, message: String?, from viewController: UIViewController, completionBlock: @escaping (UIAlertAction) -> ()) {
let alertController: UIAlertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
alertController.addAction(UIAlertAction(
title: "BUTTON_OK".localized(),
accessibilityIdentifier: "\(type(of: self).self).ok",
style: .default,
handler: completionBlock
))
viewController.presentAlert(alertController)
}
@objc public static func formatForAlertTitle(displayName: String) -> String {
return format(displayName: displayName, maxLength: 20)
}
@objc public static func formatForAlertMessage(displayName: String) -> String {
return format(displayName: displayName, maxLength: 127)
}
@objc public static func format(displayName: String, maxLength: Int) -> String {
guard displayName.count <= maxLength else {
return "\(displayName.substring(to: maxLength))"
}
return displayName
}
}

View File

@ -1,4 +1,5 @@
import PromiseKit
import SessionUtilitiesKit
extension MessageSender {
@ -104,4 +105,39 @@ extension MessageSender {
}
return promise
}
public static func syncConfiguration(forceSyncNow: Bool = true) -> Promise<Void> {
let (promise, seal) = Promise<Void>.pending()
let destination: Message.Destination = Message.Destination.contact(publicKey: getUserHexEncodedPublicKey())
// Note: SQLite only supports a single write thread so we can be sure this will retrieve the most up-to-date data
Storage.writeSync { transaction in
guard Storage.shared.getUser(using: transaction)?.name != nil, let configurationMessage = ConfigurationMessage.getCurrent(with: transaction) else {
seal.fulfill(())
return
}
if forceSyncNow {
MessageSender.send(configurationMessage, to: destination, using: transaction).done {
seal.fulfill(())
}.catch { _ in
seal.fulfill(()) // Fulfill even if this failed; the configuration in the swarm should be at most 2 days old
}.retainUntilComplete()
}
else {
let job = MessageSendJob(message: configurationMessage, destination: destination)
JobQueue.shared.add(job, using: transaction)
seal.fulfill(())
}
}
return promise
}
}
extension MessageSender {
@objc(forceSyncConfigurationNow)
public static func objc_forceSyncConfigurationNow() {
return syncConfiguration(forceSyncNow: true).retainUntilComplete()
}
}

View File

@ -9,7 +9,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[];
#import <SignalUtilitiesKit/AppSetup.h>
#import <SignalUtilitiesKit/AppVersion.h>
#import <SignalUtilitiesKit/BlockListUIUtils.h>
#import <SignalUtilitiesKit/ByteParser.h>
#import <SignalUtilitiesKit/ContactCellView.h>
#import <SignalUtilitiesKit/ContactTableViewCell.h>
@ -42,8 +41,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[];
#import <SignalUtilitiesKit/OWSUnreadIndicator.h>
#import <SignalUtilitiesKit/OWSViewController.h>
#import <SignalUtilitiesKit/ScreenLockViewController.h>
#import <SignalUtilitiesKit/SelectRecipientViewController.h>
#import <SignalUtilitiesKit/SharingThreadPickerViewController.h>
#import <SignalUtilitiesKit/SignalAccount.h>
#import <SignalUtilitiesKit/SSKAsserts.h>
#import <SignalUtilitiesKit/Theme.h>

View File

@ -1,47 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <SignalUtilitiesKit/OWSViewController.h>
NS_ASSUME_NONNULL_BEGIN
@class SignalAccount;
@protocol SelectRecipientViewControllerDelegate <NSObject>
- (NSString *)phoneNumberSectionTitle;
- (NSString *)phoneNumberButtonText;
- (NSString *)contactsSectionTitle;
- (void)phoneNumberWasSelected:(NSString *)phoneNumber;
- (BOOL)canSignalAccountBeSelected:(SignalAccount *)signalAccount;
- (void)signalAccountWasSelected:(SignalAccount *)signalAccount;
- (nullable NSString *)accessoryMessageForSignalAccount:(SignalAccount *)signalAccount;
- (BOOL)shouldHideLocalNumber;
- (BOOL)shouldHideContacts;
- (BOOL)shouldValidatePhoneNumbers;
@end
#pragma mark -
@class ContactsViewHelper;
@interface SelectRecipientViewController : OWSViewController
@property (nonatomic, weak) id<SelectRecipientViewControllerDelegate> delegate;
@property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper;
@property (nonatomic) BOOL isPresentedInNavigationController;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,332 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import <SignalUtilitiesKit/SelectRecipientViewController.h>
#import <SignalUtilitiesKit/ContactTableViewCell.h>
#import <SignalUtilitiesKit/OWSTableViewController.h>
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
#import <SignalUtilitiesKit/UIFont+OWS.h>
#import <SignalUtilitiesKit/UIUtil.h>
#import <SessionUtilitiesKit/UIView+OWS.h>
#import <SessionUtilitiesKit/AppContext.h>
#import <SignalUtilitiesKit/SignalAccount.h>
#import <SessionMessagingKit/TSAccountManager.h>
#import <SignalUtilitiesKit/OWSTextField.h>
NS_ASSUME_NONNULL_BEGIN
NSString *const kSelectRecipientViewControllerCellIdentifier = @"kSelectRecipientViewControllerCellIdentifier";
#pragma mark -
@interface SelectRecipientViewController () </*CountryCodeViewControllerDelegate,*/
OWSTableViewControllerDelegate,
UITextFieldDelegate>
@property (nonatomic) UIButton *countryCodeButton;
@property (nonatomic) UITextField *phoneNumberTextField;
@property (nonatomic) OWSFlatButton *phoneNumberButton;
@property (nonatomic) UILabel *examplePhoneNumberLabel;
@property (nonatomic, readonly) OWSTableViewController *tableViewController;
@property (nonatomic) NSString *callingCode;
@end
#pragma mark -
@implementation SelectRecipientViewController
- (void)loadView
{
[super loadView];
self.view.backgroundColor = [Theme backgroundColor];
[self createViews];
if (self.delegate.shouldHideContacts) {
self.tableViewController.tableView.scrollEnabled = NO;
}
}
- (void)viewDidLoad
{
OWSAssertDebug(self.tableViewController);
[super viewDidLoad];
}
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self.tableViewController viewDidAppear:animated];
if ([self.delegate shouldHideContacts]) {
[self.phoneNumberTextField becomeFirstResponder];
}
}
- (void)createViews
{
OWSAssertDebug(self.delegate);
_tableViewController = [OWSTableViewController new];
_tableViewController.delegate = self;
[self.view addSubview:self.tableViewController.view];
[self.tableViewController.view autoPinEdgeToSuperviewSafeArea:ALEdgeLeading];
[self.tableViewController.view autoPinEdgeToSuperviewSafeArea:ALEdgeTrailing];
[_tableViewController.view autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:self.view withOffset:0];
[_tableViewController.view autoPinEdgeToSuperviewEdge:ALEdgeBottom];
self.tableViewController.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableViewController.tableView.estimatedRowHeight = 60;
_tableViewController.view.backgroundColor = [Theme backgroundColor];
[self updateTableContents];
}
- (UILabel *)countryCodeLabel
{
UILabel *countryCodeLabel = [UILabel new];
countryCodeLabel.font = [UIFont ows_mediumFontWithSize:18.f];
countryCodeLabel.textColor = [Theme primaryColor];
countryCodeLabel.text
= NSLocalizedString(@"REGISTRATION_DEFAULT_COUNTRY_NAME", @"Label for the country code field");
return countryCodeLabel;
}
- (UIButton *)countryCodeButton
{
if (!_countryCodeButton) {
_countryCodeButton = [UIButton buttonWithType:UIButtonTypeCustom];
_countryCodeButton.titleLabel.font = [UIFont ows_mediumFontWithSize:18.f];
_countryCodeButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;
[_countryCodeButton setTitleColor:[UIColor ows_materialBlueColor] forState:UIControlStateNormal];
[_countryCodeButton addTarget:self
action:@selector(showCountryCodeView:)
forControlEvents:UIControlEventTouchUpInside];
SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, _countryCodeButton);
}
return _countryCodeButton;
}
- (UILabel *)phoneNumberLabel
{
UILabel *phoneNumberLabel = [UILabel new];
phoneNumberLabel.font = [UIFont ows_mediumFontWithSize:18.f];
phoneNumberLabel.textColor = [Theme primaryColor];
phoneNumberLabel.text
= NSLocalizedString(@"REGISTRATION_PHONENUMBER_BUTTON", @"Label for the phone number textfield");
return phoneNumberLabel;
}
- (UIFont *)examplePhoneNumberFont
{
return [UIFont ows_regularFontWithSize:16.f];
}
- (UILabel *)examplePhoneNumberLabel
{
if (!_examplePhoneNumberLabel) {
_examplePhoneNumberLabel = [UILabel new];
_examplePhoneNumberLabel.font = [self examplePhoneNumberFont];
_examplePhoneNumberLabel.textColor = [Theme secondaryColor];
SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, _examplePhoneNumberLabel);
}
return _examplePhoneNumberLabel;
}
- (UITextField *)phoneNumberTextField
{
if (!_phoneNumberTextField) {
_phoneNumberTextField = [OWSTextField new];
_phoneNumberTextField.font = [UIFont ows_mediumFontWithSize:18.f];
_phoneNumberTextField.textAlignment = _phoneNumberTextField.textAlignmentUnnatural;
_phoneNumberTextField.textColor = [UIColor ows_materialBlueColor];
_phoneNumberTextField.placeholder = NSLocalizedString(
@"REGISTRATION_ENTERNUMBER_DEFAULT_TEXT", @"Placeholder text for the phone number textfield");
_phoneNumberTextField.keyboardType = UIKeyboardTypeNumberPad;
_phoneNumberTextField.delegate = self;
[_phoneNumberTextField addTarget:self
action:@selector(textFieldDidChange:)
forControlEvents:UIControlEventEditingChanged];
SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, _phoneNumberTextField);
}
return _phoneNumberTextField;
}
- (OWSFlatButton *)phoneNumberButton
{
if (!_phoneNumberButton) {
const CGFloat kButtonHeight = 40;
OWSFlatButton *button = [OWSFlatButton buttonWithTitle:[self.delegate phoneNumberButtonText]
font:[OWSFlatButton fontForHeight:kButtonHeight]
titleColor:[UIColor whiteColor]
backgroundColor:[UIColor ows_materialBlueColor]
target:self
selector:@selector(phoneNumberButtonPressed)];
_phoneNumberButton = button;
[button autoSetDimension:ALDimensionWidth toSize:140];
[button autoSetDimension:ALDimensionHeight toSize:kButtonHeight];
SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, _phoneNumberButton);
}
return _phoneNumberButton;
}
- (UIView *)createRowWithHeight:(CGFloat)height
previousRow:(nullable UIView *)previousRow
superview:(nullable UIView *)superview
{
UIView *row = [UIView containerView];
[superview addSubview:row];
[row autoPinLeadingAndTrailingToSuperviewMargin];
if (previousRow) {
[row autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:previousRow withOffset:0];
} else {
[row autoPinEdgeToSuperviewEdge:ALEdgeTop];
}
[row autoSetDimension:ALDimensionHeight toSize:height];
return row;
}
#pragma mark - UITextFieldDelegate
- (BOOL)textField:(UITextField *)textField
shouldChangeCharactersInRange:(NSRange)range
replacementString:(NSString *)insertionText
{
return NO; // inform our caller that we took care of performing the change
}
- (BOOL)textFieldShouldReturn:(UITextField *)textField
{
[textField resignFirstResponder];
return NO;
}
#pragma mark - Table Contents
- (void)updateTableContents
{
OWSTableContents *contents = [OWSTableContents new];
__weak SelectRecipientViewController *weakSelf = self;
ContactsViewHelper *helper = self.contactsViewHelper;
OWSTableSection *phoneNumberSection = [OWSTableSection new];
phoneNumberSection.headerTitle = [self.delegate phoneNumberSectionTitle];
const CGFloat kCountryRowHeight = 50;
const CGFloat kPhoneNumberRowHeight = 50;
const CGFloat examplePhoneNumberRowHeight = self.examplePhoneNumberFont.lineHeight + 3.f;
const CGFloat kButtonRowHeight = 60;
[phoneNumberSection addItem:[OWSTableItem itemWithCustomCellBlock:^{
SelectRecipientViewController *strongSelf = weakSelf;
OWSCAssertDebug(strongSelf);
UITableViewCell *cell = [OWSTableItem newCell];
cell.preservesSuperviewLayoutMargins = YES;
cell.contentView.preservesSuperviewLayoutMargins = YES;
// Country Row
UIView *countryRow =
[strongSelf createRowWithHeight:kCountryRowHeight previousRow:nil superview:cell.contentView];
[countryRow addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:strongSelf
action:@selector(countryRowTouched:)]];
UILabel *countryCodeLabel = strongSelf.countryCodeLabel;
[countryRow addSubview:countryCodeLabel];
[countryCodeLabel autoPinLeadingToSuperviewMargin];
[countryCodeLabel autoVCenterInSuperview];
[countryRow addSubview:strongSelf.countryCodeButton];
[strongSelf.countryCodeButton autoPinTrailingToSuperviewMargin];
[strongSelf.countryCodeButton autoVCenterInSuperview];
// Phone Number Row
UIView *phoneNumberRow =
[strongSelf createRowWithHeight:kPhoneNumberRowHeight previousRow:countryRow superview:cell.contentView];
[phoneNumberRow
addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:strongSelf
action:@selector(phoneNumberRowTouched:)]];
UILabel *phoneNumberLabel = strongSelf.phoneNumberLabel;
[phoneNumberRow addSubview:phoneNumberLabel];
[phoneNumberLabel autoPinLeadingToSuperviewMargin];
[phoneNumberLabel autoVCenterInSuperview];
[phoneNumberRow addSubview:strongSelf.phoneNumberTextField];
[strongSelf.phoneNumberTextField autoPinLeadingToTrailingEdgeOfView:phoneNumberLabel offset:10.f];
[strongSelf.phoneNumberTextField autoPinTrailingToSuperviewMargin];
[strongSelf.phoneNumberTextField autoVCenterInSuperview];
// Example row.
UIView *examplePhoneNumberRow = [strongSelf createRowWithHeight:examplePhoneNumberRowHeight
previousRow:phoneNumberRow
superview:cell.contentView];
[examplePhoneNumberRow addSubview:strongSelf.examplePhoneNumberLabel];
[strongSelf.examplePhoneNumberLabel autoVCenterInSuperview];
[strongSelf.examplePhoneNumberLabel autoPinTrailingToSuperviewMargin];
// Phone Number Button Row
UIView *buttonRow = [strongSelf createRowWithHeight:kButtonRowHeight
previousRow:examplePhoneNumberRow
superview:cell.contentView];
[buttonRow addSubview:strongSelf.phoneNumberButton];
[strongSelf.phoneNumberButton autoVCenterInSuperview];
[strongSelf.phoneNumberButton autoPinTrailingToSuperviewMargin];
[buttonRow autoPinEdgeToSuperviewEdge:ALEdgeBottom];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
return cell;
}
customRowHeight:kCountryRowHeight + kPhoneNumberRowHeight
+ examplePhoneNumberRowHeight + kButtonRowHeight
actionBlock:nil]];
[contents addSection:phoneNumberSection];
self.tableViewController.contents = contents;
}
- (void)phoneNumberRowTouched:(UIGestureRecognizer *)sender
{
if (sender.state == UIGestureRecognizerStateRecognized) {
[self.phoneNumberTextField becomeFirstResponder];
}
}
- (void)countryRowTouched:(UIGestureRecognizer *)sender
{
}
#pragma mark - OWSTableViewControllerDelegate
- (void)tableViewWillBeginDragging
{
[self.phoneNumberTextField resignFirstResponder];
}
#pragma mark - ContactsViewHelperDelegate
- (void)contactsViewHelperDidUpdateContacts
{
[self updateTableContents];
}
- (BOOL)shouldHideLocalNumber
{
return [self.delegate shouldHideLocalNumber];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -1,31 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <SignalUtilitiesKit/OWSViewController.h>
@class TSThread;
NS_ASSUME_NONNULL_BEGIN
@protocol SelectThreadViewControllerDelegate <NSObject>
- (void)threadWasSelected:(TSThread *)thread;
- (BOOL)canSelectBlockedContact;
- (nullable UIView *)createHeaderWithSearchBar:(UISearchBar *)searchBar;
@end
#pragma mark -
// A base class for views used to pick a single signal user, either by
// entering a phone number or picking from your contacts.
@interface SelectThreadViewController : OWSViewController
@property (nonatomic, weak) id<SelectThreadViewControllerDelegate> selectThreadViewDelegate;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,315 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "SelectThreadViewController.h"
#import "ContactTableViewCell.h"
#import "OWSSearchBar.h"
#import "OWSTableViewController.h"
#import "ThreadViewHelper.h"
#import "UIColor+OWS.h"
#import "UIFont+OWS.h"
#import "UIView+OWS.h"
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
#import <SessionUtilitiesKit/NSString+SSK.h>
#import <SignalUtilitiesKit/SignalAccount.h>
#import <SessionMessagingKit/TSAccountManager.h>
#import <SessionMessagingKit/TSContactThread.h>
#import <SessionMessagingKit/TSThread.h>
#import <YapDatabase/YapDatabase.h>
#import <SessionUIKit/SessionUIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface SelectThreadViewController () <OWSTableViewControllerDelegate,
ThreadViewHelperDelegate,
UISearchBarDelegate>
@property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper;
@property (nonatomic, readonly) FullTextSearcher *fullTextSearcher;
@property (nonatomic, readonly) ThreadViewHelper *threadViewHelper;
@property (nonatomic, readonly) YapDatabaseConnection *uiDatabaseConnection;
@property (nonatomic, readonly) OWSTableViewController *tableViewController;
@property (nonatomic, readonly) UISearchBar *searchBar;
@end
#pragma mark -
@implementation SelectThreadViewController
- (void)loadView
{
[super loadView];
UIBarButtonItem *closeButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"X"] style:UIBarButtonItemStylePlain target:self action:@selector(dismissPressed:)];
closeButton.tintColor = LKColors.text;
self.navigationItem.leftBarButtonItem = closeButton;
_fullTextSearcher = FullTextSearcher.shared;
_threadViewHelper = [ThreadViewHelper new];
_threadViewHelper.delegate = self;
_uiDatabaseConnection = [[OWSPrimaryStorage sharedManager] newDatabaseConnection];
#ifdef DEBUG
_uiDatabaseConnection.permittedTransactions = YDB_AnyReadTransaction;
#endif
[_uiDatabaseConnection beginLongLivedReadTransaction];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModified:)
name:YapDatabaseModifiedNotification
object:OWSPrimaryStorage.sharedManager.dbNotificationObject];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(yapDatabaseModifiedExternally:)
name:YapDatabaseModifiedExternallyNotification
object:nil];
[self createViews];
// Loki: Set gradient background
self.tableViewController.tableView.backgroundColor = UIColor.clearColor;
self.tableViewController.view.backgroundColor = UIColor.clearColor;
CAGradientLayer *layer = [CAGradientLayer new];
layer.frame = UIScreen.mainScreen.bounds;
UIColor *gradientStartColor = LKAppModeUtilities.isLightMode ? [UIColor colorWithRGBHex:0xFCFCFC] : [UIColor colorWithRGBHex:0x171717];
UIColor *gradientEndColor = LKAppModeUtilities.isLightMode ? [UIColor colorWithRGBHex:0xFFFFFF] : [UIColor colorWithRGBHex:0x121212];
layer.colors = @[ (id)gradientStartColor.CGColor, (id)gradientEndColor.CGColor ];
[self.tableViewController.view.layer insertSublayer:layer atIndex:0];
// Loki: Set navigation bar background color
UINavigationBar *navigationBar = self.navigationController.navigationBar;
[navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
navigationBar.shadowImage = [UIImage new];
[navigationBar setTranslucent:NO];
navigationBar.barTintColor = LKColors.navigationBarBackground;
[self updateTableContents];
}
- (void)createViews
{
OWSAssertDebug(self.selectThreadViewDelegate);
// Table
_tableViewController = [OWSTableViewController new];
_tableViewController.delegate = self;
[self.view addSubview:self.tableViewController.view];
[self.tableViewController.view autoPinEdgeToSuperviewSafeArea:ALEdgeLeading];
[self.tableViewController.view autoPinEdgeToSuperviewSafeArea:ALEdgeTrailing];
[_tableViewController.view autoPinEdgeToSuperviewEdge:ALEdgeTop];
[_tableViewController.view autoPinEdgeToSuperviewEdge:ALEdgeBottom];
self.tableViewController.tableView.rowHeight = UITableViewAutomaticDimension;
self.tableViewController.tableView.estimatedRowHeight = 60;
BOOL isIphone6OrSmaller = (UIScreen.mainScreen.bounds.size.height - 667) < 1;
CGFloat bottomInset = isIphone6OrSmaller ? LKValues.mediumSpacing : 34.0f;
self.tableViewController.tableView.contentInset = UIEdgeInsetsMake(0, 0, bottomInset, 0);
}
- (void)yapDatabaseModifiedExternally:(NSNotification *)notification
{
OWSAssertIsOnMainThread();
OWSLogVerbose(@"");
[self.uiDatabaseConnection beginLongLivedReadTransaction];
[self updateTableContents];
}
- (void)yapDatabaseModified:(NSNotification *)notification
{
OWSAssertIsOnMainThread();
[self.uiDatabaseConnection beginLongLivedReadTransaction];
[self updateTableContents];
}
#pragma mark - UISearchBarDelegate
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
[self updateTableContents];
}
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
{
[self updateTableContents];
}
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
[self updateTableContents];
}
- (void)searchBarResultsListButtonClicked:(UISearchBar *)searchBar
{
[self updateTableContents];
}
- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope
{
[self updateTableContents];
}
#pragma mark - Table Contents
- (void)updateTableContents
{
__weak SelectThreadViewController *weakSelf = self;
ContactsViewHelper *helper = self.contactsViewHelper;
OWSTableContents *contents = [OWSTableContents new];
// Existing threads are listed first, ordered by most recently active
OWSTableSection *recentChatsSection = [OWSTableSection new];
recentChatsSection.headerTitle = NSLocalizedString(@"SELECT_THREAD_TABLE_RECENT_CHATS_TITLE", @"");
for (TSThread *thread in self.threadViewHelper.threads) {
[recentChatsSection
addItem:[OWSTableItem
itemWithCustomCellBlock:^{
SelectThreadViewController *strongSelf = weakSelf;
OWSCAssertDebug(strongSelf);
// To be consistent with the threads (above), we use ContactTableViewCell
// instead of HomeViewCell to present contacts and threads.
ContactTableViewCell *cell = [ContactTableViewCell new];
BOOL isBlocked = [SSKEnvironment.shared.blockingManager isThreadBlocked:thread];
if (isBlocked) {
cell.accessoryMessage = NSLocalizedString(
@"CONTACT_CELL_IS_BLOCKED", @"An indicator that a contact has been blocked.");
}
[cell configureWithThread:thread];
if (!cell.hasAccessoryText) {
// Don't add a disappearing messages indicator if we've already added a "blocked" label.
__block OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration;
[self.uiDatabaseConnection
readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
disappearingMessagesConfiguration = [OWSDisappearingMessagesConfiguration
fetchObjectWithUniqueID:thread.uniqueId
transaction:transaction];
}];
if (disappearingMessagesConfiguration && disappearingMessagesConfiguration.isEnabled) {
DisappearingTimerConfigurationView *disappearingTimerConfigurationView =
[[DisappearingTimerConfigurationView alloc]
initWithDurationSeconds:disappearingMessagesConfiguration.durationSeconds];
disappearingTimerConfigurationView.tintColor = LKColors.text;
[disappearingTimerConfigurationView autoSetDimensionsToSize:CGSizeMake(44, 44)];
[cell ows_setAccessoryView:disappearingTimerConfigurationView];
}
}
return cell;
}
customRowHeight:UITableViewAutomaticDimension
actionBlock:^{
typeof(self) strongSelf = weakSelf;
if (!strongSelf) {
return;
}
BOOL isBlocked = [SSKEnvironment.shared.blockingManager isThreadBlocked:thread];
if (isBlocked && ![strongSelf.selectThreadViewDelegate canSelectBlockedContact]) {
[BlockListUIUtils
showUnblockThreadActionSheet:thread
fromViewController:strongSelf
blockingManager:SSKEnvironment.shared.blockingManager
completionBlock:^(BOOL isStillBlocked) {
if (!isStillBlocked) {
[strongSelf.selectThreadViewDelegate threadWasSelected:thread];
}
}];
return;
}
[strongSelf.selectThreadViewDelegate threadWasSelected:thread];
}]];
}
if (recentChatsSection.itemCount > 0) {
[contents addSection:recentChatsSection];
}
if (recentChatsSection.itemCount < 1) {
OWSTableSection *emptySection = [OWSTableSection new];
[emptySection
addItem:[OWSTableItem
softCenterLabelItemWithText:NSLocalizedString(@"SETTINGS_BLOCK_LIST_NO_CONTACTS",
@"A label that indicates the user has no Signal contacts.")]];
[contents addSection:emptySection];
}
self.tableViewController.contents = contents;
}
- (void)signalAccountWasSelected:(SignalAccount *)signalAccount
{
OWSAssertDebug(signalAccount);
OWSAssertDebug(self.selectThreadViewDelegate);
if ([SSKEnvironment.shared.blockingManager isRecipientIdBlocked:signalAccount.recipientId]
&& ![self.selectThreadViewDelegate canSelectBlockedContact]) {
__weak SelectThreadViewController *weakSelf = self;
[BlockListUIUtils showUnblockSignalAccountActionSheet:signalAccount
fromViewController:self
blockingManager:SSKEnvironment.shared.blockingManager
completionBlock:^(BOOL isBlocked) {
if (!isBlocked) {
[weakSelf signalAccountWasSelected:signalAccount];
}
}];
return;
}
__block TSThread *thread = nil;
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
thread = [TSContactThread getOrCreateThreadWithContactSessionID:signalAccount.recipientId transaction:transaction];
}];
OWSAssertDebug(thread);
[self.selectThreadViewDelegate threadWasSelected:thread];
}
#pragma mark - Events
- (void)dismissPressed:(id)sender
{
[self.searchBar resignFirstResponder];
[self dismissViewControllerAnimated:YES completion:nil];
}
#pragma mark - OWSTableViewControllerDelegate
- (void)tableViewWillBeginDragging
{
[self.searchBar resignFirstResponder];
}
#pragma mark - ThreadViewHelperDelegate
- (void)threadListDidChange
{
[self updateTableContents];
}
#pragma mark - ContactsViewHelperDelegate
- (void)contactsViewHelperDidUpdateContacts
{
[self updateTableContents];
}
- (BOOL)shouldHideLocalNumber
{
return NO;
}
@end
NS_ASSUME_NONNULL_END

View File

@ -1,21 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <SignalUtilitiesKit/SelectThreadViewController.h>
NS_ASSUME_NONNULL_BEGIN
@class SignalAttachment;
@protocol ShareViewDelegate;
@interface SharingThreadPickerViewController : SelectThreadViewController
@property (nonatomic) NSArray<SignalAttachment *> *attachments;
- (instancetype)initWithShareViewDelegate:(id<ShareViewDelegate>)shareViewDelegate;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,458 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "SharingThreadPickerViewController.h"
#import "SignalApp.h"
#import "UIColor+OWS.h"
#import "UIFont+OWS.h"
#import "UIView+OWS.h"
#import <PromiseKit/PromiseKit.h>
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
#import <SessionUtilitiesKit/NSString+SSK.h>
#import <SignalUtilitiesKit/OWSError.h>
#import <SessionMessagingKit/SessionMessagingKit.h>
#import <SessionUIKit/SessionUIKit.h>
NS_ASSUME_NONNULL_BEGIN
typedef void (^SendCompletionBlock)(NSError *_Nullable, TSOutgoingMessage *);
typedef void (^SendMessageBlock)(SendCompletionBlock completion);
@interface SharingThreadPickerViewController () <SelectThreadViewControllerDelegate,
AttachmentApprovalViewControllerDelegate,
MessageApprovalViewControllerDelegate>
@property (nonatomic, readonly) OWSMessageSender *messageSender;
@property (nonatomic) TSThread *thread;
@property (nonatomic, readonly, weak) id<ShareViewDelegate> shareViewDelegate;
@property (atomic, nullable) TSOutgoingMessage *outgoingMessage;
@end
#pragma mark -
@implementation SharingThreadPickerViewController
- (instancetype)initWithShareViewDelegate:(id<ShareViewDelegate>)shareViewDelegate
{
self = [super init];
if (!self) {
return self;
}
_shareViewDelegate = shareViewDelegate;
self.selectThreadViewDelegate = self;
return self;
}
#pragma mark - Dependencies
- (YapDatabaseConnection *)dbReadWriteConnection
{
return OWSPrimaryStorage.sharedManager.dbReadWriteConnection;
}
- (YapDatabaseConnection *)dbReadConnection
{
return OWSPrimaryStorage.sharedManager.dbReadConnection;
}
#pragma mark - UIViewController overrides
- (void)loadView
{
[super loadView];
self.title = NSLocalizedString(@"SHARE_EXTENSION_VIEW_TITLE", @"Title for the 'share extension' view.");
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Loki: Customize title
UILabel *titleLabel = [UILabel new];
titleLabel.text = NSLocalizedString(@"Share", @"");
titleLabel.textColor = LKColors.text;
titleLabel.font = [UIFont boldSystemFontOfSize:25];
self.navigationItem.titleView = titleLabel;
}
- (BOOL)canSelectBlockedContact
{
return NO;
}
- (nullable UIView *)createHeaderWithSearchBar:(UISearchBar *)searchBar
{
OWSAssertDebug(searchBar);
const CGFloat contentVMargin = 0;
UIView *header = [UIView new];
header.backgroundColor = LKColors.navigationBarBackground;
UIButton *cancelShareButton = [UIButton buttonWithType:UIButtonTypeSystem];
[header addSubview:cancelShareButton];
[cancelShareButton setTitle:[CommonStrings cancelButton] forState:UIControlStateNormal];
cancelShareButton.userInteractionEnabled = YES;
[cancelShareButton autoPinEdgeToSuperviewMargin:ALEdgeLeading];
[cancelShareButton autoPinEdgeToSuperviewMargin:ALEdgeBottom];
[cancelShareButton setCompressionResistanceHigh];
[cancelShareButton setContentHuggingHigh];
[cancelShareButton addTarget:self
action:@selector(didTapCancelShareButton)
forControlEvents:UIControlEventTouchUpInside];
[header addSubview:searchBar];
[searchBar autoPinEdge:ALEdgeLeading toEdge:ALEdgeTrailing ofView:cancelShareButton withOffset:6];
[searchBar autoPinEdgeToSuperviewEdge:ALEdgeTrailing];
[searchBar autoPinEdgeToSuperviewEdge:ALEdgeTop];
[searchBar autoPinEdgeToSuperviewEdge:ALEdgeBottom];
UIView *borderView = [UIView new];
[header addSubview:borderView];
borderView.backgroundColor = [UIColor colorWithRGBHex:0xbbbbbb];
[borderView autoSetDimension:ALDimensionHeight toSize:0.5];
[borderView autoPinWidthToSuperview];
[borderView autoPinEdgeToSuperviewEdge:ALEdgeBottom];
// UITableViewController.tableHeaderView must have its height set.
header.frame = CGRectMake(0, 0, 0, (contentVMargin * 2 + searchBar.frame.size.height));
return header;
}
#pragma mark - SelectThreadViewControllerDelegate
- (nullable NSString *)convertAttachmentToMessageTextIfPossible
{
if (self.attachments.count > 1) {
return nil;
}
OWSAssertDebug(self.attachments.count == 1);
SignalAttachment *attachment = self.attachments.firstObject;
if (!attachment.isConvertibleToTextMessage) {
return nil;
}
if (attachment.dataLength >= kOversizeTextMessageSizeThreshold) {
return nil;
}
NSData *data = attachment.data;
OWSAssertDebug(data.length < kOversizeTextMessageSizeThreshold);
NSString *_Nullable messageText = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
OWSLogVerbose(@"messageTextForAttachment: %@", messageText);
return [messageText filterStringForDisplay];
}
- (void)threadWasSelected:(TSThread *)thread
{
OWSAssertDebug(self.attachments.count > 0);
OWSAssertDebug(thread);
self.thread = thread;
if ([self tryToShareAsMessageText]) {
return;
}
OWSNavigationController *approvalModal =
[AttachmentApprovalViewController wrappedInNavControllerWithAttachments:self.attachments approvalDelegate:self];
[self presentViewController:approvalModal animated:YES completion:nil];
}
- (BOOL)tryToShareAsMessageText
{
OWSAssertDebug(self.attachments.count > 0);
NSString *_Nullable messageText = [self convertAttachmentToMessageTextIfPossible];
if (!messageText) {
return NO;
}
MessageApprovalViewController *approvalVC =
[[MessageApprovalViewController alloc] initWithMessageText:messageText
thread:self.thread
delegate:self];
[self.navigationController pushViewController:approvalVC animated:YES];
return YES;
}
// override
- (void)dismissPressed:(id)sender
{
OWSLogDebug(@"tapped dismiss share button");
[self cancelShareExperience];
}
- (void)didTapCancelShareButton
{
OWSLogDebug(@"tapped cancel share button");
[self cancelShareExperience];
}
- (void)cancelShareExperience
{
[self.shareViewDelegate shareViewWasCancelled];
}
#pragma mark - AttachmentApprovalViewControllerDelegate
- (void)attachmentApproval:(AttachmentApprovalViewController *_Nonnull)attachmentApproval
didApproveAttachments:(NSArray<SignalAttachment *> *_Nonnull)attachments
messageText:(NSString *_Nullable)messageText
{
[self tryToSendMessageWithBlock:^(SendCompletionBlock sendCompletion) {
SNVisibleMessage *message = [SNVisibleMessage new];
message.sentTimestamp = [NSDate millisecondTimestamp];
message.text = messageText;
TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:self.thread];
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[tsMessage saveWithTransaction:transaction];
}];
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[SNMessageSender sendNonDurably:message withAttachments:attachments inThread:self.thread usingTransaction:transaction]
.then(^(id object) {
sendCompletion(nil, tsMessage);
}).catch(^(NSError *error) {
sendCompletion(error, tsMessage);
});
}];
// This is necessary to show progress
self.outgoingMessage = tsMessage;
} fromViewController:attachmentApproval];
}
- (void)attachmentApprovalDidCancel:(AttachmentApprovalViewController *)attachmentApproval
{
[self cancelShareExperience];
}
- (void)attachmentApproval:(AttachmentApprovalViewController *)attachmentApproval
didChangeMessageText:(nullable NSString *)newMessageText
{
// no-op
}
#pragma mark - MessageApprovalViewControllerDelegate
- (void)messageApproval:(MessageApprovalViewController *)approvalViewController
didApproveMessage:(NSString *)messageText
{
[self tryToSendMessageWithBlock:^(SendCompletionBlock sendCompletion) {
SNVisibleMessage *message = [SNVisibleMessage new];
message.sentTimestamp = [NSDate millisecondTimestamp];
message.text = messageText;
TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:self.thread];
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[tsMessage saveWithTransaction:transaction];
}];
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[SNMessageSender sendNonDurably:message withAttachments:@[] inThread:self.thread usingTransaction:transaction]
.then(^(id object) {
sendCompletion(nil, tsMessage);
}).catch(^(NSError *error) {
sendCompletion(error, tsMessage);
});
}];
// This is necessary to show progress
self.outgoingMessage = tsMessage;
} fromViewController:approvalViewController];
}
- (void)messageApprovalDidCancel:(MessageApprovalViewController *)approvalViewController
{
[self cancelShareExperience];
}
#pragma mark - Helpers
- (void)tryToSendMessageWithBlock:(SendMessageBlock)sendMessageBlock
fromViewController:(UIViewController *)fromViewController
{
NSString *progressTitle = NSLocalizedString(@"SHARE_EXTENSION_SENDING_IN_PROGRESS_TITLE", @"Alert title");
UIAlertController *progressAlert = [UIAlertController alertControllerWithTitle:progressTitle
message:nil
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *progressCancelAction = [UIAlertAction actionWithTitle:[CommonStrings cancelButton]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
[self.shareViewDelegate shareViewWasCancelled];
}];
[progressAlert addAction:progressCancelAction];
SendCompletionBlock sendCompletion = ^(NSError *_Nullable error, TSOutgoingMessage *message) {
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
[fromViewController
dismissViewControllerAnimated:YES
completion:^{
OWSLogInfo(@"Sending message failed with error: %@", error);
[self showSendFailureAlertWithError:error
message:message
fromViewController:fromViewController];
}];
return;
}
OWSLogInfo(@"Sending message succeeded.");
[self.shareViewDelegate shareViewWasCompleted];
});
};
[fromViewController presentAlert:progressAlert
completion:^{
sendMessageBlock(sendCompletion);
}];
}
- (void)showSendFailureAlertWithError:(NSError *)error
message:(TSOutgoingMessage *)message
fromViewController:(UIViewController *)fromViewController
{
OWSAssertIsOnMainThread();
OWSAssertDebug(error);
OWSAssertDebug(message);
OWSAssertDebug(fromViewController);
NSString *failureTitle = NSLocalizedString(@"SHARE_EXTENSION_SENDING_FAILURE_TITLE", @"Alert title");
if ([error.domain isEqual:OWSSignalServiceKitErrorDomain] && error.code == OWSErrorCodeUntrustedIdentity) {
NSString *_Nullable untrustedRecipientId = error.userInfo[OWSErrorRecipientIdentifierKey];
NSString *failureFormat = NSLocalizedString(@"SHARE_EXTENSION_FAILED_SENDING_BECAUSE_UNTRUSTED_IDENTITY_FORMAT",
@"alert body when sharing file failed because of untrusted/changed identity keys");
SNContactContext context = [SNContact contextForThread:self.thread];
NSString *displayName = [[LKStorage.shared getContactWithSessionID:untrustedRecipientId] displayNameFor:context] ?: untrustedRecipientId;
NSString *failureMessage = [NSString stringWithFormat:failureFormat, displayName];
UIAlertController *failureAlert = [UIAlertController alertControllerWithTitle:failureTitle
message:failureMessage
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *failureCancelAction = [UIAlertAction actionWithTitle:[CommonStrings cancelButton]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
[self.shareViewDelegate shareViewWasCancelled];
}];
[failureAlert addAction:failureCancelAction];
if (untrustedRecipientId.length > 0) {
UIAlertAction *confirmAction =
[UIAlertAction actionWithTitle:[SafetyNumberStrings confirmSendButton]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[self confirmIdentityAndResendMessage:message
recipientId:untrustedRecipientId
fromViewController:fromViewController];
}];
[failureAlert addAction:confirmAction];
} else {
// This shouldn't happen, but if it does we won't offer the user the ability to confirm.
// They may have to return to the main app to accept the identity change.
OWSFailDebug(@"Untrusted recipient error is missing recipient id.");
}
[fromViewController presentAlert:failureAlert];
} else {
// Non-identity failure, e.g. network offline, rate limit
UIAlertController *failureAlert = [UIAlertController alertControllerWithTitle:failureTitle
message:error.localizedDescription
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *failureCancelAction = [UIAlertAction actionWithTitle:[CommonStrings cancelButton]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
[self.shareViewDelegate shareViewWasCancelled];
}];
[failureAlert addAction:failureCancelAction];
UIAlertAction *retryAction =
[UIAlertAction actionWithTitle:[CommonStrings retryButton]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[self resendMessage:message fromViewController:fromViewController];
}];
[failureAlert addAction:retryAction];
[fromViewController presentAlert:failureAlert];
}
}
- (void)confirmIdentityAndResendMessage:(TSOutgoingMessage *)message
recipientId:(NSString *)recipientId
fromViewController:(UIViewController *)fromViewController
{
OWSAssertIsOnMainThread();
OWSAssertDebug(message);
OWSAssertDebug(recipientId.length > 0);
OWSAssertDebug(fromViewController);
OWSLogDebug(@"Confirming identity for recipient: %@", recipientId);
dispatch_async(dispatch_get_main_queue(), ^(void) {
[self resendMessage:message fromViewController:fromViewController];
});
}
- (void)resendMessage:(TSOutgoingMessage *)tsMessage fromViewController:(UIViewController *)fromViewController
{
OWSAssertIsOnMainThread();
OWSAssertDebug(tsMessage);
OWSAssertDebug(fromViewController);
NSString *progressTitle = NSLocalizedString(@"SHARE_EXTENSION_SENDING_IN_PROGRESS_TITLE", @"Alert title");
UIAlertController *progressAlert = [UIAlertController alertControllerWithTitle:progressTitle
message:nil
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *progressCancelAction = [UIAlertAction actionWithTitle:[CommonStrings cancelButton]
style:UIAlertActionStyleCancel
handler:^(UIAlertAction *_Nonnull action) {
[self.shareViewDelegate shareViewWasCancelled];
}];
[progressAlert addAction:progressCancelAction];
[fromViewController
presentAlert:progressAlert
completion:^{
SNVisibleMessage *message = [SNVisibleMessage from:tsMessage];
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
NSMutableArray<TSAttachmentStream *> *attachments = @[].mutableCopy;
for (NSString *attachmentID in tsMessage.attachmentIds) {
TSAttachmentStream *stream = [TSAttachmentStream fetchObjectWithUniqueID:attachmentID transaction:transaction];
if (![stream isKindOfClass:TSAttachmentStream.class]) { continue; }
[attachments addObject:stream];
}
[SNMessageSender prep:attachments forMessage:message usingTransaction: transaction];
[SNMessageSender sendNonDurably:message withAttachmentIDs:tsMessage.attachmentIds inThread:self.thread usingTransaction:transaction]
.thenOn(dispatch_get_main_queue(), ^() {
[self.shareViewDelegate shareViewWasCompleted];
})
.catchOn(dispatch_get_main_queue(), ^(NSError *error) {
[fromViewController dismissViewControllerAnimated:YES completion:^{
[self showSendFailureAlertWithError:error message:tsMessage fromViewController:fromViewController];
}];
});
}];
}];
}
@end
NS_ASSUME_NONNULL_END

View File

@ -14,7 +14,6 @@
#import <SessionUtilitiesKit/NSData+Image.h>
#import <SessionUtilitiesKit/NSNotificationCenter+OWS.h>
#import <SessionUtilitiesKit/NSString+SSK.h>
#import <SessionMessagingKit/OWSBlockingManager.h>
#import <SessionUtilitiesKit/OWSFileSystem.h>
#import <SignalUtilitiesKit/OWSPrimaryStorage+Loki.h>
#import <SessionMessagingKit/SSKEnvironment.h>
@ -102,11 +101,6 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error);
return SSKEnvironment.shared.identityManager;
}
- (OWSBlockingManager *)blockingManager
{
return SSKEnvironment.shared.blockingManager;
}
- (void)updateLocalProfileName:(nullable NSString *)profileName
avatarImage:(nullable UIImage *)avatarImage
success:(void (^)(void))successBlockParameter

View File

@ -4,11 +4,13 @@
NS_ASSUME_NONNULL_BEGIN
typedef void (^OWSDatabaseMigrationCompletion)(BOOL success, BOOL requiresConfigurationSync);
// This is _NOT_ a singleton and will be instantiated each time that the SAE is used.
@interface AppSetup : NSObject
+ (void)setupEnvironmentWithAppSpecificSingletonBlock:(dispatch_block_t)appSpecificSingletonBlock
migrationCompletion:(dispatch_block_t)migrationCompletion;
migrationCompletion:(OWSDatabaseMigrationCompletion)migrationCompletion;
@end

View File

@ -8,7 +8,6 @@
#import <SignalUtilitiesKit/OWSDatabaseMigration.h>
#import <SignalUtilitiesKit/OWSProfileManager.h>
#import <SessionMessagingKit/OWSBackgroundTask.h>
#import <SessionMessagingKit/OWSBlockingManager.h>
#import <SessionMessagingKit/OWSDisappearingMessagesJob.h>
#import <SessionMessagingKit/OWSIdentityManager.h>
#import <SessionMessagingKit/OWSOutgoingReceiptManager.h>
@ -23,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
@implementation AppSetup
+ (void)setupEnvironmentWithAppSpecificSingletonBlock:(dispatch_block_t)appSpecificSingletonBlock
migrationCompletion:(dispatch_block_t)migrationCompletion
migrationCompletion:(OWSDatabaseMigrationCompletion)migrationCompletion
{
OWSAssertDebug(appSpecificSingletonBlock);
OWSAssertDebug(migrationCompletion);
@ -52,7 +51,6 @@ NS_ASSUME_NONNULL_BEGIN
OWSPreferences *preferences = [OWSPreferences new];
OWSProfileManager *profileManager = [[OWSProfileManager alloc] initWithPrimaryStorage:primaryStorage];
OWSBlockingManager *blockingManager = [[OWSBlockingManager alloc] initWithPrimaryStorage:primaryStorage];
OWSIdentityManager *identityManager = [[OWSIdentityManager alloc] initWithPrimaryStorage:primaryStorage];
TSAccountManager *tsAccountManager = [[TSAccountManager alloc] initWithPrimaryStorage:primaryStorage];
OWSDisappearingMessagesJob *disappearingMessagesJob =
@ -77,7 +75,6 @@ NS_ASSUME_NONNULL_BEGIN
[SSKEnvironment setShared:[[SSKEnvironment alloc] initWithProfileManager:profileManager
primaryStorage:primaryStorage
blockingManager:blockingManager
identityManager:identityManager
tsAccountManager:tsAccountManager
disappearingMessagesJob:disappearingMessagesJob
@ -99,10 +96,10 @@ NS_ASSUME_NONNULL_BEGIN
[OWSStorage registerExtensionsWithMigrationBlock:^() {
dispatch_async(dispatch_get_main_queue(), ^{
// Don't start database migrations until storage is ready.
[VersionMigrations performUpdateCheckWithCompletion:^() {
[VersionMigrations performUpdateCheckWithCompletion:^(BOOL successful, BOOL needsConfigSync) {
OWSAssertIsOnMainThread();
migrationCompletion();
migrationCompletion(successful, needsConfigSync);
OWSAssertDebug(backgroundTask);
backgroundTask = nil;

View File

@ -4,7 +4,6 @@
NS_ASSUME_NONNULL_BEGIN
@class OWSBlockingManager;
@class OWSLinkPreviewDraft;
@class OWSQuotedReplyModel;
@class OWSUnreadIndicator;
@ -60,7 +59,6 @@ NS_ASSUME_NONNULL_BEGIN
// size of the "load window" in that view. The unread indicator should
// always be inserted within that window.
+ (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread
blockingManager:(OWSBlockingManager *)blockingManager
dbConnection:(YapDatabaseConnection *)dbConnection
hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator
lastUnreadIndicator:(nullable OWSUnreadIndicator *)lastUnreadIndicator

View File

@ -7,7 +7,6 @@
#import "OWSUnreadIndicator.h"
#import <SignalUtilitiesKit/OWSProfileManager.h>
#import <SessionMessagingKit/SSKEnvironment.h>
#import <SessionMessagingKit/OWSBlockingManager.h>
#import <SessionMessagingKit/OWSDisappearingMessagesConfiguration.h>
#import <SessionMessagingKit/TSAccountManager.h>
#import <SessionMessagingKit/TSContactThread.h>
@ -66,7 +65,6 @@ NS_ASSUME_NONNULL_BEGIN
#pragma mark - Dynamic Interactions
+ (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread
blockingManager:(OWSBlockingManager *)blockingManager
dbConnection:(YapDatabaseConnection *)dbConnection
hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator
lastUnreadIndicator:(nullable OWSUnreadIndicator *)lastUnreadIndicator
@ -75,7 +73,6 @@ NS_ASSUME_NONNULL_BEGIN
{
OWSAssertDebug(thread);
OWSAssertDebug(dbConnection);
OWSAssertDebug(blockingManager);
OWSAssertDebug(maxRangeSize > 0);
ThreadDynamicInteractions *result = [ThreadDynamicInteractions new];

View File

@ -6,7 +6,7 @@ NS_ASSUME_NONNULL_BEGIN
#define RECENT_CALLS_DEFAULT_KEY @"RPRecentCallsDefaultKey"
typedef void (^VersionMigrationCompletion)(void);
typedef void (^VersionMigrationCompletion)(BOOL success, BOOL requiresConfigurationSync);
@interface VersionMigrations : NSObject