diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index b7509e9fd..065810b23 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -269,8 +269,6 @@ B8D84ECF25E3108A005A043E /* ExpandingAttachmentsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D84ECE25E3108A005A043E /* ExpandingAttachmentsButton.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 */; }; @@ -352,8 +350,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 */; }; @@ -518,7 +514,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 */; }; @@ -574,20 +569,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 */; }; @@ -783,6 +772,8 @@ FD078E6027E2BB36000769AF /* MockIdentityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD078E5F27E2BB36000769AF /* MockIdentityManager.swift */; }; FD0BA51B27CD88EC00CC6805 /* BlindedIdMapping.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0BA51A27CD88EC00CC6805 /* BlindedIdMapping.swift */; }; FD0BA51D27CDC34600CC6805 /* SOGSV4Migration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD0BA51C27CDC34600CC6805 /* SOGSV4Migration.swift */; }; + FD28A4F227E990E800FF65E7 /* BlockingManagerRemovalMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD28A4F127E990E800FF65E7 /* BlockingManagerRemovalMigration.swift */; }; + FD28A4F427EA79F800FF65E7 /* BlockListUIUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD28A4F327EA79F800FF65E7 /* BlockListUIUtils.swift */; }; FD3C905C27E3FBEF00CD579F /* BatchRequestInfoSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3C905B27E3FBEF00CD579F /* BatchRequestInfoSpec.swift */; }; FD3C906027E410F700CD579F /* FileUploadResponseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3C905F27E410F700CD579F /* FileUploadResponseSpec.swift */; }; FD3C906227E411AF00CD579F /* HeaderSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3C906127E411AF00CD579F /* HeaderSpec.swift */; }; @@ -1406,8 +1397,6 @@ B8EB20E6263F7E4B00773E52 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = ""; }; B8EB20ED2640F28000773E52 /* VisibleMessage+OpenGroupInvitation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+OpenGroupInvitation.swift"; sourceTree = ""; }; B8EB20EF2640F7F000773E52 /* OpenGroupInvitationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupInvitationView.swift; sourceTree = ""; }; - B8F5F52725EC4F6A003BF8D4 /* BlockListUIUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BlockListUIUtils.h; sourceTree = ""; }; - B8F5F52825EC4F8A003BF8D4 /* BlockListUIUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BlockListUIUtils.m; sourceTree = ""; }; B8F5F56425EC8453003BF8D4 /* Notification+Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+Contacts.swift"; sourceTree = ""; }; B8F5F58225EC94A6003BF8D4 /* Collection+Subscripting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+Subscripting.swift"; sourceTree = ""; }; B8F5F60225EDE16F003BF8D4 /* DataExtractionNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataExtractionNotification.swift; sourceTree = ""; }; @@ -1455,7 +1444,6 @@ C33FD9AD255A548A00E217F9 /* SignalUtilitiesKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SignalUtilitiesKit.h; sourceTree = ""; }; C33FD9AE255A548A00E217F9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSPrimaryStorage.h; sourceTree = ""; }; - C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBlockingManager.m; sourceTree = ""; }; C33FDA69255A57F900E217F9 /* SSKPreferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKPreferences.swift; sourceTree = ""; }; C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingConfigurationUpdateInfoMessage.m; sourceTree = ""; }; C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProtoUtils.m; sourceTree = ""; }; @@ -1610,7 +1598,6 @@ C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushNotificationAPI.swift; sourceTree = ""; }; C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LKGroupUtilities.m; sourceTree = ""; }; C33FDBE9255A581A00E217F9 /* TSInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInteraction.m; sourceTree = ""; }; - C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBlockingManager.h; sourceTree = ""; }; C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSRecipientIdentity.m; sourceTree = ""; }; C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSStorageKeys.h; sourceTree = ""; }; C33FDBF1255A581B00E217F9 /* OWSIdentityManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSIdentityManager.h; sourceTree = ""; }; @@ -1732,21 +1719,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; }; @@ -1943,6 +1923,8 @@ FD078E5F27E2BB36000769AF /* MockIdentityManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockIdentityManager.swift; sourceTree = ""; }; FD0BA51A27CD88EC00CC6805 /* BlindedIdMapping.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlindedIdMapping.swift; sourceTree = ""; }; FD0BA51C27CDC34600CC6805 /* SOGSV4Migration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SOGSV4Migration.swift; sourceTree = ""; }; + FD28A4F127E990E800FF65E7 /* BlockingManagerRemovalMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockingManagerRemovalMigration.swift; sourceTree = ""; }; + FD28A4F327EA79F800FF65E7 /* BlockListUIUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockListUIUtils.swift; sourceTree = ""; }; FD3C905B27E3FBEF00CD579F /* BatchRequestInfoSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchRequestInfoSpec.swift; sourceTree = ""; }; FD3C905F27E410F700CD579F /* FileUploadResponseSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileUploadResponseSpec.swift; sourceTree = ""; }; FD3C906127E411AF00CD579F /* HeaderSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeaderSpec.swift; sourceTree = ""; }; @@ -2735,7 +2717,6 @@ isa = PBXGroup; children = ( C3D9E3B52567685D0040E4F3 /* Attachments */, - C32C5B9E256DC720003C73A2 /* Blocking */, B8F5F61925EDE4B0003BF8D4 /* Data Extraction */, C32C5B01256DC054003C73A2 /* Expiration */, C32C5D22256DD496003C73A2 /* Link Previews */, @@ -2901,15 +2882,6 @@ path = Quotes; sourceTree = ""; }; - C32C5B9E256DC720003C73A2 /* Blocking */ = { - isa = PBXGroup; - children = ( - C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */, - C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */, - ); - path = Blocking; - sourceTree = ""; - }; C32C5BB9256DC7C4003C73A2 /* To Do */ = { isa = PBXGroup; children = ( @@ -3041,7 +3013,6 @@ C36096EE25AD21BC008B62B2 /* Screen Lock */, C3851CD225624B060061EEB0 /* Shared Views */, C360970125AD22D3008B62B2 /* Shared View Controllers */, - C36096F025AD227E008B62B2 /* Sharing */, C3851CE3256250FA0061EEB0 /* To Do */, C3CA3B11255CF17200F4C6D4 /* Utilities */, ); @@ -3271,19 +3242,6 @@ path = "Profile Pictures"; sourceTree = ""; }; - 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 = ""; - }; C360970125AD22D3008B62B2 /* Shared View Controllers */ = { isa = PBXGroup; children = ( @@ -3315,6 +3273,7 @@ B8B32044258C117C0020074B /* ContactsMigration.swift */, FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */, FD3C907227E8387300CD579F /* OpenGroupServerIdLookupMigration.swift */, + FD28A4F127E990E800FF65E7 /* BlockingManagerRemovalMigration.swift */, FD0BA51C27CDC34600CC6805 /* SOGSV4Migration.swift */, C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */, C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */, @@ -3405,8 +3364,7 @@ C38BBA0D255E321C0041B9A3 /* Messaging */ = { isa = PBXGroup; children = ( - B8F5F52725EC4F6A003BF8D4 /* BlockListUIUtils.h */, - B8F5F52825EC4F8A003BF8D4 /* BlockListUIUtils.m */, + FD28A4F327EA79F800FF65E7 /* BlockListUIUtils.swift */, C38EF2FC255B6DBD007E1867 /* ConversationStyle.swift */, C38EF3D4255B6DEE007E1867 /* DisappearingTimerConfigurationView.swift */, C33FDA72255A57FA00E217F9 /* OWSFailedAttachmentDownloadsJob.h */, @@ -3414,7 +3372,6 @@ C33FDADB255A580400E217F9 /* OWSFailedMessagesJob.h */, C33FDAB7255A580100E217F9 /* OWSFailedMessagesJob.m */, C38EF397255B6DD9007E1867 /* ThreadViewModel.swift */, - C38EF30B255B6DBE007E1867 /* BlockListCache.swift */, C38EF2E4255B6DB9007E1867 /* FullTextSearcher.swift */, C38EF2E9255B6DBA007E1867 /* OWSUnreadIndicator.h */, C38EF2E3255B6DB9007E1867 /* OWSUnreadIndicator.m */, @@ -4194,7 +4151,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 */, @@ -4207,7 +4163,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 */, @@ -4219,7 +4174,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 */, @@ -4227,7 +4181,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; @@ -4311,7 +4264,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 */, @@ -5143,10 +5095,10 @@ C38EF317255B6DBF007E1867 /* DisplayableText.swift in Sources */, C38EF30F255B6DBF007E1867 /* AppPreferences.swift in Sources */, C38EF3C3255B6DE7007E1867 /* ImageEditorTextItem.swift in Sources */, + FD28A4F227E990E800FF65E7 /* 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 */, @@ -5154,11 +5106,11 @@ 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 */, C38EF3FF255B6DF7007E1867 /* TappableView.swift in Sources */, + FD28A4F427EA79F800FF65E7 /* BlockListUIUtils.swift in Sources */, C38EF3C2255B6DE7007E1867 /* ImageEditorPaletteView.swift in Sources */, C38EF245255B6D67007E1867 /* UIFont+OWS.m in Sources */, C38EF36F255B6DCC007E1867 /* OWSViewController.m in Sources */, @@ -5189,7 +5141,6 @@ C38EF409255B6DF7007E1867 /* ContactTableViewCell.m in Sources */, FD3C907327E8387300CD579F /* OpenGroupServerIdLookupMigration.swift 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 */, @@ -5226,7 +5177,6 @@ C38EF36B255B6DCC007E1867 /* ScreenLockViewController.m in Sources */, C38EF228255B6D5D007E1867 /* AttachmentSharing.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 */, @@ -5261,7 +5211,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 */, @@ -5412,7 +5361,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 */, @@ -5950,7 +5898,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 332; + CURRENT_PROJECT_VERSION = 333; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -6023,7 +5971,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 332; + CURRENT_PROJECT_VERSION = 333; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -6089,7 +6037,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 332; + CURRENT_PROJECT_VERSION = 333; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = "$(inherited)"; @@ -6163,7 +6111,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; CODE_SIGN_STYLE = Automatic; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 332; + CURRENT_PROJECT_VERSION = 333; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = SUQ8J2PCT7; ENABLE_NS_ASSERTIONS = NO; @@ -7099,7 +7047,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 332; + CURRENT_PROJECT_VERSION = 333; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", @@ -7170,7 +7118,7 @@ CODE_SIGN_ENTITLEMENTS = Session/Meta/Signal.entitlements; CODE_SIGN_IDENTITY = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CURRENT_PROJECT_VERSION = 332; + CURRENT_PROJECT_VERSION = 333; DEVELOPMENT_TEAM = SUQ8J2PCT7; FRAMEWORK_SEARCH_PATHS = ( "$(inherited)", diff --git a/Session/Backups/OWSBackup.m b/Session/Backups/OWSBackup.m index 4f0ec36b0..3323867c9 100644 --- a/Session/Backups/OWSBackup.m +++ b/Session/Backups/OWSBackup.m @@ -58,7 +58,6 @@ NSString *NSStringForBackupImportState(OWSBackupState state) NSArray *MiscCollectionsToBackup(void) { return @[ - kOWSBlockingManager_BlockListCollection, OWSUserProfile.collection, SSKIncrementingIdFinder.collectionName, OWSPreferencesSignalDatabaseCollection, diff --git a/Session/Backups/OWSBackupImportJob.m b/Session/Backups/OWSBackupImportJob.m index 46233da19..ab8d0e98c 100644 --- a/Session/Backups/OWSBackupImportJob.m +++ b/Session/Backups/OWSBackupImportJob.m @@ -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)); }]; }); diff --git a/Session/Closed Groups/NewClosedGroupVC.swift b/Session/Closed Groups/NewClosedGroupVC.swift index 57ddd3f12..80efefa2c 100644 --- a/Session/Closed Groups/NewClosedGroupVC.swift +++ b/Session/Closed Groups/NewClosedGroupVC.swift @@ -175,8 +175,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) } diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index 7da3e5392..9fc83e25d 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -50,21 +50,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) @@ -1204,6 +1208,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 @@ -1237,11 +1244,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() - } } } } @@ -1278,6 +1280,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 @@ -1295,24 +1303,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) } } diff --git a/Session/Conversations/ConversationVC.swift b/Session/Conversations/ConversationVC.swift index e4e1f471c..0e726ebde 100644 --- a/Session/Conversations/ConversationVC.swift +++ b/Session/Conversations/ConversationVC.swift @@ -367,7 +367,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) @@ -815,10 +815,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() } } diff --git a/Session/Conversations/ConversationViewModel.m b/Session/Conversations/ConversationViewModel.m index ac9ba0ccc..db4f9e164 100644 --- a/Session/Conversations/ConversationViewModel.m +++ b/Session/Conversations/ConversationViewModel.m @@ -10,7 +10,6 @@ #import #import #import -#import #import #import #import @@ -247,11 +246,6 @@ NS_ASSUME_NONNULL_BEGIN return self.primaryStorage.dbReadWriteConnection; } -- (OWSBlockingManager *)blockingManager -{ - return OWSBlockingManager.sharedManager; -} - - (id)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 diff --git a/Session/Conversations/Settings/OWSConversationSettingsViewController.m b/Session/Conversations/Settings/OWSConversationSettingsViewController.m index b7a4d1978..f46cfb2d5 100644 --- a/Session/Conversations/Settings/OWSConversationSettingsViewController.m +++ b/Session/Conversations/Settings/OWSConversationSettingsViewController.m @@ -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 *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]; }]; diff --git a/Session/Conversations/Views & Modals/BlockedModal.swift b/Session/Conversations/Views & Modals/BlockedModal.swift index c41e76632..de6a87f3b 100644 --- a/Session/Conversations/Views & Modals/BlockedModal.swift +++ b/Session/Conversations/Views & Modals/BlockedModal.swift @@ -1,5 +1,6 @@ +import SessionMessagingKit -final class BlockedModal : Modal { +final class BlockedModal: Modal { private let publicKey: String // MARK: Lifecycle @@ -63,7 +64,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) } } diff --git a/Session/Conversations/Views & Modals/JoinOpenGroupModal.swift b/Session/Conversations/Views & Modals/JoinOpenGroupModal.swift index 732a633a9..178a9c6f0 100644 --- a/Session/Conversations/Views & Modals/JoinOpenGroupModal.swift +++ b/Session/Conversations/Views & Modals/JoinOpenGroupModal.swift @@ -1,3 +1,5 @@ +import UIKit +import SessionMessagingKit final class JoinOpenGroupModal : Modal { private let name: String @@ -74,8 +76,7 @@ final class JoinOpenGroupModal : Modal { OpenGroupManager.shared .add(roomToken: room, server: server, publicKey: publicKey, isConfigMessage: false, using: transaction as! YapDatabaseReadWriteTransaction) .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) diff --git a/Session/Home/HomeVC.swift b/Session/Home/HomeVC.swift index 30d58f363..166f9bd52 100644 --- a/Session/Home/HomeVC.swift +++ b/Session/Home/HomeVC.swift @@ -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) ] } } diff --git a/Session/Home/Message Requests/MessageRequestsViewController.swift b/Session/Home/Message Requests/MessageRequestsViewController.swift index 62dcb634b..083b92257 100644 --- a/Session/Home/Message Requests/MessageRequestsViewController.swift +++ b/Session/Home/Message Requests/MessageRequestsViewController.swift @@ -348,23 +348,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() } } ) @@ -382,19 +382,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() } ) }) diff --git a/Session/Meta/AppDelegate.m b/Session/Meta/AppDelegate.m index fbf3a99cb..8497003fe 100644 --- a/Session/Meta/AppDelegate.m +++ b/Session/Meta/AppDelegate.m @@ -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]; } diff --git a/Session/Meta/AppDelegate.swift b/Session/Meta/AppDelegate.swift index 6f1182807..ce3c93df8 100644 --- a/Session/Meta/AppDelegate.swift +++ b/Session/Meta/AppDelegate.swift @@ -1,4 +1,5 @@ import PromiseKit +import SessionMessagingKit extension AppDelegate { @@ -8,39 +9,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 { - let destination = Message.Destination.contact(publicKey: getUserHexEncodedPublicKey()) - let (promise, seal) = Promise.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() } @objc func startClosedGroupPoller() { diff --git a/Session/Open Groups/JoinOpenGroupVC.swift b/Session/Open Groups/JoinOpenGroupVC.swift index 914525266..ea9335491 100644 --- a/Session/Open Groups/JoinOpenGroupVC.swift +++ b/Session/Open Groups/JoinOpenGroupVC.swift @@ -1,3 +1,5 @@ +import UIKit +import SessionMessagingKit final class JoinOpenGroupVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControllerDelegate, OWSQRScannerDelegate { private let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil) @@ -145,8 +147,7 @@ final class JoinOpenGroupVC : BaseVC, UIPageViewControllerDataSource, UIPageView .add(roomToken: roomToken, server: server, publicKey: publicKey, isConfigMessage: false, using: transaction as! YapDatabaseReadWriteTransaction) .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 diff --git a/Session/Settings/NukeDataModal.swift b/Session/Settings/NukeDataModal.swift index d08b30d9a..19b03dc3b 100644 --- a/Session/Settings/NukeDataModal.swift +++ b/Session/Settings/NukeDataModal.swift @@ -123,9 +123,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.mutate { $0.encodedPublicKey = nil } // Remove the cached key so it gets re-cached on next access diff --git a/Session/Settings/SettingsVC.swift b/Session/Settings/SettingsVC.swift index ea52be018..d9718ff65 100644 --- a/Session/Settings/SettingsVC.swift +++ b/Session/Settings/SettingsVC.swift @@ -1,5 +1,6 @@ import UIKit import SessionUtilitiesKit +import SessionMessagingKit final class SettingsVC : BaseVC, AvatarViewHelperDelegate { private var profilePictureToBeUploaded: UIImage? @@ -368,8 +369,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 } diff --git a/Session/Shared/ConversationCell.swift b/Session/Shared/ConversationCell.swift index 152a442c3..16ccb648d 100644 --- a/Session/Shared/ConversationCell.swift +++ b/Session/Shared/ConversationCell.swift @@ -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 } diff --git a/SessionMessagingKit/Contacts/Contact.swift b/SessionMessagingKit/Contacts/Contact.swift index 53d7ab4bb..47b303ecf 100644 --- a/SessionMessagingKit/Contacts/Contact.swift +++ b/SessionMessagingKit/Contacts/Contact.swift @@ -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 diff --git a/SessionMessagingKit/Database/Notification+Contacts.swift b/SessionMessagingKit/Database/Notification+Contacts.swift index 05f3cfca1..74d855ea0 100644 --- a/SessionMessagingKit/Database/Notification+Contacts.swift +++ b/SessionMessagingKit/Database/Notification+Contacts.swift @@ -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 } diff --git a/SessionMessagingKit/Database/Storage+Contacts.swift b/SessionMessagingKit/Database/Storage+Contacts.swift index 5ff6d5d42..dcb5e0674 100644 --- a/SessionMessagingKit/Database/Storage+Contacts.swift +++ b/SessionMessagingKit/Database/Storage+Contacts.swift @@ -45,12 +45,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) + } } } diff --git a/SessionMessagingKit/Database/TSDatabaseView.m b/SessionMessagingKit/Database/TSDatabaseView.m index 87baf72f2..ec47b53b7 100644 --- a/SessionMessagingKit/Database/TSDatabaseView.m +++ b/SessionMessagingKit/Database/TSDatabaseView.m @@ -9,7 +9,6 @@ #import "TSIncomingMessage.h" #import "TSOutgoingMessage.h" #import "TSThread.h" -#import "OWSBlockingManager.h" #import #import #import @@ -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; } diff --git a/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift b/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift index 1f37f57ac..f7eb6b627 100644 --- a/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift +++ b/SessionMessagingKit/Messages/Control Messages/ConfigurationMessage+Convenience.swift @@ -44,7 +44,7 @@ extension ConfigurationMessage { if let threadId: String = thread.uniqueId, let openGroup = storage.getOpenGroup(for: threadId) { openGroups.insert("\(openGroup.server)/\(openGroup.room)?public_key=\(openGroup.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 ) diff --git a/SessionMessagingKit/Meta/SessionMessagingKit.h b/SessionMessagingKit/Meta/SessionMessagingKit.h index 498e820cb..da0a86ab6 100644 --- a/SessionMessagingKit/Meta/SessionMessagingKit.h +++ b/SessionMessagingKit/Meta/SessionMessagingKit.h @@ -10,7 +10,6 @@ FOUNDATION_EXPORT const unsigned char SessionMessagingKitVersionString[]; #import #import #import -#import #import #import #import diff --git a/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.h b/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.h deleted file mode 100644 index a470f6e4e..000000000 --- a/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -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 *)blockedPhoneNumbers sendSyncMessage:(BOOL)sendSyncMessage; - -// TODO convert to property -- (NSArray *)blockedPhoneNumbers; - -@property (readonly) NSArray *blockedGroupIds; -@property (readonly) NSArray *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 diff --git a/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.m b/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.m deleted file mode 100644 index c814fa73c..000000000 --- a/SessionMessagingKit/Sending & Receiving/Blocking/OWSBlockingManager.m +++ /dev/null @@ -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 -#import - -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 *blockedPhoneNumberSet; -@property (atomic, readonly) NSMutableDictionary *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 *)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 *)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 *)blockedGroupIds -{ - @synchronized(self) { - [self ensureLazyInitialization]; - return self.blockedGroupMap.allKeys; - } -} - -- (NSArray *)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 *blockedPhoneNumbers = [self blockedPhoneNumbers]; - - [self.dbConnection setObject:blockedPhoneNumbers - forKey:kOWSBlockingManager_BlockedPhoneNumbersKey - inCollection:kOWSBlockingManager_BlockListCollection]; - - NSDictionary *blockedGroupMap; - @synchronized(self) { - blockedGroupMap = [self.blockedGroupMap copy]; - } - NSArray *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 *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 *blockedPhoneNumbers = - [self.dbConnection objectForKey:kOWSBlockingManager_BlockedPhoneNumbersKey - inCollection:kOWSBlockingManager_BlockListCollection]; - _blockedPhoneNumberSet = [[NSMutableSet alloc] initWithArray:(blockedPhoneNumbers ?: [NSArray new])]; - - NSDictionary *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 *)blockedPhoneNumbers - groupIds:(NSArray *)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 diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift index 4b052e252..47317cbd0 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver+Handling.swift @@ -5,10 +5,6 @@ import SessionSnodeKit 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, dependencies: Dependencies = Dependencies()) throws { switch message { case let message as ReadReceipt: handleReadReceipt(message, using: transaction) @@ -213,6 +209,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 @@ -220,9 +217,15 @@ extension MessageReceiver { // Note: We only update these values if the proto actually has values for them (this is to // prevent an edge case where an old client could override the values with default values // since they aren't included) - if contactInfo.hasIsApproved { contact.isApproved = contactInfo.isApproved } + // + // Note: Since message requests has no reverse, the only case we need to process is a + // config message setting *isApproved* and *didApproveMe* to true. This may prevent some + // weird edge cases where a config message swapping *isApproved* and *didApproveMe* to + // false. + if contactInfo.hasIsApproved && contactInfo.isApproved { contact.isApproved = true } + if contactInfo.hasDidApproveMe && contactInfo.didApproveMe { contact.didApproveMe = true } + if contactInfo.hasIsBlocked { contact.isBlocked = contactInfo.isBlocked } - if contactInfo.hasDidApproveMe { contact.didApproveMe = contactInfo.didApproveMe } Storage.shared.setContact(contact, using: transaction) @@ -232,7 +235,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.getWithContactSessionID(sessionID, transaction: transaction), thread.isMessageRequest(using: transaction) { @@ -242,22 +245,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 @@ -830,23 +817,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, dependencies: Dependencies) { diff --git a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift index 857960017..60dc6dc10 100644 --- a/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift +++ b/SessionMessagingKit/Sending & Receiving/MessageReceiver.swift @@ -140,7 +140,9 @@ public enum MessageReceiver { } // 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 diff --git a/SessionMessagingKit/Threads/TSContactThread.m b/SessionMessagingKit/Threads/TSContactThread.m index 5c4a9459c..5633149d4 100644 --- a/SessionMessagingKit/Threads/TSContactThread.m +++ b/SessionMessagingKit/Threads/TSContactThread.m @@ -112,6 +112,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; diff --git a/SessionMessagingKit/Threads/TSThread.h b/SessionMessagingKit/Threads/TSThread.h index 9a925a177..b6629794e 100644 --- a/SessionMessagingKit/Threads/TSThread.h +++ b/SessionMessagingKit/Threads/TSThread.h @@ -55,6 +55,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; diff --git a/SessionMessagingKit/Threads/TSThread.m b/SessionMessagingKit/Threads/TSThread.m index 3311f5705..889dde49a 100644 --- a/SessionMessagingKit/Threads/TSThread.m +++ b/SessionMessagingKit/Threads/TSThread.m @@ -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 { diff --git a/SessionMessagingKit/Utilities/SSKEnvironment.h b/SessionMessagingKit/Utilities/SSKEnvironment.h index bd17878ce..d44250910 100644 --- a/SessionMessagingKit/Utilities/SSKEnvironment.h +++ b/SessionMessagingKit/Utilities/SSKEnvironment.h @@ -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)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 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; diff --git a/SessionMessagingKit/Utilities/SSKEnvironment.m b/SessionMessagingKit/Utilities/SSKEnvironment.m index a638d3047..2c9046129 100644 --- a/SessionMessagingKit/Utilities/SSKEnvironment.m +++ b/SessionMessagingKit/Utilities/SSKEnvironment.m @@ -14,7 +14,6 @@ static SSKEnvironment *sharedSSKEnvironment; @property (nonatomic) id 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)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; diff --git a/SessionNotificationServiceExtension/NotificationServiceExtension.swift b/SessionNotificationServiceExtension/NotificationServiceExtension.swift index 2da1ee44e..cd5021133 100644 --- a/SessionNotificationServiceExtension/NotificationServiceExtension.swift +++ b/SessionNotificationServiceExtension/NotificationServiceExtension.swift @@ -109,8 +109,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() } ) @@ -119,10 +119,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() } diff --git a/SessionShareExtension/ShareVC.swift b/SessionShareExtension/ShareVC.swift index 34716c706..3da672138 100644 --- a/SessionShareExtension/ShareVC.swift +++ b/SessionShareExtension/ShareVC.swift @@ -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() } diff --git a/SessionShareExtension/SimplifiedConversationCell.swift b/SessionShareExtension/SimplifiedConversationCell.swift index b23f02b43..1c7896c54 100644 --- a/SessionShareExtension/SimplifiedConversationCell.swift +++ b/SessionShareExtension/SimplifiedConversationCell.swift @@ -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() } diff --git a/SignalUtilitiesKit/Database/Migrations/BlockingManagerRemovalMigration.swift b/SignalUtilitiesKit/Database/Migrations/BlockingManagerRemovalMigration.swift new file mode 100644 index 000000000..518a4bc7e --- /dev/null +++ b/SignalUtilitiesKit/Database/Migrations/BlockingManagerRemovalMigration.swift @@ -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 = 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) + } + ) + } +} diff --git a/SignalUtilitiesKit/Database/Migrations/ContactsMigration.swift b/SignalUtilitiesKit/Database/Migrations/ContactsMigration.swift index 1c6c2e4cc..8dc9708fe 100644 --- a/SignalUtilitiesKit/Database/Migrations/ContactsMigration.swift +++ b/SignalUtilitiesKit/Database/Migrations/ContactsMigration.swift @@ -27,7 +27,7 @@ public class ContactsMigration : OWSDatabaseMigration { } self.save(with: transaction) // Intentionally capture self }, completion: { - completion() + completion(true, false) }) } } diff --git a/SignalUtilitiesKit/Database/Migrations/MessageRequestsMigration.swift b/SignalUtilitiesKit/Database/Migrations/MessageRequestsMigration.swift index d1fe7cf24..441d9fc00 100644 --- a/SignalUtilitiesKit/Database/Migrations/MessageRequestsMigration.swift +++ b/SignalUtilitiesKit/Database/Migrations/MessageRequestsMigration.swift @@ -57,7 +57,7 @@ public class MessageRequestsMigration : OWSDatabaseMigration { } self.save(with: transaction) // Intentionally capture self }, completion: { - completion() + completion(true, true) }) } } diff --git a/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigration.h b/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigration.h index 3f1bd715e..d99decd7e 100644 --- a/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigration.h +++ b/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigration.h @@ -6,7 +6,7 @@ NS_ASSUME_NONNULL_BEGIN -typedef void (^OWSDatabaseMigrationCompletion)(void); +typedef void (^OWSDatabaseMigrationCompletion)(BOOL success, BOOL requiresConfigurationSync); @class OWSPrimaryStorage; diff --git a/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigration.m b/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigration.m index 5e78fa2b9..53ba11003 100644 --- a/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigration.m +++ b/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigration.m @@ -76,7 +76,7 @@ NS_ASSUME_NONNULL_BEGIN OWSLogInfo(@"Completed migration %@", self.uniqueId); [self save]; - completion(); + completion(true, false); }]; } diff --git a/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.h b/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.h index 82e658a1f..58c75ec8c 100644 --- a/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.h +++ b/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.h @@ -4,7 +4,7 @@ NS_ASSUME_NONNULL_BEGIN -typedef void (^OWSDatabaseMigrationCompletion)(void); +typedef void (^OWSDatabaseMigrationCompletion)(BOOL success, BOOL requiresConfigurationSync); @interface OWSDatabaseMigrationRunner : NSObject diff --git a/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.m b/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.m index 91b370f4e..559c8dc03 100644 --- a/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.m +++ b/SignalUtilitiesKit/Database/Migrations/OWSDatabaseMigrationRunner.m @@ -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 *)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]; }]; } diff --git a/SignalUtilitiesKit/Database/Migrations/OWSResaveCollectionDBMigration.m b/SignalUtilitiesKit/Database/Migrations/OWSResaveCollectionDBMigration.m index a6cc9c67f..f899bed9b 100644 --- a/SignalUtilitiesKit/Database/Migrations/OWSResaveCollectionDBMigration.m +++ b/SignalUtilitiesKit/Database/Migrations/OWSResaveCollectionDBMigration.m @@ -48,7 +48,7 @@ NS_ASSUME_NONNULL_BEGIN OWSLogVerbose(@"%lu", (unsigned long)recordIds.count); if (recordIds.count < 1) { - completion(); + completion(true, false); return; } diff --git a/SignalUtilitiesKit/Database/Migrations/OpenGroupServerIdLookupMigration.swift b/SignalUtilitiesKit/Database/Migrations/OpenGroupServerIdLookupMigration.swift index 31f7077f6..78fec52b6 100644 --- a/SignalUtilitiesKit/Database/Migrations/OpenGroupServerIdLookupMigration.swift +++ b/SignalUtilitiesKit/Database/Migrations/OpenGroupServerIdLookupMigration.swift @@ -43,7 +43,7 @@ public class OpenGroupServerIdLookupMigration: OWSDatabaseMigration { } self.save(with: transaction) // Intentionally capture self }, completion: { - completion() + completion(true, false) }) } } diff --git a/SignalUtilitiesKit/Database/Migrations/SOGSV4Migration.swift b/SignalUtilitiesKit/Database/Migrations/SOGSV4Migration.swift index 6c945b28b..d73972429 100644 --- a/SignalUtilitiesKit/Database/Migrations/SOGSV4Migration.swift +++ b/SignalUtilitiesKit/Database/Migrations/SOGSV4Migration.swift @@ -27,7 +27,7 @@ public class SOGSV4Migration: OWSDatabaseMigration { self.save(with: transaction) // Intentionally capture self }, completion: { - completion() + completion(true, false) }) } } diff --git a/SignalUtilitiesKit/Messaging/BlockListCache.swift b/SignalUtilitiesKit/Messaging/BlockListCache.swift deleted file mode 100644 index 37b64c564..000000000 --- a/SignalUtilitiesKit/Messaging/BlockListCache.swift +++ /dev/null @@ -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 = Set() - private var blockedGroupIds: Set = 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, blockedGroupIds: Set) { - serialQueue.sync { - self.blockedRecipientIds = blockedRecipientIds - self.blockedGroupIds = blockedGroupIds - } - } -} diff --git a/SignalUtilitiesKit/Messaging/BlockListUIUtils.h b/SignalUtilitiesKit/Messaging/BlockListUIUtils.h deleted file mode 100644 index c1dad0286..000000000 --- a/SignalUtilitiesKit/Messaging/BlockListUIUtils.h +++ /dev/null @@ -1,68 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -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 diff --git a/SignalUtilitiesKit/Messaging/BlockListUIUtils.m b/SignalUtilitiesKit/Messaging/BlockListUIUtils.m deleted file mode 100644 index 1c78ee13c..000000000 --- a/SignalUtilitiesKit/Messaging/BlockListUIUtils.m +++ /dev/null @@ -1,494 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "BlockListUIUtils.h" -#import "TSContactThread.h" -#import -#import -#import -#import -#import -#import -#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 *)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 *)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 *)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 *)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 diff --git a/SignalUtilitiesKit/Messaging/BlockListUIUtils.swift b/SignalUtilitiesKit/Messaging/BlockListUIUtils.swift new file mode 100644 index 000000000..d933bc53e --- /dev/null +++ b/SignalUtilitiesKit/Messaging/BlockListUIUtils.swift @@ -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 + } +} diff --git a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift index c0510d16b..3864c18de 100644 --- a/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift +++ b/SignalUtilitiesKit/Messaging/Sending & Receiving/MessageSender+Convenience.swift @@ -1,4 +1,5 @@ import PromiseKit +import SessionUtilitiesKit extension MessageSender { @@ -178,4 +179,39 @@ extension MessageSender { return promise } + + public static func syncConfiguration(forceSyncNow: Bool = true) -> Promise { + let (promise, seal) = Promise.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() + } } diff --git a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h index 1d2cedbc2..bccb9c6a5 100644 --- a/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h +++ b/SignalUtilitiesKit/Meta/SignalUtilitiesKit.h @@ -10,7 +10,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import #import #import #import @@ -43,8 +42,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[]; #import #import #import -#import -#import #import #import #import diff --git a/SignalUtilitiesKit/Sharing/SelectRecipientViewController.h b/SignalUtilitiesKit/Sharing/SelectRecipientViewController.h deleted file mode 100644 index 2d950efe5..000000000 --- a/SignalUtilitiesKit/Sharing/SelectRecipientViewController.h +++ /dev/null @@ -1,47 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class SignalAccount; - -@protocol SelectRecipientViewControllerDelegate - -- (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 delegate; - -@property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper; - -@property (nonatomic) BOOL isPresentedInNavigationController; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Sharing/SelectRecipientViewController.m b/SignalUtilitiesKit/Sharing/SelectRecipientViewController.m deleted file mode 100644 index cf18cc5c4..000000000 --- a/SignalUtilitiesKit/Sharing/SelectRecipientViewController.m +++ /dev/null @@ -1,332 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import - -#import -#import -#import -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -NSString *const kSelectRecipientViewControllerCellIdentifier = @"kSelectRecipientViewControllerCellIdentifier"; - -#pragma mark - - -@interface SelectRecipientViewController () - -@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 diff --git a/SignalUtilitiesKit/Sharing/SelectThreadViewController.h b/SignalUtilitiesKit/Sharing/SelectThreadViewController.h deleted file mode 100644 index 6d8c0299b..000000000 --- a/SignalUtilitiesKit/Sharing/SelectThreadViewController.h +++ /dev/null @@ -1,31 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -@class TSThread; - -NS_ASSUME_NONNULL_BEGIN - -@protocol SelectThreadViewControllerDelegate - -- (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 selectThreadViewDelegate; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Sharing/SelectThreadViewController.m b/SignalUtilitiesKit/Sharing/SelectThreadViewController.m deleted file mode 100644 index 0a2f5ffe8..000000000 --- a/SignalUtilitiesKit/Sharing/SelectThreadViewController.m +++ /dev/null @@ -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 -#import -#import -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@interface SelectThreadViewController () - -@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 diff --git a/SignalUtilitiesKit/Sharing/SharingThreadPickerViewController.h b/SignalUtilitiesKit/Sharing/SharingThreadPickerViewController.h deleted file mode 100644 index b77cc95de..000000000 --- a/SignalUtilitiesKit/Sharing/SharingThreadPickerViewController.h +++ /dev/null @@ -1,21 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import - -NS_ASSUME_NONNULL_BEGIN - -@class SignalAttachment; - -@protocol ShareViewDelegate; - -@interface SharingThreadPickerViewController : SelectThreadViewController - -@property (nonatomic) NSArray *attachments; - -- (instancetype)initWithShareViewDelegate:(id)shareViewDelegate; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalUtilitiesKit/Sharing/SharingThreadPickerViewController.m b/SignalUtilitiesKit/Sharing/SharingThreadPickerViewController.m deleted file mode 100644 index ae54400b6..000000000 --- a/SignalUtilitiesKit/Sharing/SharingThreadPickerViewController.m +++ /dev/null @@ -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 -#import -#import -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -typedef void (^SendCompletionBlock)(NSError *_Nullable, TSOutgoingMessage *); -typedef void (^SendMessageBlock)(SendCompletionBlock completion); - -@interface SharingThreadPickerViewController () - -@property (nonatomic, readonly) OWSMessageSender *messageSender; -@property (nonatomic) TSThread *thread; -@property (nonatomic, readonly, weak) id shareViewDelegate; -@property (atomic, nullable) TSOutgoingMessage *outgoingMessage; - -@end - -#pragma mark - - -@implementation SharingThreadPickerViewController - -- (instancetype)initWithShareViewDelegate:(id)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 *_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 *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 diff --git a/SignalUtilitiesKit/To Do/OWSProfileManager.m b/SignalUtilitiesKit/To Do/OWSProfileManager.m index ad28e1ef2..8822c80bf 100644 --- a/SignalUtilitiesKit/To Do/OWSProfileManager.m +++ b/SignalUtilitiesKit/To Do/OWSProfileManager.m @@ -14,7 +14,6 @@ #import #import #import -#import #import #import #import @@ -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 diff --git a/SignalUtilitiesKit/Utilities/AppSetup.h b/SignalUtilitiesKit/Utilities/AppSetup.h index d4f3f489a..aa4f587c7 100644 --- a/SignalUtilitiesKit/Utilities/AppSetup.h +++ b/SignalUtilitiesKit/Utilities/AppSetup.h @@ -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 diff --git a/SignalUtilitiesKit/Utilities/AppSetup.m b/SignalUtilitiesKit/Utilities/AppSetup.m index cd48b7319..062c572d9 100644 --- a/SignalUtilitiesKit/Utilities/AppSetup.m +++ b/SignalUtilitiesKit/Utilities/AppSetup.m @@ -8,7 +8,6 @@ #import #import #import -#import #import #import #import @@ -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; diff --git a/SignalUtilitiesKit/Utilities/ThreadUtil.h b/SignalUtilitiesKit/Utilities/ThreadUtil.h index 28ca1f27e..ddc936b94 100644 --- a/SignalUtilitiesKit/Utilities/ThreadUtil.h +++ b/SignalUtilitiesKit/Utilities/ThreadUtil.h @@ -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 diff --git a/SignalUtilitiesKit/Utilities/ThreadUtil.m b/SignalUtilitiesKit/Utilities/ThreadUtil.m index ccd85df3b..c2b61eb2d 100644 --- a/SignalUtilitiesKit/Utilities/ThreadUtil.m +++ b/SignalUtilitiesKit/Utilities/ThreadUtil.m @@ -7,7 +7,6 @@ #import "OWSUnreadIndicator.h" #import #import -#import #import #import #import @@ -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]; diff --git a/SignalUtilitiesKit/Utilities/VersionMigrations.h b/SignalUtilitiesKit/Utilities/VersionMigrations.h index 7f6e8fcb0..932366703 100644 --- a/SignalUtilitiesKit/Utilities/VersionMigrations.h +++ b/SignalUtilitiesKit/Utilities/VersionMigrations.h @@ -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