mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
Merge remote-tracking branch 'upstream/dev' into dev
This commit is contained in:
commit
459502f1c3
63 changed files with 508 additions and 2594 deletions
|
@ -268,8 +268,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 */; };
|
||||
|
@ -353,8 +351,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 */; };
|
||||
|
@ -521,7 +517,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 */; };
|
||||
|
@ -577,20 +572,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 */; };
|
||||
|
@ -774,6 +763,8 @@
|
|||
F5765D284BC6ECAC0C1D33F0 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_SessionNotificationServiceExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4A93ECA93B3DE800CC7D7F6 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_SessionNotificationServiceExtension.framework */; };
|
||||
FC3BD9881A30A790005B96BB /* Social.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC3BD9871A30A790005B96BB /* Social.framework */; };
|
||||
FCB11D8C1A129A76002F93FB /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FCB11D8B1A129A76002F93FB /* CoreMedia.framework */; };
|
||||
FD28A4F227E990E800FF65E7 /* BlockingManagerRemovalMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD28A4F127E990E800FF65E7 /* BlockingManagerRemovalMigration.swift */; };
|
||||
FD28A4F427EA79F800FF65E7 /* BlockListUIUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD28A4F327EA79F800FF65E7 /* BlockListUIUtils.swift */; };
|
||||
FD3C907327E8387300CD579F /* OpenGroupServerIdLookupMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3C907227E8387300CD579F /* OpenGroupServerIdLookupMigration.swift */; };
|
||||
FD3C907527E83AC200CD579F /* OpenGroupServerIdLookup.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3C907427E83AC200CD579F /* OpenGroupServerIdLookup.swift */; };
|
||||
FD5D200F27AA2B6000FEA984 /* MessageRequestResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5D200E27AA2B6000FEA984 /* MessageRequestResponse.swift */; };
|
||||
|
@ -1292,8 +1283,6 @@
|
|||
B8EB20E6263F7E4B00773E52 /* sk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sk; path = sk.lproj/Localizable.strings; sourceTree = "<group>"; };
|
||||
B8EB20ED2640F28000773E52 /* VisibleMessage+OpenGroupInvitation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VisibleMessage+OpenGroupInvitation.swift"; sourceTree = "<group>"; };
|
||||
B8EB20EF2640F7F000773E52 /* OpenGroupInvitationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupInvitationView.swift; sourceTree = "<group>"; };
|
||||
B8F5F52725EC4F6A003BF8D4 /* BlockListUIUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BlockListUIUtils.h; sourceTree = "<group>"; };
|
||||
B8F5F52825EC4F8A003BF8D4 /* BlockListUIUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = BlockListUIUtils.m; sourceTree = "<group>"; };
|
||||
B8F5F56425EC8453003BF8D4 /* Notification+Contacts.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+Contacts.swift"; sourceTree = "<group>"; };
|
||||
B8F5F58225EC94A6003BF8D4 /* Collection+Subscripting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+Subscripting.swift"; sourceTree = "<group>"; };
|
||||
B8F5F60225EDE16F003BF8D4 /* DataExtractionNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataExtractionNotification.swift; sourceTree = "<group>"; };
|
||||
|
@ -1343,7 +1332,6 @@
|
|||
C33FD9AD255A548A00E217F9 /* SignalUtilitiesKit.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SignalUtilitiesKit.h; sourceTree = "<group>"; };
|
||||
C33FD9AE255A548A00E217F9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
C33FDA67255A57F900E217F9 /* OWSPrimaryStorage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSPrimaryStorage.h; sourceTree = "<group>"; };
|
||||
C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBlockingManager.m; sourceTree = "<group>"; };
|
||||
C33FDA69255A57F900E217F9 /* SSKPreferences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SSKPreferences.swift; sourceTree = "<group>"; };
|
||||
C33FDA6B255A57FA00E217F9 /* OWSDisappearingConfigurationUpdateInfoMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDisappearingConfigurationUpdateInfoMessage.m; sourceTree = "<group>"; };
|
||||
C33FDA6C255A57FA00E217F9 /* ProtoUtils.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ProtoUtils.m; sourceTree = "<group>"; };
|
||||
|
@ -1498,7 +1486,6 @@
|
|||
C33FDBDE255A581900E217F9 /* PushNotificationAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PushNotificationAPI.swift; sourceTree = "<group>"; };
|
||||
C33FDBE1255A581A00E217F9 /* LKGroupUtilities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = LKGroupUtilities.m; sourceTree = "<group>"; };
|
||||
C33FDBE9255A581A00E217F9 /* TSInteraction.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInteraction.m; sourceTree = "<group>"; };
|
||||
C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBlockingManager.h; sourceTree = "<group>"; };
|
||||
C33FDBEC255A581B00E217F9 /* OWSRecipientIdentity.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSRecipientIdentity.m; sourceTree = "<group>"; };
|
||||
C33FDBEF255A581B00E217F9 /* TSStorageKeys.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSStorageKeys.h; sourceTree = "<group>"; };
|
||||
C33FDBF1255A581B00E217F9 /* OWSIdentityManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSIdentityManager.h; sourceTree = "<group>"; };
|
||||
|
@ -1622,21 +1609,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; };
|
||||
|
@ -1819,6 +1799,8 @@
|
|||
F9BBF530D71905BA9007675F /* Pods-SessionShareExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionShareExtension.debug.xcconfig"; path = "Pods/Target Support Files/Pods-SessionShareExtension/Pods-SessionShareExtension.debug.xcconfig"; sourceTree = "<group>"; };
|
||||
FC3BD9871A30A790005B96BB /* Social.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Social.framework; path = System/Library/Frameworks/Social.framework; sourceTree = SDKROOT; };
|
||||
FCB11D8B1A129A76002F93FB /* CoreMedia.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreMedia.framework; path = System/Library/Frameworks/CoreMedia.framework; sourceTree = SDKROOT; };
|
||||
FD28A4F127E990E800FF65E7 /* BlockingManagerRemovalMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockingManagerRemovalMigration.swift; sourceTree = "<group>"; };
|
||||
FD28A4F327EA79F800FF65E7 /* BlockListUIUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockListUIUtils.swift; sourceTree = "<group>"; };
|
||||
FD3C907227E8387300CD579F /* OpenGroupServerIdLookupMigration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupServerIdLookupMigration.swift; sourceTree = "<group>"; };
|
||||
FD3C907427E83AC200CD579F /* OpenGroupServerIdLookup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupServerIdLookup.swift; sourceTree = "<group>"; };
|
||||
FD5D200E27AA2B6000FEA984 /* MessageRequestResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageRequestResponse.swift; sourceTree = "<group>"; };
|
||||
|
@ -2491,7 +2473,6 @@
|
|||
isa = PBXGroup;
|
||||
children = (
|
||||
C3D9E3B52567685D0040E4F3 /* Attachments */,
|
||||
C32C5B9E256DC720003C73A2 /* Blocking */,
|
||||
B8F5F61925EDE4B0003BF8D4 /* Data Extraction */,
|
||||
C32C5B01256DC054003C73A2 /* Expiration */,
|
||||
C32C5D22256DD496003C73A2 /* Link Previews */,
|
||||
|
@ -2657,15 +2638,6 @@
|
|||
path = Quotes;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C32C5B9E256DC720003C73A2 /* Blocking */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C33FDBEB255A581B00E217F9 /* OWSBlockingManager.h */,
|
||||
C33FDA68255A57F900E217F9 /* OWSBlockingManager.m */,
|
||||
);
|
||||
path = Blocking;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C32C5BB9256DC7C4003C73A2 /* To Do */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -2797,7 +2769,6 @@
|
|||
C36096EE25AD21BC008B62B2 /* Screen Lock */,
|
||||
C3851CD225624B060061EEB0 /* Shared Views */,
|
||||
C360970125AD22D3008B62B2 /* Shared View Controllers */,
|
||||
C36096F025AD227E008B62B2 /* Sharing */,
|
||||
C3851CE3256250FA0061EEB0 /* To Do */,
|
||||
C3CA3B11255CF17200F4C6D4 /* Utilities */,
|
||||
);
|
||||
|
@ -3027,19 +2998,6 @@
|
|||
path = "Profile Pictures";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C36096F025AD227E008B62B2 /* Sharing */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
C38EF34E255B6DC8007E1867 /* SelectRecipientViewController.h */,
|
||||
C38EF345255B6DC6007E1867 /* SelectRecipientViewController.m */,
|
||||
C38EF341255B6DC5007E1867 /* SelectThreadViewController.h */,
|
||||
C38EF342255B6DC5007E1867 /* SelectThreadViewController.m */,
|
||||
C38EF353255B6DCB007E1867 /* SharingThreadPickerViewController.h */,
|
||||
C38EF352255B6DC9007E1867 /* SharingThreadPickerViewController.m */,
|
||||
);
|
||||
path = Sharing;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
C360970125AD22D3008B62B2 /* Shared View Controllers */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -3070,6 +3028,7 @@
|
|||
B8B32044258C117C0020074B /* ContactsMigration.swift */,
|
||||
FD88BADA27A750F200BBC442 /* MessageRequestsMigration.swift */,
|
||||
FD3C907227E8387300CD579F /* OpenGroupServerIdLookupMigration.swift */,
|
||||
FD28A4F127E990E800FF65E7 /* BlockingManagerRemovalMigration.swift */,
|
||||
C38EF271255B6D79007E1867 /* OWSDatabaseMigration.h */,
|
||||
C38EF270255B6D79007E1867 /* OWSDatabaseMigration.m */,
|
||||
C38EF26F255B6D79007E1867 /* OWSDatabaseMigrationRunner.h */,
|
||||
|
@ -3159,8 +3118,7 @@
|
|||
C38BBA0D255E321C0041B9A3 /* Messaging */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B8F5F52725EC4F6A003BF8D4 /* BlockListUIUtils.h */,
|
||||
B8F5F52825EC4F8A003BF8D4 /* BlockListUIUtils.m */,
|
||||
FD28A4F327EA79F800FF65E7 /* BlockListUIUtils.swift */,
|
||||
C38EF2FC255B6DBD007E1867 /* ConversationStyle.swift */,
|
||||
C38EF3D4255B6DEE007E1867 /* DisappearingTimerConfigurationView.swift */,
|
||||
C33FDA72255A57FA00E217F9 /* OWSFailedAttachmentDownloadsJob.h */,
|
||||
|
@ -3168,7 +3126,6 @@
|
|||
C33FDADB255A580400E217F9 /* OWSFailedMessagesJob.h */,
|
||||
C33FDAB7255A580100E217F9 /* OWSFailedMessagesJob.m */,
|
||||
C38EF397255B6DD9007E1867 /* ThreadViewModel.swift */,
|
||||
C38EF30B255B6DBE007E1867 /* BlockListCache.swift */,
|
||||
C38EF2E4255B6DB9007E1867 /* FullTextSearcher.swift */,
|
||||
C38EF2E9255B6DBA007E1867 /* OWSUnreadIndicator.h */,
|
||||
C38EF2E3255B6DB9007E1867 /* OWSUnreadIndicator.m */,
|
||||
|
@ -3684,7 +3641,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 */,
|
||||
|
@ -3697,7 +3653,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 */,
|
||||
|
@ -3709,7 +3664,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 */,
|
||||
|
@ -3717,7 +3671,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;
|
||||
|
@ -3802,7 +3755,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 */,
|
||||
|
@ -4495,10 +4447,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 */,
|
||||
|
@ -4506,11 +4458,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 */,
|
||||
|
@ -4541,7 +4493,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 */,
|
||||
|
@ -4578,7 +4529,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 */,
|
||||
|
@ -4612,7 +4562,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 */,
|
||||
|
@ -4750,7 +4699,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 */,
|
||||
|
|
|
@ -58,7 +58,6 @@ NSString *NSStringForBackupImportState(OWSBackupState state)
|
|||
NSArray<NSString *> *MiscCollectionsToBackup(void)
|
||||
{
|
||||
return @[
|
||||
kOWSBlockingManager_BlockListCollection,
|
||||
OWSUserProfile.collection,
|
||||
SSKIncrementingIdFinder.collectionName,
|
||||
OWSPreferencesSignalDatabaseCollection,
|
||||
|
|
|
@ -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));
|
||||
}];
|
||||
});
|
||||
|
|
|
@ -174,8 +174,7 @@ final class NewClosedGroupVC : BaseVC, UITableViewDataSource, UITableViewDelegat
|
|||
promise = MessageSender.createClosedGroup(name: name, members: selectedContacts, transaction: transaction)
|
||||
}
|
||||
let _ = promise.done(on: DispatchQueue.main) { thread in
|
||||
let appDelegate = UIApplication.shared.delegate as! AppDelegate
|
||||
appDelegate.forceSyncConfigurationNowIfNeeded().retainUntilComplete() // FIXME: It's probably cleaner to do this inside createClosedGroup(...)
|
||||
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete()
|
||||
self?.presentingViewController?.dismiss(animated: true, completion: nil)
|
||||
SignalApp.shared().presentConversation(for: thread, action: .compose, animated: false)
|
||||
}
|
||||
|
|
|
@ -48,21 +48,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
|
||||
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)
|
||||
|
@ -1153,6 +1157,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
|
||||
|
@ -1186,11 +1193,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()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1227,6 +1229,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
|
||||
|
||||
|
@ -1244,24 +1252,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) {
|
||||
// Force a config sync and pop to the previous screen
|
||||
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete()
|
||||
|
||||
// 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 (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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -359,7 +359,7 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
|
|||
notificationCenter.addObserver(self, selector: #selector(handleKeyboardWillChangeFrameNotification(_:)), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
|
||||
notificationCenter.addObserver(self, selector: #selector(handleKeyboardWillHideNotification(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
|
||||
notificationCenter.addObserver(self, selector: #selector(handleAudioDidFinishPlayingNotification(_:)), name: .SNAudioDidFinishPlaying, object: nil)
|
||||
notificationCenter.addObserver(self, selector: #selector(addOrRemoveBlockedBanner), name: NSNotification.Name(rawValue: kNSNotificationName_BlockListDidChange), object: nil)
|
||||
notificationCenter.addObserver(self, selector: #selector(addOrRemoveBlockedBanner), name: .contactBlockedStateChanged, object: nil)
|
||||
notificationCenter.addObserver(self, selector: #selector(handleGroupUpdatedNotification), name: .groupThreadUpdated, object: nil)
|
||||
notificationCenter.addObserver(self, selector: #selector(sendScreenshotNotificationIfNeeded), name: UIApplication.userDidTakeScreenshotNotification, object: nil)
|
||||
notificationCenter.addObserver(self, selector: #selector(handleMessageSentStatusChanged), name: .messageSentStatusDidChange, object: nil)
|
||||
|
@ -722,10 +722,11 @@ final class ConversationVC : BaseVC, ConversationViewModelDelegate, OWSConversat
|
|||
blockedBanner.removeFromSuperview()
|
||||
}
|
||||
guard let thread = thread as? TSContactThread else { return detach() }
|
||||
if OWSBlockingManager.shared().isRecipientIdBlocked(thread.contactSessionID()) {
|
||||
if thread.isBlocked() {
|
||||
view.addSubview(blockedBanner)
|
||||
blockedBanner.pin([ UIView.HorizontalEdge.left, UIView.VerticalEdge.top, UIView.HorizontalEdge.right ], to: view)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
detach()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@
|
|||
#import <SignalCoreKit/NSDate+OWS.h>
|
||||
#import <SignalUtilitiesKit/OWSUnreadIndicator.h>
|
||||
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
|
||||
#import <SessionMessagingKit/OWSBlockingManager.h>
|
||||
#import <SessionMessagingKit/OWSPrimaryStorage.h>
|
||||
#import <SessionMessagingKit/SSKEnvironment.h>
|
||||
#import <SessionMessagingKit/TSDatabaseView.h>
|
||||
|
@ -247,11 +246,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return self.primaryStorage.dbReadWriteConnection;
|
||||
}
|
||||
|
||||
- (OWSBlockingManager *)blockingManager
|
||||
{
|
||||
return OWSBlockingManager.sharedManager;
|
||||
}
|
||||
|
||||
- (id<OWSTypingIndicators>)typingIndicators
|
||||
{
|
||||
return SSKEnvironment.shared.typingIndicators;
|
||||
|
@ -287,7 +281,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(blockListDidChange:)
|
||||
name:kNSNotificationName_BlockListDidChange
|
||||
name:NSNotification.contactBlockedStateChanged
|
||||
object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(localProfileDidChange:)
|
||||
|
@ -492,7 +486,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
ThreadDynamicInteractions *dynamicInteractions =
|
||||
[ThreadUtil ensureDynamicInteractionsForThread:self.thread
|
||||
blockingManager:self.blockingManager
|
||||
dbConnection:self.editingDatabaseConnection
|
||||
hideUnreadMessagesIndicator:self.hasClearedUnreadMessagesIndicator
|
||||
lastUnreadIndicator:self.dynamicInteractions.unreadIndicator
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
//
|
||||
|
||||
#import "OWSConversationSettingsViewController.h"
|
||||
#import "OWSBlockingManager.h"
|
||||
#import "OWSSoundSettingsViewController.h"
|
||||
#import "Session-Swift.h"
|
||||
#import "UIFont+OWS.h"
|
||||
|
@ -37,7 +36,6 @@ CGFloat kIconViewLength = 24;
|
|||
@property (nonatomic) NSArray<NSNumber *> *disappearingMessagesDurations;
|
||||
@property (nonatomic) OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration;
|
||||
@property (nullable, nonatomic) MediaGallery *mediaGallery;
|
||||
@property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper;
|
||||
@property (nonatomic, readonly) UIImageView *avatarView;
|
||||
@property (nonatomic, readonly) UILabel *disappearingMessagesDurationLabel;
|
||||
@property (nonatomic) UILabel *displayNameLabel;
|
||||
|
@ -107,11 +105,6 @@ CGFloat kIconViewLength = 24;
|
|||
return SSKEnvironment.shared.tsAccountManager;
|
||||
}
|
||||
|
||||
- (OWSBlockingManager *)blockingManager
|
||||
{
|
||||
return [OWSBlockingManager sharedManager];
|
||||
}
|
||||
|
||||
- (OWSProfileManager *)profileManager
|
||||
{
|
||||
return [OWSProfileManager sharedManager];
|
||||
|
@ -601,7 +594,7 @@ CGFloat kIconViewLength = 24;
|
|||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
|
||||
UISwitch *blockConversationSwitch = [UISwitch new];
|
||||
blockConversationSwitch.on = [strongSelf.blockingManager isThreadBlocked:strongSelf.thread];
|
||||
blockConversationSwitch.on = strongSelf.thread.isBlocked;
|
||||
[blockConversationSwitch addTarget:strongSelf action:@selector(blockConversationSwitchDidChange:)
|
||||
forControlEvents:UIControlEventValueChanged];
|
||||
cell.accessoryView = blockConversationSwitch;
|
||||
|
@ -868,9 +861,13 @@ CGFloat kIconViewLength = 24;
|
|||
if (![sender isKindOfClass:[UISwitch class]]) {
|
||||
OWSFailDebug(@"Unexpected sender for block user switch: %@", sender);
|
||||
}
|
||||
if (![self.thread isKindOfClass:[TSContactThread class]]) {
|
||||
OWSFailDebug(@"unexpected thread type: %@", self.thread.class);
|
||||
}
|
||||
UISwitch *blockConversationSwitch = (UISwitch *)sender;
|
||||
TSContactThread *contactThread = (TSContactThread *)self.thread;
|
||||
|
||||
BOOL isCurrentlyBlocked = [self.blockingManager isThreadBlocked:self.thread];
|
||||
BOOL isCurrentlyBlocked = contactThread.isBlocked;
|
||||
|
||||
__weak OWSConversationSettingsViewController *weakSelf = self;
|
||||
if (blockConversationSwitch.isOn) {
|
||||
|
@ -878,13 +875,17 @@ 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,13 +894,17 @@ 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];
|
||||
}];
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -72,8 +72,7 @@ final class JoinOpenGroupModal : Modal {
|
|||
Storage.shared.write { [presentingViewController = self.presentingViewController!] transaction in
|
||||
OpenGroupManagerV2.shared.add(room: room, server: server, publicKey: publicKey, using: transaction)
|
||||
.done(on: DispatchQueue.main) { _ in
|
||||
let appDelegate = UIApplication.shared.delegate as! AppDelegate
|
||||
appDelegate.forceSyncConfigurationNowIfNeeded().retainUntilComplete() // FIXME: It's probably cleaner to do this inside addOpenGroup(...)
|
||||
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete() // FIXME: It's probably cleaner to do this inside addOpenGroup(...)
|
||||
}
|
||||
.catch(on: DispatchQueue.main) { error in
|
||||
let alert = UIAlertController(title: "Couldn't Join", message: error.localizedDescription, preferredStyle: .alert)
|
||||
|
|
|
@ -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)
|
||||
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)
|
||||
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) ]
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
)
|
||||
})
|
||||
|
|
|
@ -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,12 +411,17 @@ 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];
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
func forceSyncConfigurationNowIfNeeded() -> Promise<Void> {
|
||||
let destination = Message.Destination.contact(publicKey: getUserHexEncodedPublicKey())
|
||||
let (promise, seal) = Promise<Void>.pending()
|
||||
|
||||
// Note: SQLite only supports a single write thread so we can be sure this will retrieve the most up-to-date data
|
||||
Storage.writeSync { transaction in
|
||||
guard Storage.shared.getUser(using: transaction)?.name != nil, let configurationMessage = ConfigurationMessage.getCurrent(with: transaction) else {
|
||||
seal.fulfill(())
|
||||
return
|
||||
}
|
||||
|
||||
MessageSender.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() {
|
||||
|
|
|
@ -144,8 +144,7 @@ final class JoinOpenGroupVC : BaseVC, UIPageViewControllerDataSource, UIPageView
|
|||
OpenGroupManagerV2.shared.add(room: room, server: server, publicKey: publicKey, using: transaction)
|
||||
.done(on: DispatchQueue.main) { [weak self] _ in
|
||||
self?.presentingViewController?.dismiss(animated: true, completion: nil)
|
||||
let appDelegate = UIApplication.shared.delegate as! AppDelegate
|
||||
appDelegate.forceSyncConfigurationNowIfNeeded().retainUntilComplete() // FIXME: It's probably cleaner to do this inside addOpenGroup(...)
|
||||
MessageSender.syncConfiguration(forceSyncNow: true).retainUntilComplete() // FIXME: It's probably cleaner to do this inside addOpenGroup(...)
|
||||
}
|
||||
.catch(on: DispatchQueue.main) { [weak self] error in
|
||||
self?.dismiss(animated: true, completion: nil) // Dismiss the loader
|
||||
|
|
|
@ -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.cachedEncodedPublicKey.mutate { $0 = nil } // Remove the cached key so it gets re-cached on next access
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import UIKit
|
||||
import SessionMessagingKit
|
||||
|
||||
final class SettingsVC : BaseVC, AvatarViewHelperDelegate {
|
||||
private var profilePictureToBeUploaded: UIImage?
|
||||
|
@ -367,8 +368,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 }
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -43,12 +43,18 @@ extension Storage {
|
|||
// Post notification
|
||||
let notificationCenter = NotificationCenter.default
|
||||
notificationCenter.post(name: .contactUpdated, object: contact.sessionID)
|
||||
|
||||
if contact.sessionID == getUserHexEncodedPublicKey() {
|
||||
notificationCenter.post(name: Notification.Name(kNSNotificationName_LocalProfileDidChange), object: nil)
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
let userInfo = [ kNSNotificationKey_ProfileRecipientId : contact.sessionID ]
|
||||
notificationCenter.post(name: Notification.Name(kNSNotificationName_OtherUsersProfileDidChange), object: nil, userInfo: userInfo)
|
||||
}
|
||||
|
||||
if contact.isBlocked != oldContact?.isBlocked {
|
||||
notificationCenter.post(name: .contactBlockedStateChanged, object: contact.sessionID)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
#import "TSIncomingMessage.h"
|
||||
#import "TSOutgoingMessage.h"
|
||||
#import "TSThread.h"
|
||||
#import "OWSBlockingManager.h"
|
||||
#import <YapDatabase/YapDatabaseAutoView.h>
|
||||
#import <YapDatabase/YapDatabaseCrossProcessNotification.h>
|
||||
#import <YapDatabase/YapDatabaseViewTypes.h>
|
||||
|
@ -264,7 +263,7 @@ NSString *const TSLazyRestoreAttachmentsGroup = @"TSLazyRestoreAttachmentsGroup"
|
|||
|
||||
if ([thread isMessageRequestUsingTransaction:transaction]) {
|
||||
// Don't show blocked threads at all
|
||||
if ([[OWSBlockingManager sharedManager] isThreadBlocked: thread]) {
|
||||
if (thread.isBlocked) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
)
|
||||
|
|
|
@ -10,7 +10,6 @@ FOUNDATION_EXPORT const unsigned char SessionMessagingKitVersionString[];
|
|||
#import <SessionMessagingKit/OWSAudioPlayer.h>
|
||||
#import <SessionMessagingKit/OWSBackgroundTask.h>
|
||||
#import <SessionMessagingKit/OWSBackupFragment.h>
|
||||
#import <SessionMessagingKit/OWSBlockingManager.h>
|
||||
#import <SessionMessagingKit/OWSDisappearingConfigurationUpdateInfoMessage.h>
|
||||
#import <SessionMessagingKit/OWSDisappearingMessagesConfiguration.h>
|
||||
#import <SessionMessagingKit/OWSDisappearingMessagesFinder.h>
|
||||
|
|
|
@ -1,49 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class OWSPrimaryStorage;
|
||||
@class TSGroupModel;
|
||||
@class TSThread;
|
||||
|
||||
extern NSString *const kNSNotificationName_BlockListDidChange;
|
||||
|
||||
extern NSString *const kOWSBlockingManager_BlockListCollection;
|
||||
|
||||
// This class can be safely accessed and used from any thread.
|
||||
@interface OWSBlockingManager : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
+ (instancetype)sharedManager;
|
||||
|
||||
- (void)addBlockedPhoneNumber:(NSString *)phoneNumber;
|
||||
|
||||
- (void)removeBlockedPhoneNumber:(NSString *)phoneNumber;
|
||||
|
||||
// When updating the block list from a sync message, we don't
|
||||
// want to fire a sync message.
|
||||
- (void)setBlockedPhoneNumbers:(NSArray<NSString *> *)blockedPhoneNumbers sendSyncMessage:(BOOL)sendSyncMessage;
|
||||
|
||||
// TODO convert to property
|
||||
- (NSArray<NSString *> *)blockedPhoneNumbers;
|
||||
|
||||
@property (readonly) NSArray<NSData *> *blockedGroupIds;
|
||||
@property (readonly) NSArray<TSGroupModel *> *blockedGroups;
|
||||
|
||||
- (void)addBlockedGroup:(TSGroupModel *)group;
|
||||
- (void)removeBlockedGroupId:(NSData *)groupId;
|
||||
- (nullable TSGroupModel *)cachedGroupDetailsWithGroupId:(NSData *)groupId;
|
||||
|
||||
- (BOOL)isRecipientIdBlocked:(NSString *)recipientId;
|
||||
- (BOOL)isGroupIdBlocked:(NSData *)groupId;
|
||||
- (BOOL)isThreadBlocked:(TSThread *)thread;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,348 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "OWSBlockingManager.h"
|
||||
#import "AppContext.h"
|
||||
#import "AppReadiness.h"
|
||||
#import "NSNotificationCenter+OWS.h"
|
||||
#import "OWSPrimaryStorage.h"
|
||||
#import "SSKEnvironment.h"
|
||||
#import "TSContactThread.h"
|
||||
#import "TSGroupThread.h"
|
||||
#import "YapDatabaseConnection+OWS.h"
|
||||
#import <SessionMessagingKit/SessionMessagingKit-Swift.h>
|
||||
#import <SessionUtilitiesKit/SessionUtilitiesKit-Swift.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NSString *const kNSNotificationName_BlockListDidChange = @"kNSNotificationName_BlockListDidChange";
|
||||
|
||||
NSString *const kOWSBlockingManager_BlockListCollection = @"kOWSBlockingManager_BlockedPhoneNumbersCollection";
|
||||
|
||||
// These keys are used to persist the current local "block list" state.
|
||||
NSString *const kOWSBlockingManager_BlockedPhoneNumbersKey = @"kOWSBlockingManager_BlockedPhoneNumbersKey";
|
||||
NSString *const kOWSBlockingManager_BlockedGroupMapKey = @"kOWSBlockingManager_BlockedGroupMapKey";
|
||||
|
||||
// These keys are used to persist the most recently synced remote "block list" state.
|
||||
NSString *const kOWSBlockingManager_SyncedBlockedPhoneNumbersKey = @"kOWSBlockingManager_SyncedBlockedPhoneNumbersKey";
|
||||
NSString *const kOWSBlockingManager_SyncedBlockedGroupIdsKey = @"kOWSBlockingManager_SyncedBlockedGroupIdsKey";
|
||||
|
||||
@interface OWSBlockingManager ()
|
||||
|
||||
@property (nonatomic, readonly) YapDatabaseConnection *dbConnection;
|
||||
|
||||
// We don't store the phone numbers as instances of PhoneNumber to avoid
|
||||
// consistency issues between clients, but these should all be valid e164
|
||||
// phone numbers.
|
||||
@property (atomic, readonly) NSMutableSet<NSString *> *blockedPhoneNumberSet;
|
||||
@property (atomic, readonly) NSMutableDictionary<NSData *, TSGroupModel *> *blockedGroupMap;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation OWSBlockingManager
|
||||
|
||||
+ (instancetype)sharedManager
|
||||
{
|
||||
return SSKEnvironment.shared.blockingManager;
|
||||
}
|
||||
|
||||
- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage
|
||||
{
|
||||
self = [super init];
|
||||
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
_dbConnection = primaryStorage.newDatabaseConnection;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self];
|
||||
}
|
||||
|
||||
- (void)observeNotifications
|
||||
{
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(applicationDidBecomeActive:)
|
||||
name:OWSApplicationDidBecomeActiveNotification
|
||||
object:nil];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (BOOL)isThreadBlocked:(TSThread *)thread
|
||||
{
|
||||
if ([thread isKindOfClass:[TSContactThread class]]) {
|
||||
TSContactThread *contactThread = (TSContactThread *)thread;
|
||||
return [self isRecipientIdBlocked:contactThread.contactSessionID];
|
||||
} else if ([thread isKindOfClass:[TSGroupThread class]]) {
|
||||
TSGroupThread *groupThread = (TSGroupThread *)thread;
|
||||
return [self isGroupIdBlocked:groupThread.groupModel.groupId];
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - Contact Blocking
|
||||
|
||||
- (void)addBlockedPhoneNumber:(NSString *)phoneNumber
|
||||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
[self ensureLazyInitialization];
|
||||
|
||||
if ([_blockedPhoneNumberSet containsObject:phoneNumber]) {
|
||||
// Ignore redundant changes.
|
||||
return;
|
||||
}
|
||||
|
||||
[_blockedPhoneNumberSet addObject:phoneNumber];
|
||||
}
|
||||
|
||||
[self handleUpdate];
|
||||
}
|
||||
|
||||
- (void)removeBlockedPhoneNumber:(NSString *)phoneNumber
|
||||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
[self ensureLazyInitialization];
|
||||
|
||||
if (![_blockedPhoneNumberSet containsObject:phoneNumber]) {
|
||||
// Ignore redundant changes.
|
||||
return;
|
||||
}
|
||||
|
||||
[_blockedPhoneNumberSet removeObject:phoneNumber];
|
||||
}
|
||||
|
||||
[self handleUpdate];
|
||||
}
|
||||
|
||||
- (void)setBlockedPhoneNumbers:(NSArray<NSString *> *)blockedPhoneNumbers sendSyncMessage:(BOOL)sendSyncMessage
|
||||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
[self ensureLazyInitialization];
|
||||
|
||||
NSSet *newSet = [NSSet setWithArray:blockedPhoneNumbers];
|
||||
if ([_blockedPhoneNumberSet isEqualToSet:newSet]) {
|
||||
return;
|
||||
}
|
||||
|
||||
_blockedPhoneNumberSet = [newSet mutableCopy];
|
||||
}
|
||||
|
||||
[self handleUpdate:sendSyncMessage];
|
||||
}
|
||||
|
||||
- (NSArray<NSString *> *)blockedPhoneNumbers
|
||||
{
|
||||
@synchronized(self)
|
||||
{
|
||||
[self ensureLazyInitialization];
|
||||
|
||||
return [_blockedPhoneNumberSet.allObjects sortedArrayUsingSelector:@selector(compare:)];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isRecipientIdBlocked:(NSString *)recipientId
|
||||
{
|
||||
return [self.blockedPhoneNumbers containsObject:recipientId];
|
||||
}
|
||||
|
||||
#pragma mark - Group Blocking
|
||||
|
||||
- (NSArray<NSData *> *)blockedGroupIds
|
||||
{
|
||||
@synchronized(self) {
|
||||
[self ensureLazyInitialization];
|
||||
return self.blockedGroupMap.allKeys;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSArray<TSGroupModel *> *)blockedGroups
|
||||
{
|
||||
@synchronized(self) {
|
||||
[self ensureLazyInitialization];
|
||||
return self.blockedGroupMap.allValues;
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)isGroupIdBlocked:(NSData *)groupId
|
||||
{
|
||||
return self.blockedGroupMap[groupId] != nil;
|
||||
}
|
||||
|
||||
- (nullable TSGroupModel *)cachedGroupDetailsWithGroupId:(NSData *)groupId
|
||||
{
|
||||
@synchronized(self) {
|
||||
return self.blockedGroupMap[groupId];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)addBlockedGroup:(TSGroupModel *)groupModel
|
||||
{
|
||||
NSData *groupId = groupModel.groupId;
|
||||
|
||||
@synchronized(self) {
|
||||
[self ensureLazyInitialization];
|
||||
|
||||
if ([self isGroupIdBlocked:groupId]) {
|
||||
// Ignore redundant changes.
|
||||
return;
|
||||
}
|
||||
self.blockedGroupMap[groupId] = groupModel;
|
||||
}
|
||||
|
||||
[self handleUpdate];
|
||||
}
|
||||
|
||||
- (void)removeBlockedGroupId:(NSData *)groupId
|
||||
{
|
||||
@synchronized(self) {
|
||||
[self ensureLazyInitialization];
|
||||
|
||||
if (![self isGroupIdBlocked:groupId]) {
|
||||
// Ignore redundant changes.
|
||||
return;
|
||||
}
|
||||
|
||||
[self.blockedGroupMap removeObjectForKey:groupId];
|
||||
}
|
||||
|
||||
[self handleUpdate];
|
||||
}
|
||||
|
||||
|
||||
#pragma mark - Updates
|
||||
|
||||
// This should be called every time the block list changes.
|
||||
|
||||
- (void)handleUpdate
|
||||
{
|
||||
// By default, always send a sync message when the block list changes.
|
||||
[self handleUpdate:YES];
|
||||
}
|
||||
|
||||
// TODO label the `sendSyncMessage` param
|
||||
- (void)handleUpdate:(BOOL)sendSyncMessage
|
||||
{
|
||||
NSArray<NSString *> *blockedPhoneNumbers = [self blockedPhoneNumbers];
|
||||
|
||||
[self.dbConnection setObject:blockedPhoneNumbers
|
||||
forKey:kOWSBlockingManager_BlockedPhoneNumbersKey
|
||||
inCollection:kOWSBlockingManager_BlockListCollection];
|
||||
|
||||
NSDictionary *blockedGroupMap;
|
||||
@synchronized(self) {
|
||||
blockedGroupMap = [self.blockedGroupMap copy];
|
||||
}
|
||||
NSArray<NSData *> *blockedGroupIds = blockedGroupMap.allKeys;
|
||||
|
||||
[self.dbConnection setObject:blockedGroupMap
|
||||
forKey:kOWSBlockingManager_BlockedGroupMapKey
|
||||
inCollection:kOWSBlockingManager_BlockListCollection];
|
||||
|
||||
// Update the contact blocked state (so sync'ing won't be busted)
|
||||
NSMutableArray<SNContact *> *contactsToUpdate = [[NSMutableArray alloc] init];
|
||||
|
||||
[[[LKStorage shared] getAllContacts] enumerateObjectsUsingBlock:^(SNContact * _Nonnull obj, BOOL * _Nonnull stop) {
|
||||
// If the blocked flag doesn't match then add it to the array to be saved
|
||||
BOOL contactInBlockedList = [blockedPhoneNumbers containsObject:obj.sessionID];
|
||||
|
||||
if (obj.isBlocked != contactInBlockedList) {
|
||||
obj.isBlocked = contactInBlockedList;
|
||||
[contactsToUpdate addObject:obj];
|
||||
}
|
||||
}];
|
||||
|
||||
if ([contactsToUpdate count] > 0) {
|
||||
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction * _Nonnull transaction) {
|
||||
[contactsToUpdate enumerateObjectsUsingBlock:^(SNContact * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
|
||||
[[LKStorage shared] setContact:obj usingTransaction:transaction];
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
if (sendSyncMessage) {
|
||||
|
||||
} else {
|
||||
// If this update came from an incoming block list sync message,
|
||||
// update the "synced blocked list" state immediately,
|
||||
// since we're now in sync.
|
||||
//
|
||||
// There could be data loss if both clients modify the block list
|
||||
// at the same time, but:
|
||||
//
|
||||
// a) Block list changes will be rare.
|
||||
// b) Conflicting block list changes will be even rarer.
|
||||
// c) It's unlikely a user will make conflicting changes on two
|
||||
// devices around the same time.
|
||||
// d) There isn't a good way to avoid this.
|
||||
[self saveSyncedBlockListWithPhoneNumbers:blockedPhoneNumbers groupIds:blockedGroupIds];
|
||||
}
|
||||
|
||||
[[NSNotificationCenter defaultCenter] postNotificationNameAsync:kNSNotificationName_BlockListDidChange
|
||||
object:nil
|
||||
userInfo:nil];
|
||||
});
|
||||
}
|
||||
|
||||
// This method should only be called from within a synchronized block.
|
||||
- (void)ensureLazyInitialization
|
||||
{
|
||||
if (_blockedPhoneNumberSet) {
|
||||
|
||||
// already loaded
|
||||
return;
|
||||
}
|
||||
|
||||
NSArray<NSString *> *blockedPhoneNumbers =
|
||||
[self.dbConnection objectForKey:kOWSBlockingManager_BlockedPhoneNumbersKey
|
||||
inCollection:kOWSBlockingManager_BlockListCollection];
|
||||
_blockedPhoneNumberSet = [[NSMutableSet alloc] initWithArray:(blockedPhoneNumbers ?: [NSArray new])];
|
||||
|
||||
NSDictionary<NSData *, TSGroupModel *> *storedBlockedGroupMap =
|
||||
[self.dbConnection objectForKey:kOWSBlockingManager_BlockedGroupMapKey
|
||||
inCollection:kOWSBlockingManager_BlockListCollection];
|
||||
if ([storedBlockedGroupMap isKindOfClass:[NSDictionary class]]) {
|
||||
_blockedGroupMap = [storedBlockedGroupMap mutableCopy];
|
||||
} else {
|
||||
_blockedGroupMap = [NSMutableDictionary new];
|
||||
}
|
||||
|
||||
[self observeNotifications];
|
||||
}
|
||||
|
||||
/// Records the last block list which we successfully synced.
|
||||
- (void)saveSyncedBlockListWithPhoneNumbers:(NSArray<NSString *> *)blockedPhoneNumbers
|
||||
groupIds:(NSArray<NSData *> *)blockedGroupIds
|
||||
{
|
||||
[self.dbConnection setObject:blockedPhoneNumbers
|
||||
forKey:kOWSBlockingManager_SyncedBlockedPhoneNumbersKey
|
||||
inCollection:kOWSBlockingManager_BlockListCollection];
|
||||
|
||||
[self.dbConnection setObject:blockedGroupIds
|
||||
forKey:kOWSBlockingManager_SyncedBlockedGroupIdsKey
|
||||
inCollection:kOWSBlockingManager_BlockListCollection];
|
||||
}
|
||||
|
||||
#pragma mark - Notifications
|
||||
|
||||
- (void)applicationDidBecomeActive:(NSNotification *)notification
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -3,10 +3,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) throws {
|
||||
switch message {
|
||||
case let message as ReadReceipt: handleReadReceipt(message, using: transaction)
|
||||
|
@ -212,6 +208,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
|
||||
|
@ -237,7 +234,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)
|
||||
{
|
||||
|
@ -247,22 +244,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
|
||||
|
@ -833,23 +814,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) {
|
||||
|
|
|
@ -106,8 +106,12 @@ public enum MessageReceiver {
|
|||
default: throw Error.unknownEnvelopeType
|
||||
}
|
||||
}
|
||||
|
||||
// Don't process the envelope any further if the sender is blocked
|
||||
guard !isBlocked(sender) else { throw Error.senderBlocked }
|
||||
guard Storage.shared.getContact(with: sender, using: transaction)?.isBlocked != true else {
|
||||
throw Error.senderBlocked
|
||||
}
|
||||
|
||||
// Parse the proto
|
||||
let proto: SNProtoContent
|
||||
do {
|
||||
|
|
|
@ -83,6 +83,20 @@ NSString *const TSContactThreadPrefix = @"c";
|
|||
);
|
||||
}
|
||||
|
||||
- (BOOL)isBlocked {
|
||||
NSString *sessionID = self.contactSessionID;
|
||||
SNContact *contact = [LKStorage.shared getContactWithSessionID:sessionID];
|
||||
|
||||
return (contact.isBlocked == YES);
|
||||
}
|
||||
|
||||
- (BOOL)isBlockedUsingTransaction:(YapDatabaseReadTransaction *)transaction {
|
||||
NSString *sessionID = self.contactSessionID;
|
||||
SNContact *contact = [LKStorage.shared getContactWithSessionID:sessionID using:transaction];
|
||||
|
||||
return (contact.isBlocked == YES);
|
||||
}
|
||||
|
||||
- (BOOL)isGroupThread
|
||||
{
|
||||
return NO;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -11,7 +11,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@class OWS2FAManager;
|
||||
@class OWSAttachmentDownloads;
|
||||
@class OWSBatchMessageProcessor;
|
||||
@class OWSBlockingManager;
|
||||
@class OWSDisappearingMessagesJob;
|
||||
@class OWSIdentityManager;
|
||||
@class OWSMessageDecrypter;
|
||||
|
@ -39,7 +38,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)initWithProfileManager:(id<ProfileManagerProtocol>)profileManager
|
||||
primaryStorage:(OWSPrimaryStorage *)primaryStorage
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
identityManager:(OWSIdentityManager *)identityManager
|
||||
tsAccountManager:(TSAccountManager *)tsAccountManager
|
||||
disappearingMessagesJob:(OWSDisappearingMessagesJob *)disappearingMessagesJob
|
||||
|
@ -61,7 +59,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@property (nonatomic, readonly) id<ProfileManagerProtocol> profileManager;
|
||||
@property (nonatomic, readonly) OWSPrimaryStorage *primaryStorage;
|
||||
@property (nonatomic, readonly) OWSBlockingManager *blockingManager;
|
||||
@property (nonatomic, readonly) OWSIdentityManager *identityManager;
|
||||
@property (nonatomic, readonly) TSAccountManager *tsAccountManager;
|
||||
@property (nonatomic, readonly) OWSDisappearingMessagesJob *disappearingMessagesJob;
|
||||
|
|
|
@ -14,7 +14,6 @@ static SSKEnvironment *sharedSSKEnvironment;
|
|||
|
||||
@property (nonatomic) id<ProfileManagerProtocol> profileManager;
|
||||
@property (nonatomic) OWSPrimaryStorage *primaryStorage;
|
||||
@property (nonatomic) OWSBlockingManager *blockingManager;
|
||||
@property (nonatomic) OWSIdentityManager *identityManager;
|
||||
@property (nonatomic) TSAccountManager *tsAccountManager;
|
||||
@property (nonatomic) OWSDisappearingMessagesJob *disappearingMessagesJob;
|
||||
|
@ -37,7 +36,6 @@ static SSKEnvironment *sharedSSKEnvironment;
|
|||
|
||||
- (instancetype)initWithProfileManager:(id<ProfileManagerProtocol>)profileManager
|
||||
primaryStorage:(OWSPrimaryStorage *)primaryStorage
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
identityManager:(OWSIdentityManager *)identityManager
|
||||
tsAccountManager:(TSAccountManager *)tsAccountManager
|
||||
disappearingMessagesJob:(OWSDisappearingMessagesJob *)disappearingMessagesJob
|
||||
|
@ -54,7 +52,6 @@ static SSKEnvironment *sharedSSKEnvironment;
|
|||
|
||||
_profileManager = profileManager;
|
||||
_primaryStorage = primaryStorage;
|
||||
_blockingManager = blockingManager;
|
||||
_identityManager = identityManager;
|
||||
_tsAccountManager = tsAccountManager;
|
||||
_disappearingMessagesJob = disappearingMessagesJob;
|
||||
|
|
|
@ -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,11 +119,16 @@ 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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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,13 +72,18 @@ 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()
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,47 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc(SNBlockingManagerRemovalMigration)
|
||||
public class BlockingManagerRemovalMigration: OWSDatabaseMigration {
|
||||
@objc
|
||||
class func migrationId() -> String {
|
||||
return "004"
|
||||
}
|
||||
|
||||
override public func runUp(completion: @escaping OWSDatabaseMigrationCompletion) {
|
||||
self.doMigrationAsync(completion: completion)
|
||||
}
|
||||
|
||||
private func doMigrationAsync(completion: @escaping OWSDatabaseMigrationCompletion) {
|
||||
// These are the legacy keys that were used to persist the "block list" state
|
||||
let kOWSBlockingManager_BlockListCollection: String = "kOWSBlockingManager_BlockedPhoneNumbersCollection"
|
||||
let kOWSBlockingManager_BlockedPhoneNumbersKey: String = "kOWSBlockingManager_BlockedPhoneNumbersKey"
|
||||
|
||||
let dbConnection: YapDatabaseConnection = primaryStorage.newDatabaseConnection()
|
||||
|
||||
let blockedSessionIds: Set<String> = Set(dbConnection.object(
|
||||
forKey: kOWSBlockingManager_BlockedPhoneNumbersKey,
|
||||
inCollection: kOWSBlockingManager_BlockListCollection
|
||||
) as? [String] ?? [])
|
||||
|
||||
Storage.write(
|
||||
with: { transaction in
|
||||
Storage.shared.getAllContacts(with: transaction)
|
||||
.filter { contact -> Bool in blockedSessionIds.contains(contact.sessionID) }
|
||||
.forEach { contact in
|
||||
contact.isBlocked = true
|
||||
Storage.shared.setContact(contact, using: transaction)
|
||||
}
|
||||
|
||||
// Now that the values have been migrated we can clear out the old collection
|
||||
transaction.removeAllObjects(inCollection: kOWSBlockingManager_BlockListCollection)
|
||||
|
||||
self.save(with: transaction) // Intentionally capture self
|
||||
},
|
||||
completion: {
|
||||
completion(true, true)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
|
@ -27,7 +27,7 @@ public class ContactsMigration : OWSDatabaseMigration {
|
|||
}
|
||||
self.save(with: transaction) // Intentionally capture self
|
||||
}, completion: {
|
||||
completion()
|
||||
completion(true, false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ public class MessageRequestsMigration : OWSDatabaseMigration {
|
|||
}
|
||||
self.save(with: transaction) // Intentionally capture self
|
||||
}, completion: {
|
||||
completion()
|
||||
completion(true, true)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void (^OWSDatabaseMigrationCompletion)(void);
|
||||
typedef void (^OWSDatabaseMigrationCompletion)(BOOL success, BOOL requiresConfigurationSync);
|
||||
|
||||
@class OWSPrimaryStorage;
|
||||
|
||||
|
|
|
@ -76,7 +76,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSLogInfo(@"Completed migration %@", self.uniqueId);
|
||||
[self save];
|
||||
|
||||
completion();
|
||||
completion(true, false);
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void (^OWSDatabaseMigrationCompletion)(void);
|
||||
typedef void (^OWSDatabaseMigrationCompletion)(BOOL success, BOOL requiresConfigurationSync);
|
||||
|
||||
@interface OWSDatabaseMigrationRunner : NSObject
|
||||
|
||||
|
|
|
@ -28,7 +28,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
return @[
|
||||
[SNOpenGroupServerIdLookupMigration new],
|
||||
[SNMessageRequestsMigration new],
|
||||
[SNContactsMigration new]
|
||||
[SNContactsMigration new],
|
||||
[SNBlockingManagerRemovalMigration new]
|
||||
];
|
||||
}
|
||||
|
||||
|
@ -44,7 +45,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
{
|
||||
[self removeUnknownMigrations];
|
||||
|
||||
[self runMigrations:[self.allMigrations mutableCopy] completion:completion];
|
||||
[self runMigrations:[self.allMigrations mutableCopy]
|
||||
prevWasSuccessful: true
|
||||
prevNeedsConfigSync:false
|
||||
completion:completion];
|
||||
}
|
||||
|
||||
// Some users (especially internal users) will move back and forth between
|
||||
|
@ -77,6 +81,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
// * Ensure predictable ordering.
|
||||
// * Prevent them from interfering with each other (e.g. deadlock).
|
||||
- (void)runMigrations:(NSMutableArray<OWSDatabaseMigration *> *)migrations
|
||||
prevWasSuccessful:(BOOL)prevWasSuccessful
|
||||
prevNeedsConfigSync:(BOOL)prevNeedsConfigSync
|
||||
completion:(OWSDatabaseMigrationCompletion)completion
|
||||
{
|
||||
OWSAssertDebug(migrations);
|
||||
|
@ -85,7 +91,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
// If there are no more migrations to run, complete.
|
||||
if (migrations.count < 1) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
completion();
|
||||
completion(prevWasSuccessful, prevNeedsConfigSync);
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
@ -96,14 +102,20 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
// If migration has already been run, skip it.
|
||||
if ([OWSDatabaseMigration fetchObjectWithUniqueID:migration.uniqueId] != nil) {
|
||||
[self runMigrations:migrations completion:completion];
|
||||
[self runMigrations:migrations
|
||||
prevWasSuccessful:prevWasSuccessful
|
||||
prevNeedsConfigSync:prevNeedsConfigSync
|
||||
completion:completion];
|
||||
return;
|
||||
}
|
||||
|
||||
OWSLogInfo(@"Running migration: %@", migration);
|
||||
[migration runUpWithCompletion:^{
|
||||
[migration runUpWithCompletion:^(BOOL successful, BOOL needsConfigSync){
|
||||
OWSLogInfo(@"Migration complete: %@", migration);
|
||||
[self runMigrations:migrations completion:completion];
|
||||
[self runMigrations:migrations
|
||||
prevWasSuccessful:(prevWasSuccessful && successful)
|
||||
prevNeedsConfigSync:(prevNeedsConfigSync || needsConfigSync)
|
||||
completion:completion];
|
||||
}];
|
||||
}
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSLogVerbose(@"%lu", (unsigned long)recordIds.count);
|
||||
|
||||
if (recordIds.count < 1) {
|
||||
completion();
|
||||
completion(true, false);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -42,7 +42,7 @@ public class OpenGroupServerIdLookupMigration: OWSDatabaseMigration {
|
|||
}
|
||||
self.save(with: transaction) // Intentionally capture self
|
||||
}, completion: {
|
||||
completion()
|
||||
completion(true, false)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,122 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
@objc(OWSBlockListCacheDelegate)
|
||||
public protocol BlockListCacheDelegate: class {
|
||||
func blockListCacheDidUpdate(_ blocklistCache: BlockListCache)
|
||||
}
|
||||
|
||||
/// A performant cache for which contacts/groups are blocked.
|
||||
///
|
||||
/// The source of truth for which contacts and groups are blocked is the `blockingManager`, but because
|
||||
/// those accessors are made to be thread safe, they can be slow in tight loops, e.g. when rendering table
|
||||
/// view cells.
|
||||
///
|
||||
/// Typically you'll want to create a Cache, update it to the latest state while simultaneously being informed
|
||||
/// of any future changes to block list state.
|
||||
///
|
||||
/// class SomeViewController: BlockListCacheDelegate {
|
||||
/// let blockListCache = BlockListCache()
|
||||
/// func viewDidLoad() {
|
||||
/// super.viewDidLoad()
|
||||
/// blockListCache.startObservingAndSyncState(delegate: self)
|
||||
/// self.updateAnyViewsWhichDepondOnBlockListCache()
|
||||
/// }
|
||||
///
|
||||
/// func blockListCacheDidUpdate(_ blocklistCache: BlockListCache) {
|
||||
/// self.updateAnyViewsWhichDepondOnBlockListCache()
|
||||
/// }
|
||||
///
|
||||
/// ...
|
||||
/// }
|
||||
///
|
||||
@objc(OWSBlockListCache)
|
||||
public class BlockListCache: NSObject {
|
||||
|
||||
private var blockedRecipientIds: Set<String> = Set()
|
||||
private var blockedGroupIds: Set<Data> = Set()
|
||||
private let serialQueue: DispatchQueue = DispatchQueue(label: "BlockListCache")
|
||||
weak var delegate: BlockListCacheDelegate?
|
||||
|
||||
private var blockingManager: OWSBlockingManager {
|
||||
return OWSBlockingManager.shared()
|
||||
}
|
||||
|
||||
/// Generally something which wants to use this cache wants to do 3 things
|
||||
/// 1. get the cache on the latest state
|
||||
/// 2. update the cache whenever the blockingManager's state changes
|
||||
/// 3. be notified when the cache updates
|
||||
/// This method does all three.
|
||||
@objc
|
||||
public func startObservingAndSyncState(delegate: BlockListCacheDelegate) {
|
||||
self.delegate = delegate
|
||||
NotificationCenter.default.addObserver(self,
|
||||
selector: #selector(blockListDidChange),
|
||||
name: NSNotification.Name(rawValue: kNSNotificationName_BlockListDidChange),
|
||||
object: nil)
|
||||
updateWithoutNotifyingDelegate()
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
@objc
|
||||
func blockListDidChange() {
|
||||
self.update()
|
||||
}
|
||||
|
||||
@objc(isRecipientIdBlocked:)
|
||||
public func isBlocked(recipientId: String) -> Bool {
|
||||
return serialQueue.sync {
|
||||
blockedRecipientIds.contains(recipientId)
|
||||
}
|
||||
}
|
||||
|
||||
@objc(isGroupIdBlocked:)
|
||||
public func isBlocked(groupId: Data) -> Bool {
|
||||
return serialQueue.sync {
|
||||
blockedGroupIds.contains(groupId)
|
||||
}
|
||||
}
|
||||
|
||||
@objc(isThreadBlocked:)
|
||||
public func isBlocked(thread: TSThread) -> Bool {
|
||||
switch thread {
|
||||
case let contactThread as TSContactThread:
|
||||
return serialQueue.sync {
|
||||
blockedRecipientIds.contains(contactThread.contactSessionID())
|
||||
}
|
||||
case let groupThread as TSGroupThread:
|
||||
return serialQueue.sync {
|
||||
blockedGroupIds.contains(groupThread.groupModel.groupId)
|
||||
}
|
||||
default:
|
||||
owsFailDebug("\(self.logTag) in \(#function) unexpected thread type: \(type(of: thread))")
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: -
|
||||
|
||||
public func update() {
|
||||
updateWithoutNotifyingDelegate()
|
||||
DispatchQueue.main.async {
|
||||
self.delegate?.blockListCacheDidUpdate(self)
|
||||
}
|
||||
}
|
||||
|
||||
private func updateWithoutNotifyingDelegate() {
|
||||
let blockedRecipientIds = Set(blockingManager.blockedPhoneNumbers())
|
||||
let blockedGroupIds = Set(blockingManager.blockedGroupIds)
|
||||
update(blockedRecipientIds: blockedRecipientIds, blockedGroupIds: blockedGroupIds)
|
||||
}
|
||||
|
||||
private func update(blockedRecipientIds: Set<String>, blockedGroupIds: Set<Data>) {
|
||||
serialQueue.sync {
|
||||
self.blockedRecipientIds = blockedRecipientIds
|
||||
self.blockedGroupIds = blockedGroupIds
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class Contact;
|
||||
@class OWSBlockingManager;
|
||||
@class SignalAccount;
|
||||
@class TSGroupModel;
|
||||
@class TSThread;
|
||||
|
||||
typedef void (^BlockActionCompletionBlock)(BOOL isBlocked);
|
||||
|
||||
@interface BlockListUIUtils : NSObject
|
||||
|
||||
- (instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
#pragma mark - Block
|
||||
|
||||
+ (void)showBlockThreadActionSheet:(TSThread *)thread
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
|
||||
|
||||
+ (void)showBlockPhoneNumberActionSheet:(NSString *)phoneNumber
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
|
||||
|
||||
+ (void)showBlockSignalAccountActionSheet:(SignalAccount *)signalAccount
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
|
||||
|
||||
#pragma mark - Unblock
|
||||
|
||||
+ (void)showUnblockThreadActionSheet:(TSThread *)thread
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
|
||||
|
||||
+ (void)showUnblockPhoneNumberActionSheet:(NSString *)phoneNumber
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
|
||||
|
||||
+ (void)showUnblockSignalAccountActionSheet:(SignalAccount *)signalAccount
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
|
||||
|
||||
+ (void)showUnblockGroupActionSheet:(TSGroupModel *)groupModel
|
||||
displayName:(NSString *)displayName
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock;
|
||||
|
||||
#pragma mark - UI Utils
|
||||
|
||||
+ (NSString *)formatDisplayNameForAlertTitle:(NSString *)displayName;
|
||||
+ (NSString *)formatDisplayNameForAlertMessage:(NSString *)displayName;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,494 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "BlockListUIUtils.h"
|
||||
#import "TSContactThread.h"
|
||||
#import <SessionMessagingKit/OWSBlockingManager.h>
|
||||
#import <SignalUtilitiesKit/SignalAccount.h>
|
||||
#import <SessionMessagingKit/TSAccountManager.h>
|
||||
#import <SessionMessagingKit/TSGroupThread.h>
|
||||
#import <SignalUtilitiesKit/UIUtil.h>
|
||||
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
|
||||
#import "UIView+OWS.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void (^BlockAlertCompletionBlock)(UIAlertAction *action);
|
||||
|
||||
@implementation BlockListUIUtils
|
||||
|
||||
#pragma mark - Block
|
||||
|
||||
+ (void)showBlockThreadActionSheet:(TSThread *)thread
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
|
||||
{
|
||||
if ([thread isKindOfClass:[TSContactThread class]]) {
|
||||
TSContactThread *contactThread = (TSContactThread *)thread;
|
||||
[self showBlockPhoneNumberActionSheet:contactThread.contactSessionID
|
||||
fromViewController:fromViewController
|
||||
blockingManager:blockingManager
|
||||
completionBlock:completionBlock];
|
||||
} else if ([thread isKindOfClass:[TSGroupThread class]]) {
|
||||
TSGroupThread *groupThread = (TSGroupThread *)thread;
|
||||
[self showBlockGroupActionSheet:groupThread
|
||||
fromViewController:fromViewController
|
||||
blockingManager:blockingManager
|
||||
completionBlock:completionBlock];
|
||||
} else {
|
||||
OWSFailDebug(@"unexpected thread type: %@", thread.class);
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)showBlockPhoneNumberActionSheet:(NSString *)phoneNumber
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
|
||||
{
|
||||
NSString *displayName = [[LKStorage.shared getContactWithSessionID:phoneNumber] displayNameFor:SNContactContextRegular] ?: phoneNumber;
|
||||
[self showBlockPhoneNumbersActionSheet:@[ phoneNumber ]
|
||||
displayName:displayName
|
||||
fromViewController:fromViewController
|
||||
blockingManager:blockingManager
|
||||
completionBlock:completionBlock];
|
||||
}
|
||||
|
||||
+ (void)showBlockSignalAccountActionSheet:(SignalAccount *)signalAccount
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
|
||||
{
|
||||
NSString *displayName = [[LKStorage.shared getContactWithSessionID:signalAccount.recipientId] displayNameFor:SNContactContextRegular] ?: signalAccount.recipientId;
|
||||
[self showBlockPhoneNumbersActionSheet:@[ signalAccount.recipientId ]
|
||||
displayName:displayName
|
||||
fromViewController:fromViewController
|
||||
blockingManager:blockingManager
|
||||
completionBlock:completionBlock];
|
||||
}
|
||||
|
||||
+ (void)showBlockPhoneNumbersActionSheet:(NSArray<NSString *> *)phoneNumbers
|
||||
displayName:(NSString *)displayName
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
|
||||
{
|
||||
OWSAssertDebug(phoneNumbers.count > 0);
|
||||
OWSAssertDebug(displayName.length > 0);
|
||||
OWSAssertDebug(fromViewController);
|
||||
OWSAssertDebug(blockingManager);
|
||||
|
||||
NSString *localContactId = [TSAccountManager localNumber];
|
||||
OWSAssertDebug(localContactId.length > 0);
|
||||
for (NSString *phoneNumber in phoneNumbers) {
|
||||
OWSAssertDebug(phoneNumber.length > 0);
|
||||
|
||||
if ([localContactId isEqualToString:phoneNumber]) {
|
||||
[self showOkAlertWithTitle:NSLocalizedString(@"BLOCK_LIST_VIEW_CANT_BLOCK_SELF_ALERT_TITLE",
|
||||
@"The title of the 'You can't block yourself' alert.")
|
||||
message:NSLocalizedString(@"BLOCK_LIST_VIEW_CANT_BLOCK_SELF_ALERT_MESSAGE",
|
||||
@"The message of the 'You can't block yourself' alert.")
|
||||
fromViewController:fromViewController
|
||||
completionBlock:^(UIAlertAction *action) {
|
||||
if (completionBlock) {
|
||||
completionBlock(NO);
|
||||
}
|
||||
}];
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
NSString *title = [NSString stringWithFormat:NSLocalizedString(@"BLOCK_LIST_BLOCK_USER_TITLE_FORMAT",
|
||||
@"A format for the 'block user' action sheet title. Embeds {{the "
|
||||
@"blocked user's name or phone number}}."),
|
||||
[self formatDisplayNameForAlertTitle:displayName]];
|
||||
|
||||
UIAlertController *actionSheet =
|
||||
[UIAlertController alertControllerWithTitle:title
|
||||
message:NSLocalizedString(@"BLOCK_USER_BEHAVIOR_EXPLANATION",
|
||||
@"An explanation of the consequences of blocking another user.")
|
||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
UIAlertAction *blockAction = [UIAlertAction
|
||||
actionWithTitle:NSLocalizedString(@"BLOCK_LIST_BLOCK_BUTTON", @"Button label for the 'block' button")
|
||||
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"block")
|
||||
style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
[self blockPhoneNumbers:phoneNumbers
|
||||
displayName:displayName
|
||||
fromViewController:fromViewController
|
||||
blockingManager:blockingManager
|
||||
completionBlock:^(UIAlertAction *ignore) {
|
||||
if (completionBlock) {
|
||||
completionBlock(YES);
|
||||
}
|
||||
}];
|
||||
}];
|
||||
[actionSheet addAction:blockAction];
|
||||
|
||||
UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:CommonStrings.cancelButton
|
||||
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"dismiss")
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
if (completionBlock) {
|
||||
completionBlock(NO);
|
||||
}
|
||||
}];
|
||||
[actionSheet addAction:dismissAction];
|
||||
[fromViewController presentAlert:actionSheet];
|
||||
}
|
||||
|
||||
+ (void)showBlockGroupActionSheet:(TSGroupThread *)groupThread
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
|
||||
{
|
||||
OWSAssertDebug(groupThread);
|
||||
OWSAssertDebug(fromViewController);
|
||||
OWSAssertDebug(blockingManager);
|
||||
|
||||
NSString *groupName = groupThread.name.length > 0 ? groupThread.name : TSGroupThread.defaultGroupName;
|
||||
NSString *title = [NSString
|
||||
stringWithFormat:NSLocalizedString(@"BLOCK_LIST_BLOCK_GROUP_TITLE_FORMAT",
|
||||
@"A format for the 'block group' action sheet title. Embeds the {{group name}}."),
|
||||
[self formatDisplayNameForAlertTitle:groupName]];
|
||||
|
||||
UIAlertController *actionSheet =
|
||||
[UIAlertController alertControllerWithTitle:title
|
||||
message:NSLocalizedString(@"BLOCK_GROUP_BEHAVIOR_EXPLANATION",
|
||||
@"An explanation of the consequences of blocking a group.")
|
||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
UIAlertAction *blockAction = [UIAlertAction
|
||||
actionWithTitle:NSLocalizedString(@"BLOCK_LIST_BLOCK_BUTTON", @"Button label for the 'block' button")
|
||||
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"block")
|
||||
style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
[self blockGroup:groupThread
|
||||
fromViewController:fromViewController
|
||||
blockingManager:blockingManager
|
||||
completionBlock:^(UIAlertAction *ignore) {
|
||||
if (completionBlock) {
|
||||
completionBlock(YES);
|
||||
}
|
||||
}];
|
||||
}];
|
||||
[actionSheet addAction:blockAction];
|
||||
|
||||
UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:CommonStrings.cancelButton
|
||||
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"dismiss")
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
if (completionBlock) {
|
||||
completionBlock(NO);
|
||||
}
|
||||
}];
|
||||
[actionSheet addAction:dismissAction];
|
||||
[fromViewController presentAlert:actionSheet];
|
||||
}
|
||||
|
||||
+ (void)blockPhoneNumbers:(NSArray<NSString *> *)phoneNumbers
|
||||
displayName:(NSString *)displayName
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(BlockAlertCompletionBlock)completionBlock
|
||||
{
|
||||
OWSAssertDebug(phoneNumbers.count > 0);
|
||||
OWSAssertDebug(displayName.length > 0);
|
||||
OWSAssertDebug(fromViewController);
|
||||
OWSAssertDebug(blockingManager);
|
||||
|
||||
for (NSString *phoneNumber in phoneNumbers) {
|
||||
OWSAssertDebug(phoneNumber.length > 0);
|
||||
[blockingManager addBlockedPhoneNumber:phoneNumber];
|
||||
}
|
||||
|
||||
[self showOkAlertWithTitle:NSLocalizedString(
|
||||
@"BLOCK_LIST_VIEW_BLOCKED_ALERT_TITLE", @"The title of the 'user blocked' alert.")
|
||||
message:[NSString
|
||||
stringWithFormat:NSLocalizedString(@"BLOCK_LIST_VIEW_BLOCKED_ALERT_MESSAGE_FORMAT",
|
||||
@"The message format of the 'conversation blocked' alert. "
|
||||
@"Embeds the {{conversation title}}."),
|
||||
[self formatDisplayNameForAlertMessage:displayName]]
|
||||
fromViewController:fromViewController
|
||||
completionBlock:completionBlock];
|
||||
}
|
||||
|
||||
+ (void)blockGroup:(TSGroupThread *)groupThread
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(BlockAlertCompletionBlock)completionBlock
|
||||
{
|
||||
OWSAssertDebug(groupThread);
|
||||
OWSAssertDebug(fromViewController);
|
||||
OWSAssertDebug(blockingManager);
|
||||
|
||||
// block the group regardless of the ability to deliver the "leave group" message.
|
||||
[blockingManager addBlockedGroup:groupThread.groupModel];
|
||||
|
||||
// blockingManager.addBlocked* creates sneaky transactions, so we can't pass in a transaction
|
||||
// via params and instead have to create our own sneaky transaction here.
|
||||
[groupThread leaveGroupWithSneakyTransaction];
|
||||
|
||||
// TODO: If we ever start using this again we should make sure to send a group leave message here
|
||||
|
||||
NSString *groupName = groupThread.name.length > 0 ? groupThread.name : TSGroupThread.defaultGroupName;
|
||||
|
||||
NSString *alertTitle
|
||||
= NSLocalizedString(@"BLOCK_LIST_VIEW_BLOCKED_GROUP_ALERT_TITLE", @"The title of the 'group blocked' alert.");
|
||||
NSString *alertBodyFormat = NSLocalizedString(@"BLOCK_LIST_VIEW_BLOCKED_ALERT_MESSAGE_FORMAT",
|
||||
@"The message format of the 'conversation blocked' alert. Embeds the {{conversation title}}.");
|
||||
NSString *alertBody =
|
||||
[NSString stringWithFormat:alertBodyFormat, [self formatDisplayNameForAlertMessage:groupName]];
|
||||
|
||||
[self showOkAlertWithTitle:alertTitle
|
||||
message:alertBody
|
||||
fromViewController:fromViewController
|
||||
completionBlock:completionBlock];
|
||||
}
|
||||
|
||||
#pragma mark - Unblock
|
||||
|
||||
+ (void)showUnblockThreadActionSheet:(TSThread *)thread
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
|
||||
{
|
||||
if ([thread isKindOfClass:[TSContactThread class]]) {
|
||||
TSContactThread *contactThread = (TSContactThread *)thread;
|
||||
[self showUnblockPhoneNumberActionSheet:contactThread.contactSessionID
|
||||
fromViewController:fromViewController
|
||||
blockingManager:blockingManager
|
||||
completionBlock:completionBlock];
|
||||
} else if ([thread isKindOfClass:[TSGroupThread class]]) {
|
||||
TSGroupThread *groupThread = (TSGroupThread *)thread;
|
||||
NSString *groupName = groupThread.name.length > 0 ? groupThread.name : TSGroupThread.defaultGroupName;
|
||||
[self showUnblockGroupActionSheet:groupThread.groupModel
|
||||
displayName:groupName
|
||||
fromViewController:fromViewController
|
||||
blockingManager:blockingManager
|
||||
completionBlock:completionBlock];
|
||||
} else {
|
||||
OWSFailDebug(@"unexpected thread type: %@", thread.class);
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)showUnblockPhoneNumberActionSheet:(NSString *)phoneNumber
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
|
||||
{
|
||||
NSString *displayName = [[LKStorage.shared getContactWithSessionID:phoneNumber] displayNameFor:SNContactContextRegular] ?: phoneNumber;
|
||||
[self showUnblockPhoneNumbersActionSheet:@[ phoneNumber ]
|
||||
displayName:displayName
|
||||
fromViewController:fromViewController
|
||||
blockingManager:blockingManager
|
||||
completionBlock:completionBlock];
|
||||
}
|
||||
|
||||
+ (void)showUnblockSignalAccountActionSheet:(SignalAccount *)signalAccount
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
|
||||
{
|
||||
NSString *displayName = [[LKStorage.shared getContactWithSessionID:signalAccount.recipientId] displayNameFor:SNContactContextRegular] ?: signalAccount.recipientId;
|
||||
[self showUnblockPhoneNumbersActionSheet:@[ signalAccount.recipientId ]
|
||||
displayName:displayName
|
||||
fromViewController:fromViewController
|
||||
blockingManager:blockingManager
|
||||
completionBlock:completionBlock];
|
||||
}
|
||||
|
||||
+ (void)showUnblockPhoneNumbersActionSheet:(NSArray<NSString *> *)phoneNumbers
|
||||
displayName:(NSString *)displayName
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
|
||||
{
|
||||
OWSAssertDebug(phoneNumbers.count > 0);
|
||||
OWSAssertDebug(displayName.length > 0);
|
||||
OWSAssertDebug(fromViewController);
|
||||
OWSAssertDebug(blockingManager);
|
||||
|
||||
NSString *title = [NSString
|
||||
stringWithFormat:
|
||||
NSLocalizedString(@"BLOCK_LIST_UNBLOCK_TITLE_FORMAT",
|
||||
@"A format for the 'unblock conversation' action sheet title. Embeds the {{conversation title}}."),
|
||||
[self formatDisplayNameForAlertTitle:displayName]];
|
||||
|
||||
UIAlertController *actionSheet =
|
||||
[UIAlertController alertControllerWithTitle:title message:nil preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
UIAlertAction *unblockAction =
|
||||
[UIAlertAction actionWithTitle:NSLocalizedString(
|
||||
@"BLOCK_LIST_UNBLOCK_BUTTON", @"Button label for the 'unblock' button")
|
||||
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"unblock")
|
||||
style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
[BlockListUIUtils unblockPhoneNumbers:phoneNumbers
|
||||
displayName:displayName
|
||||
fromViewController:fromViewController
|
||||
blockingManager:blockingManager
|
||||
completionBlock:^(UIAlertAction *ignore) {
|
||||
if (completionBlock) {
|
||||
completionBlock(NO);
|
||||
}
|
||||
}];
|
||||
}];
|
||||
[actionSheet addAction:unblockAction];
|
||||
|
||||
UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:CommonStrings.cancelButton
|
||||
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"dismiss")
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
if (completionBlock) {
|
||||
completionBlock(YES);
|
||||
}
|
||||
}];
|
||||
[actionSheet addAction:dismissAction];
|
||||
[fromViewController presentAlert:actionSheet];
|
||||
}
|
||||
|
||||
+ (void)unblockPhoneNumbers:(NSArray<NSString *> *)phoneNumbers
|
||||
displayName:(NSString *)displayName
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(BlockAlertCompletionBlock)completionBlock
|
||||
{
|
||||
OWSAssertDebug(phoneNumbers.count > 0);
|
||||
OWSAssertDebug(displayName.length > 0);
|
||||
OWSAssertDebug(fromViewController);
|
||||
OWSAssertDebug(blockingManager);
|
||||
|
||||
for (NSString *phoneNumber in phoneNumbers) {
|
||||
OWSAssertDebug(phoneNumber.length > 0);
|
||||
[blockingManager removeBlockedPhoneNumber:phoneNumber];
|
||||
}
|
||||
|
||||
NSString *titleFormat = NSLocalizedString(@"BLOCK_LIST_VIEW_UNBLOCKED_ALERT_TITLE_FORMAT",
|
||||
@"Alert title after unblocking a group or 1:1 chat. Embeds the {{conversation title}}.");
|
||||
NSString *title = [NSString stringWithFormat:titleFormat, [self formatDisplayNameForAlertMessage:displayName]];
|
||||
|
||||
[self showOkAlertWithTitle:title message:nil fromViewController:fromViewController completionBlock:completionBlock];
|
||||
}
|
||||
|
||||
+ (void)showUnblockGroupActionSheet:(TSGroupModel *)groupModel
|
||||
displayName:(NSString *)displayName
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(nullable BlockActionCompletionBlock)completionBlock
|
||||
{
|
||||
OWSAssertDebug(displayName.length > 0);
|
||||
OWSAssertDebug(fromViewController);
|
||||
OWSAssertDebug(blockingManager);
|
||||
|
||||
NSString *title =
|
||||
[NSString stringWithFormat:NSLocalizedString(@"BLOCK_LIST_UNBLOCK_GROUP_TITLE",
|
||||
@"Action sheet title when confirming you want to unblock a group.")];
|
||||
|
||||
NSString *message = NSLocalizedString(
|
||||
@"BLOCK_LIST_UNBLOCK_GROUP_BODY", @"Action sheet body when confirming you want to unblock a group");
|
||||
|
||||
UIAlertController *actionSheet = [UIAlertController alertControllerWithTitle:title
|
||||
message:message
|
||||
preferredStyle:UIAlertControllerStyleActionSheet];
|
||||
|
||||
UIAlertAction *unblockAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"BLOCK_LIST_UNBLOCK_BUTTON",
|
||||
@"Button label for the 'unblock' button")
|
||||
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"unblock")
|
||||
style:UIAlertActionStyleDestructive
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
[BlockListUIUtils unblockGroup:groupModel
|
||||
displayName:displayName
|
||||
fromViewController:fromViewController
|
||||
blockingManager:blockingManager
|
||||
completionBlock:^(UIAlertAction *ignore) {
|
||||
if (completionBlock) {
|
||||
completionBlock(NO);
|
||||
}
|
||||
}];
|
||||
}];
|
||||
[actionSheet addAction:unblockAction];
|
||||
|
||||
UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:CommonStrings.cancelButton
|
||||
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"dismiss")
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
if (completionBlock) {
|
||||
completionBlock(YES);
|
||||
}
|
||||
}];
|
||||
[actionSheet addAction:dismissAction];
|
||||
[fromViewController presentAlert:actionSheet];
|
||||
}
|
||||
|
||||
+ (void)unblockGroup:(TSGroupModel *)groupModel
|
||||
displayName:(NSString *)displayName
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
completionBlock:(BlockAlertCompletionBlock)completionBlock
|
||||
{
|
||||
OWSAssertDebug(displayName.length > 0);
|
||||
OWSAssertDebug(fromViewController);
|
||||
OWSAssertDebug(blockingManager);
|
||||
|
||||
[blockingManager removeBlockedGroupId:groupModel.groupId];
|
||||
|
||||
NSString *titleFormat = NSLocalizedString(@"BLOCK_LIST_VIEW_UNBLOCKED_ALERT_TITLE_FORMAT",
|
||||
@"Alert title after unblocking a group or 1:1 chat. Embeds the {{conversation title}}.");
|
||||
NSString *title = [NSString stringWithFormat:titleFormat, [self formatDisplayNameForAlertMessage:displayName]];
|
||||
|
||||
NSString *message
|
||||
= NSLocalizedString(@"BLOCK_LIST_VIEW_UNBLOCKED_GROUP_ALERT_BODY", @"Alert body after unblocking a group.");
|
||||
[self showOkAlertWithTitle:title
|
||||
message:message
|
||||
fromViewController:fromViewController
|
||||
completionBlock:completionBlock];
|
||||
}
|
||||
|
||||
#pragma mark - UI
|
||||
|
||||
+ (void)showOkAlertWithTitle:(NSString *)title
|
||||
message:(nullable NSString *)message
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
completionBlock:(BlockAlertCompletionBlock)completionBlock
|
||||
{
|
||||
OWSAssertDebug(title.length > 0);
|
||||
OWSAssertDebug(fromViewController);
|
||||
|
||||
UIAlertController *alert =
|
||||
[UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction *okAction = [UIAlertAction actionWithTitle:NSLocalizedString(@"BUTTON_OK", nil)
|
||||
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"ok")
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:completionBlock];
|
||||
[alert addAction:okAction];
|
||||
[fromViewController presentAlert:alert];
|
||||
}
|
||||
|
||||
+ (NSString *)formatDisplayNameForAlertTitle:(NSString *)displayName
|
||||
{
|
||||
return [self formatDisplayName:displayName withMaxLength:20];
|
||||
}
|
||||
|
||||
+ (NSString *)formatDisplayNameForAlertMessage:(NSString *)displayName
|
||||
{
|
||||
return [self formatDisplayName:displayName withMaxLength:127];
|
||||
}
|
||||
|
||||
+ (NSString *)formatDisplayName:(NSString *)displayName withMaxLength:(NSUInteger)maxLength
|
||||
{
|
||||
OWSAssertDebug(displayName.length > 0);
|
||||
|
||||
if (displayName.length > maxLength) {
|
||||
return [[displayName substringToIndex:maxLength] stringByAppendingString:@"…"];
|
||||
}
|
||||
|
||||
return displayName;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
144
SignalUtilitiesKit/Messaging/BlockListUIUtils.swift
Normal file
144
SignalUtilitiesKit/Messaging/BlockListUIUtils.swift
Normal file
|
@ -0,0 +1,144 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import UIKit
|
||||
import SessionMessagingKit
|
||||
|
||||
@objc public class BlockListUIUtils: NSObject {
|
||||
// MARK: - Block
|
||||
|
||||
/// This method shows an alert to unblock a contact in a ContactThread and will update the `isBlocked` flag of the contact if the user decides to continue
|
||||
///
|
||||
/// **Note:** Make sure to force a config sync in the `completionBlock` if the blocked state was successfully changed
|
||||
@objc public static func showBlockThreadActionSheet(_ thread: TSContactThread, from viewController: UIViewController, completionBlock: ((Bool) -> ())? = nil) {
|
||||
let userPublicKey = getUserHexEncodedPublicKey()
|
||||
|
||||
guard thread.contactSessionID() != userPublicKey, let contact: Contact = Storage.shared.getContact(with: thread.contactSessionID()) else {
|
||||
completionBlock?(false)
|
||||
return
|
||||
}
|
||||
|
||||
let displayName: String = (contact.displayName(for: .regular) ?? thread.contactSessionID())
|
||||
let actionSheet: UIAlertController = UIAlertController(
|
||||
title: String(
|
||||
format: "BLOCK_LIST_BLOCK_USER_TITLE_FORMAT".localized(),
|
||||
self.formatForAlertTitle(displayName: displayName)
|
||||
),
|
||||
message: "BLOCK_USER_BEHAVIOR_EXPLANATION".localized(),
|
||||
preferredStyle: .actionSheet
|
||||
)
|
||||
actionSheet.addAction(UIAlertAction(
|
||||
title: "BLOCK_LIST_BLOCK_BUTTON".localized(),
|
||||
accessibilityIdentifier: "\(type(of: self).self).block",
|
||||
style: .destructive,
|
||||
handler: { _ in
|
||||
Storage.write(
|
||||
with: { transaction in
|
||||
contact.isBlocked = true
|
||||
Storage.shared.setContact(contact, using: transaction)
|
||||
},
|
||||
completion: {
|
||||
self.showOkAlert(
|
||||
title: "BLOCK_LIST_VIEW_BLOCKED_ALERT_TITLE".localized(),
|
||||
message: String(
|
||||
format: "BLOCK_LIST_VIEW_BLOCKED_ALERT_MESSAGE_FORMAT".localized(),
|
||||
self.formatForAlertMessage(displayName: displayName)
|
||||
),
|
||||
from: viewController,
|
||||
completionBlock: { _ in completionBlock?(true) }
|
||||
)
|
||||
})
|
||||
}
|
||||
))
|
||||
actionSheet.addAction(UIAlertAction(
|
||||
title: CommonStrings.cancelButton,
|
||||
accessibilityIdentifier: "\(type(of: self).self).dismiss",
|
||||
style: .cancel,
|
||||
handler: { _ in completionBlock?(false) }
|
||||
))
|
||||
|
||||
viewController.presentAlert(actionSheet)
|
||||
}
|
||||
|
||||
// MARK: - Unblock
|
||||
|
||||
/// This method shows an alert to unblock a contact in a ContactThread and will update the `isBlocked` flag of the contact if the user decides to continue
|
||||
///
|
||||
/// **Note:** Make sure to force a config sync in the `completionBlock` if the blocked state was successfully changed
|
||||
@objc public static func showUnblockThreadActionSheet(_ thread: TSContactThread, from viewController: UIViewController, completionBlock: ((Bool) -> ())? = nil) {
|
||||
guard let contact: Contact = Storage.shared.getContact(with: thread.contactSessionID()) else {
|
||||
completionBlock?(true)
|
||||
return
|
||||
}
|
||||
|
||||
let displayName: String = (contact.displayName(for: .regular) ?? thread.contactSessionID())
|
||||
let actionSheet: UIAlertController = UIAlertController(
|
||||
title: String(
|
||||
format: "BLOCK_LIST_UNBLOCK_TITLE_FORMAT".localized(),
|
||||
self.formatForAlertTitle(displayName: displayName)
|
||||
),
|
||||
message: nil,
|
||||
preferredStyle: .actionSheet
|
||||
)
|
||||
actionSheet.addAction(UIAlertAction(
|
||||
title: "BLOCK_LIST_UNBLOCK_BUTTON".localized(),
|
||||
accessibilityIdentifier: "\(type(of: self).self).unblock",
|
||||
style: .destructive,
|
||||
handler: { _ in
|
||||
Storage.write(
|
||||
with: { transaction in
|
||||
contact.isBlocked = false
|
||||
Storage.shared.setContact(contact, using: transaction)
|
||||
},
|
||||
completion: {
|
||||
self.showOkAlert(
|
||||
title: String(
|
||||
format: "BLOCK_LIST_VIEW_UNBLOCKED_ALERT_TITLE_FORMAT".localized(),
|
||||
self.formatForAlertMessage(displayName: displayName)
|
||||
),
|
||||
message: nil,
|
||||
from: viewController,
|
||||
completionBlock: { _ in completionBlock?(false) }
|
||||
)
|
||||
})
|
||||
}
|
||||
))
|
||||
actionSheet.addAction(UIAlertAction(
|
||||
title: CommonStrings.cancelButton,
|
||||
accessibilityIdentifier: "\(type(of: self).self).dismiss",
|
||||
style: .cancel,
|
||||
handler: { _ in completionBlock?(true) }
|
||||
))
|
||||
|
||||
viewController.presentAlert(actionSheet)
|
||||
}
|
||||
|
||||
// MARK: - UI
|
||||
|
||||
@objc public static func showOkAlert(title: String, message: String?, from viewController: UIViewController, completionBlock: @escaping (UIAlertAction) -> ()) {
|
||||
let alertController: UIAlertController = UIAlertController(title: title, message: message, preferredStyle: .alert)
|
||||
alertController.addAction(UIAlertAction(
|
||||
title: "BUTTON_OK".localized(),
|
||||
accessibilityIdentifier: "\(type(of: self).self).ok",
|
||||
style: .default,
|
||||
handler: completionBlock
|
||||
))
|
||||
|
||||
viewController.presentAlert(alertController)
|
||||
}
|
||||
|
||||
@objc public static func formatForAlertTitle(displayName: String) -> String {
|
||||
return format(displayName: displayName, maxLength: 20)
|
||||
}
|
||||
|
||||
@objc public static func formatForAlertMessage(displayName: String) -> String {
|
||||
return format(displayName: displayName, maxLength: 127)
|
||||
}
|
||||
|
||||
@objc public static func format(displayName: String, maxLength: Int) -> String {
|
||||
guard displayName.count <= maxLength else {
|
||||
return "\(displayName.substring(to: maxLength))…"
|
||||
}
|
||||
|
||||
return displayName
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
import PromiseKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
extension MessageSender {
|
||||
|
||||
|
@ -104,4 +105,39 @@ extension MessageSender {
|
|||
}
|
||||
return promise
|
||||
}
|
||||
|
||||
public static func syncConfiguration(forceSyncNow: Bool = true) -> Promise<Void> {
|
||||
let (promise, seal) = Promise<Void>.pending()
|
||||
let destination: Message.Destination = Message.Destination.contact(publicKey: getUserHexEncodedPublicKey())
|
||||
|
||||
// Note: SQLite only supports a single write thread so we can be sure this will retrieve the most up-to-date data
|
||||
Storage.writeSync { transaction in
|
||||
guard Storage.shared.getUser(using: transaction)?.name != nil, let configurationMessage = ConfigurationMessage.getCurrent(with: transaction) else {
|
||||
seal.fulfill(())
|
||||
return
|
||||
}
|
||||
|
||||
if forceSyncNow {
|
||||
MessageSender.send(configurationMessage, to: destination, using: transaction).done {
|
||||
seal.fulfill(())
|
||||
}.catch { _ in
|
||||
seal.fulfill(()) // Fulfill even if this failed; the configuration in the swarm should be at most 2 days old
|
||||
}.retainUntilComplete()
|
||||
}
|
||||
else {
|
||||
let job = MessageSendJob(message: configurationMessage, destination: destination)
|
||||
JobQueue.shared.add(job, using: transaction)
|
||||
seal.fulfill(())
|
||||
}
|
||||
}
|
||||
|
||||
return promise
|
||||
}
|
||||
}
|
||||
|
||||
extension MessageSender {
|
||||
@objc(forceSyncConfigurationNow)
|
||||
public static func objc_forceSyncConfigurationNow() {
|
||||
return syncConfiguration(forceSyncNow: true).retainUntilComplete()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[];
|
|||
#import <SignalUtilitiesKit/AppSetup.h>
|
||||
#import <SignalUtilitiesKit/AppVersion.h>
|
||||
#import <SignalUtilitiesKit/AttachmentSharing.h>
|
||||
#import <SignalUtilitiesKit/BlockListUIUtils.h>
|
||||
#import <SignalUtilitiesKit/ByteParser.h>
|
||||
#import <SignalUtilitiesKit/ContactCellView.h>
|
||||
#import <SignalUtilitiesKit/ContactTableViewCell.h>
|
||||
|
@ -43,8 +42,6 @@ FOUNDATION_EXPORT const unsigned char SignalUtilitiesKitVersionString[];
|
|||
#import <SignalUtilitiesKit/OWSUnreadIndicator.h>
|
||||
#import <SignalUtilitiesKit/OWSViewController.h>
|
||||
#import <SignalUtilitiesKit/ScreenLockViewController.h>
|
||||
#import <SignalUtilitiesKit/SelectRecipientViewController.h>
|
||||
#import <SignalUtilitiesKit/SharingThreadPickerViewController.h>
|
||||
#import <SignalUtilitiesKit/SignalAccount.h>
|
||||
#import <SignalUtilitiesKit/SSKAsserts.h>
|
||||
#import <SignalUtilitiesKit/Theme.h>
|
||||
|
|
|
@ -1,47 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SignalUtilitiesKit/OWSViewController.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class SignalAccount;
|
||||
|
||||
@protocol SelectRecipientViewControllerDelegate <NSObject>
|
||||
|
||||
- (NSString *)phoneNumberSectionTitle;
|
||||
- (NSString *)phoneNumberButtonText;
|
||||
- (NSString *)contactsSectionTitle;
|
||||
|
||||
- (void)phoneNumberWasSelected:(NSString *)phoneNumber;
|
||||
|
||||
- (BOOL)canSignalAccountBeSelected:(SignalAccount *)signalAccount;
|
||||
|
||||
- (void)signalAccountWasSelected:(SignalAccount *)signalAccount;
|
||||
|
||||
- (nullable NSString *)accessoryMessageForSignalAccount:(SignalAccount *)signalAccount;
|
||||
|
||||
- (BOOL)shouldHideLocalNumber;
|
||||
|
||||
- (BOOL)shouldHideContacts;
|
||||
|
||||
- (BOOL)shouldValidatePhoneNumbers;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@class ContactsViewHelper;
|
||||
|
||||
@interface SelectRecipientViewController : OWSViewController
|
||||
|
||||
@property (nonatomic, weak) id<SelectRecipientViewControllerDelegate> delegate;
|
||||
|
||||
@property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper;
|
||||
|
||||
@property (nonatomic) BOOL isPresentedInNavigationController;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,332 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SignalUtilitiesKit/SelectRecipientViewController.h>
|
||||
|
||||
#import <SignalUtilitiesKit/ContactTableViewCell.h>
|
||||
#import <SignalUtilitiesKit/OWSTableViewController.h>
|
||||
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
|
||||
#import <SignalUtilitiesKit/UIFont+OWS.h>
|
||||
#import <SignalUtilitiesKit/UIUtil.h>
|
||||
#import <SessionUtilitiesKit/UIView+OWS.h>
|
||||
#import <SessionUtilitiesKit/AppContext.h>
|
||||
#import <SignalUtilitiesKit/SignalAccount.h>
|
||||
#import <SessionMessagingKit/TSAccountManager.h>
|
||||
#import <SignalUtilitiesKit/OWSTextField.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
NSString *const kSelectRecipientViewControllerCellIdentifier = @"kSelectRecipientViewControllerCellIdentifier";
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface SelectRecipientViewController () </*CountryCodeViewControllerDelegate,*/
|
||||
OWSTableViewControllerDelegate,
|
||||
UITextFieldDelegate>
|
||||
|
||||
@property (nonatomic) UIButton *countryCodeButton;
|
||||
|
||||
@property (nonatomic) UITextField *phoneNumberTextField;
|
||||
|
||||
@property (nonatomic) OWSFlatButton *phoneNumberButton;
|
||||
|
||||
@property (nonatomic) UILabel *examplePhoneNumberLabel;
|
||||
|
||||
@property (nonatomic, readonly) OWSTableViewController *tableViewController;
|
||||
|
||||
@property (nonatomic) NSString *callingCode;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation SelectRecipientViewController
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
|
||||
self.view.backgroundColor = [Theme backgroundColor];
|
||||
|
||||
[self createViews];
|
||||
|
||||
if (self.delegate.shouldHideContacts) {
|
||||
self.tableViewController.tableView.scrollEnabled = NO;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
OWSAssertDebug(self.tableViewController);
|
||||
|
||||
[super viewDidLoad];
|
||||
}
|
||||
|
||||
- (void)viewDidAppear:(BOOL)animated
|
||||
{
|
||||
[super viewDidAppear:animated];
|
||||
[self.tableViewController viewDidAppear:animated];
|
||||
|
||||
if ([self.delegate shouldHideContacts]) {
|
||||
[self.phoneNumberTextField becomeFirstResponder];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)createViews
|
||||
{
|
||||
OWSAssertDebug(self.delegate);
|
||||
|
||||
_tableViewController = [OWSTableViewController new];
|
||||
_tableViewController.delegate = self;
|
||||
[self.view addSubview:self.tableViewController.view];
|
||||
[self.tableViewController.view autoPinEdgeToSuperviewSafeArea:ALEdgeLeading];
|
||||
[self.tableViewController.view autoPinEdgeToSuperviewSafeArea:ALEdgeTrailing];
|
||||
[_tableViewController.view autoPinEdge:ALEdgeTop toEdge:ALEdgeTop ofView:self.view withOffset:0];
|
||||
[_tableViewController.view autoPinEdgeToSuperviewEdge:ALEdgeBottom];
|
||||
self.tableViewController.tableView.rowHeight = UITableViewAutomaticDimension;
|
||||
self.tableViewController.tableView.estimatedRowHeight = 60;
|
||||
_tableViewController.view.backgroundColor = [Theme backgroundColor];
|
||||
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
- (UILabel *)countryCodeLabel
|
||||
{
|
||||
UILabel *countryCodeLabel = [UILabel new];
|
||||
countryCodeLabel.font = [UIFont ows_mediumFontWithSize:18.f];
|
||||
countryCodeLabel.textColor = [Theme primaryColor];
|
||||
countryCodeLabel.text
|
||||
= NSLocalizedString(@"REGISTRATION_DEFAULT_COUNTRY_NAME", @"Label for the country code field");
|
||||
return countryCodeLabel;
|
||||
}
|
||||
|
||||
- (UIButton *)countryCodeButton
|
||||
{
|
||||
if (!_countryCodeButton) {
|
||||
_countryCodeButton = [UIButton buttonWithType:UIButtonTypeCustom];
|
||||
_countryCodeButton.titleLabel.font = [UIFont ows_mediumFontWithSize:18.f];
|
||||
_countryCodeButton.contentHorizontalAlignment = UIControlContentHorizontalAlignmentRight;
|
||||
[_countryCodeButton setTitleColor:[UIColor ows_materialBlueColor] forState:UIControlStateNormal];
|
||||
[_countryCodeButton addTarget:self
|
||||
action:@selector(showCountryCodeView:)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, _countryCodeButton);
|
||||
}
|
||||
|
||||
return _countryCodeButton;
|
||||
}
|
||||
|
||||
- (UILabel *)phoneNumberLabel
|
||||
{
|
||||
UILabel *phoneNumberLabel = [UILabel new];
|
||||
phoneNumberLabel.font = [UIFont ows_mediumFontWithSize:18.f];
|
||||
phoneNumberLabel.textColor = [Theme primaryColor];
|
||||
phoneNumberLabel.text
|
||||
= NSLocalizedString(@"REGISTRATION_PHONENUMBER_BUTTON", @"Label for the phone number textfield");
|
||||
return phoneNumberLabel;
|
||||
}
|
||||
|
||||
- (UIFont *)examplePhoneNumberFont
|
||||
{
|
||||
return [UIFont ows_regularFontWithSize:16.f];
|
||||
}
|
||||
|
||||
- (UILabel *)examplePhoneNumberLabel
|
||||
{
|
||||
if (!_examplePhoneNumberLabel) {
|
||||
_examplePhoneNumberLabel = [UILabel new];
|
||||
_examplePhoneNumberLabel.font = [self examplePhoneNumberFont];
|
||||
_examplePhoneNumberLabel.textColor = [Theme secondaryColor];
|
||||
SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, _examplePhoneNumberLabel);
|
||||
}
|
||||
|
||||
return _examplePhoneNumberLabel;
|
||||
}
|
||||
|
||||
- (UITextField *)phoneNumberTextField
|
||||
{
|
||||
if (!_phoneNumberTextField) {
|
||||
_phoneNumberTextField = [OWSTextField new];
|
||||
_phoneNumberTextField.font = [UIFont ows_mediumFontWithSize:18.f];
|
||||
_phoneNumberTextField.textAlignment = _phoneNumberTextField.textAlignmentUnnatural;
|
||||
_phoneNumberTextField.textColor = [UIColor ows_materialBlueColor];
|
||||
_phoneNumberTextField.placeholder = NSLocalizedString(
|
||||
@"REGISTRATION_ENTERNUMBER_DEFAULT_TEXT", @"Placeholder text for the phone number textfield");
|
||||
_phoneNumberTextField.keyboardType = UIKeyboardTypeNumberPad;
|
||||
_phoneNumberTextField.delegate = self;
|
||||
[_phoneNumberTextField addTarget:self
|
||||
action:@selector(textFieldDidChange:)
|
||||
forControlEvents:UIControlEventEditingChanged];
|
||||
SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, _phoneNumberTextField);
|
||||
}
|
||||
|
||||
return _phoneNumberTextField;
|
||||
}
|
||||
|
||||
- (OWSFlatButton *)phoneNumberButton
|
||||
{
|
||||
if (!_phoneNumberButton) {
|
||||
const CGFloat kButtonHeight = 40;
|
||||
OWSFlatButton *button = [OWSFlatButton buttonWithTitle:[self.delegate phoneNumberButtonText]
|
||||
font:[OWSFlatButton fontForHeight:kButtonHeight]
|
||||
titleColor:[UIColor whiteColor]
|
||||
backgroundColor:[UIColor ows_materialBlueColor]
|
||||
target:self
|
||||
selector:@selector(phoneNumberButtonPressed)];
|
||||
_phoneNumberButton = button;
|
||||
[button autoSetDimension:ALDimensionWidth toSize:140];
|
||||
[button autoSetDimension:ALDimensionHeight toSize:kButtonHeight];
|
||||
SET_SUBVIEW_ACCESSIBILITY_IDENTIFIER(self, _phoneNumberButton);
|
||||
}
|
||||
return _phoneNumberButton;
|
||||
}
|
||||
|
||||
- (UIView *)createRowWithHeight:(CGFloat)height
|
||||
previousRow:(nullable UIView *)previousRow
|
||||
superview:(nullable UIView *)superview
|
||||
{
|
||||
UIView *row = [UIView containerView];
|
||||
[superview addSubview:row];
|
||||
[row autoPinLeadingAndTrailingToSuperviewMargin];
|
||||
if (previousRow) {
|
||||
[row autoPinEdge:ALEdgeTop toEdge:ALEdgeBottom ofView:previousRow withOffset:0];
|
||||
} else {
|
||||
[row autoPinEdgeToSuperviewEdge:ALEdgeTop];
|
||||
}
|
||||
[row autoSetDimension:ALDimensionHeight toSize:height];
|
||||
return row;
|
||||
}
|
||||
|
||||
#pragma mark - UITextFieldDelegate
|
||||
|
||||
- (BOOL)textField:(UITextField *)textField
|
||||
shouldChangeCharactersInRange:(NSRange)range
|
||||
replacementString:(NSString *)insertionText
|
||||
{
|
||||
return NO; // inform our caller that we took care of performing the change
|
||||
}
|
||||
|
||||
- (BOOL)textFieldShouldReturn:(UITextField *)textField
|
||||
{
|
||||
[textField resignFirstResponder];
|
||||
return NO;
|
||||
}
|
||||
|
||||
#pragma mark - Table Contents
|
||||
|
||||
- (void)updateTableContents
|
||||
{
|
||||
OWSTableContents *contents = [OWSTableContents new];
|
||||
__weak SelectRecipientViewController *weakSelf = self;
|
||||
ContactsViewHelper *helper = self.contactsViewHelper;
|
||||
|
||||
OWSTableSection *phoneNumberSection = [OWSTableSection new];
|
||||
phoneNumberSection.headerTitle = [self.delegate phoneNumberSectionTitle];
|
||||
const CGFloat kCountryRowHeight = 50;
|
||||
const CGFloat kPhoneNumberRowHeight = 50;
|
||||
const CGFloat examplePhoneNumberRowHeight = self.examplePhoneNumberFont.lineHeight + 3.f;
|
||||
const CGFloat kButtonRowHeight = 60;
|
||||
[phoneNumberSection addItem:[OWSTableItem itemWithCustomCellBlock:^{
|
||||
SelectRecipientViewController *strongSelf = weakSelf;
|
||||
OWSCAssertDebug(strongSelf);
|
||||
|
||||
UITableViewCell *cell = [OWSTableItem newCell];
|
||||
cell.preservesSuperviewLayoutMargins = YES;
|
||||
cell.contentView.preservesSuperviewLayoutMargins = YES;
|
||||
|
||||
// Country Row
|
||||
UIView *countryRow =
|
||||
[strongSelf createRowWithHeight:kCountryRowHeight previousRow:nil superview:cell.contentView];
|
||||
[countryRow addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:strongSelf
|
||||
action:@selector(countryRowTouched:)]];
|
||||
|
||||
UILabel *countryCodeLabel = strongSelf.countryCodeLabel;
|
||||
[countryRow addSubview:countryCodeLabel];
|
||||
[countryCodeLabel autoPinLeadingToSuperviewMargin];
|
||||
[countryCodeLabel autoVCenterInSuperview];
|
||||
|
||||
[countryRow addSubview:strongSelf.countryCodeButton];
|
||||
[strongSelf.countryCodeButton autoPinTrailingToSuperviewMargin];
|
||||
[strongSelf.countryCodeButton autoVCenterInSuperview];
|
||||
|
||||
// Phone Number Row
|
||||
UIView *phoneNumberRow =
|
||||
[strongSelf createRowWithHeight:kPhoneNumberRowHeight previousRow:countryRow superview:cell.contentView];
|
||||
[phoneNumberRow
|
||||
addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:strongSelf
|
||||
action:@selector(phoneNumberRowTouched:)]];
|
||||
|
||||
UILabel *phoneNumberLabel = strongSelf.phoneNumberLabel;
|
||||
[phoneNumberRow addSubview:phoneNumberLabel];
|
||||
[phoneNumberLabel autoPinLeadingToSuperviewMargin];
|
||||
[phoneNumberLabel autoVCenterInSuperview];
|
||||
|
||||
[phoneNumberRow addSubview:strongSelf.phoneNumberTextField];
|
||||
[strongSelf.phoneNumberTextField autoPinLeadingToTrailingEdgeOfView:phoneNumberLabel offset:10.f];
|
||||
[strongSelf.phoneNumberTextField autoPinTrailingToSuperviewMargin];
|
||||
[strongSelf.phoneNumberTextField autoVCenterInSuperview];
|
||||
|
||||
// Example row.
|
||||
UIView *examplePhoneNumberRow = [strongSelf createRowWithHeight:examplePhoneNumberRowHeight
|
||||
previousRow:phoneNumberRow
|
||||
superview:cell.contentView];
|
||||
[examplePhoneNumberRow addSubview:strongSelf.examplePhoneNumberLabel];
|
||||
[strongSelf.examplePhoneNumberLabel autoVCenterInSuperview];
|
||||
[strongSelf.examplePhoneNumberLabel autoPinTrailingToSuperviewMargin];
|
||||
|
||||
// Phone Number Button Row
|
||||
UIView *buttonRow = [strongSelf createRowWithHeight:kButtonRowHeight
|
||||
previousRow:examplePhoneNumberRow
|
||||
superview:cell.contentView];
|
||||
[buttonRow addSubview:strongSelf.phoneNumberButton];
|
||||
[strongSelf.phoneNumberButton autoVCenterInSuperview];
|
||||
[strongSelf.phoneNumberButton autoPinTrailingToSuperviewMargin];
|
||||
|
||||
[buttonRow autoPinEdgeToSuperviewEdge:ALEdgeBottom];
|
||||
|
||||
cell.selectionStyle = UITableViewCellSelectionStyleNone;
|
||||
return cell;
|
||||
}
|
||||
customRowHeight:kCountryRowHeight + kPhoneNumberRowHeight
|
||||
+ examplePhoneNumberRowHeight + kButtonRowHeight
|
||||
actionBlock:nil]];
|
||||
[contents addSection:phoneNumberSection];
|
||||
|
||||
self.tableViewController.contents = contents;
|
||||
}
|
||||
|
||||
- (void)phoneNumberRowTouched:(UIGestureRecognizer *)sender
|
||||
{
|
||||
if (sender.state == UIGestureRecognizerStateRecognized) {
|
||||
[self.phoneNumberTextField becomeFirstResponder];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)countryRowTouched:(UIGestureRecognizer *)sender
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - OWSTableViewControllerDelegate
|
||||
|
||||
- (void)tableViewWillBeginDragging
|
||||
{
|
||||
[self.phoneNumberTextField resignFirstResponder];
|
||||
}
|
||||
|
||||
#pragma mark - ContactsViewHelperDelegate
|
||||
|
||||
- (void)contactsViewHelperDidUpdateContacts
|
||||
{
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
- (BOOL)shouldHideLocalNumber
|
||||
{
|
||||
return [self.delegate shouldHideLocalNumber];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,31 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SignalUtilitiesKit/OWSViewController.h>
|
||||
|
||||
@class TSThread;
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol SelectThreadViewControllerDelegate <NSObject>
|
||||
|
||||
- (void)threadWasSelected:(TSThread *)thread;
|
||||
|
||||
- (BOOL)canSelectBlockedContact;
|
||||
|
||||
- (nullable UIView *)createHeaderWithSearchBar:(UISearchBar *)searchBar;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
// A base class for views used to pick a single signal user, either by
|
||||
// entering a phone number or picking from your contacts.
|
||||
@interface SelectThreadViewController : OWSViewController
|
||||
|
||||
@property (nonatomic, weak) id<SelectThreadViewControllerDelegate> selectThreadViewDelegate;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,315 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SelectThreadViewController.h"
|
||||
#import "ContactTableViewCell.h"
|
||||
#import "OWSSearchBar.h"
|
||||
#import "OWSTableViewController.h"
|
||||
#import "ThreadViewHelper.h"
|
||||
#import "UIColor+OWS.h"
|
||||
#import "UIFont+OWS.h"
|
||||
#import "UIView+OWS.h"
|
||||
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
|
||||
#import <SessionUtilitiesKit/NSString+SSK.h>
|
||||
#import <SignalUtilitiesKit/SignalAccount.h>
|
||||
#import <SessionMessagingKit/TSAccountManager.h>
|
||||
#import <SessionMessagingKit/TSContactThread.h>
|
||||
#import <SessionMessagingKit/TSThread.h>
|
||||
#import <YapDatabase/YapDatabase.h>
|
||||
#import <SessionUIKit/SessionUIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface SelectThreadViewController () <OWSTableViewControllerDelegate,
|
||||
ThreadViewHelperDelegate,
|
||||
UISearchBarDelegate>
|
||||
|
||||
@property (nonatomic, readonly) ContactsViewHelper *contactsViewHelper;
|
||||
@property (nonatomic, readonly) FullTextSearcher *fullTextSearcher;
|
||||
@property (nonatomic, readonly) ThreadViewHelper *threadViewHelper;
|
||||
@property (nonatomic, readonly) YapDatabaseConnection *uiDatabaseConnection;
|
||||
|
||||
@property (nonatomic, readonly) OWSTableViewController *tableViewController;
|
||||
|
||||
@property (nonatomic, readonly) UISearchBar *searchBar;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation SelectThreadViewController
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
|
||||
UIBarButtonItem *closeButton = [[UIBarButtonItem alloc] initWithImage:[UIImage imageNamed:@"X"] style:UIBarButtonItemStylePlain target:self action:@selector(dismissPressed:)];
|
||||
closeButton.tintColor = LKColors.text;
|
||||
self.navigationItem.leftBarButtonItem = closeButton;
|
||||
|
||||
_fullTextSearcher = FullTextSearcher.shared;
|
||||
_threadViewHelper = [ThreadViewHelper new];
|
||||
_threadViewHelper.delegate = self;
|
||||
|
||||
_uiDatabaseConnection = [[OWSPrimaryStorage sharedManager] newDatabaseConnection];
|
||||
#ifdef DEBUG
|
||||
_uiDatabaseConnection.permittedTransactions = YDB_AnyReadTransaction;
|
||||
#endif
|
||||
[_uiDatabaseConnection beginLongLivedReadTransaction];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(yapDatabaseModified:)
|
||||
name:YapDatabaseModifiedNotification
|
||||
object:OWSPrimaryStorage.sharedManager.dbNotificationObject];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(yapDatabaseModifiedExternally:)
|
||||
name:YapDatabaseModifiedExternallyNotification
|
||||
object:nil];
|
||||
|
||||
[self createViews];
|
||||
|
||||
// Loki: Set gradient background
|
||||
self.tableViewController.tableView.backgroundColor = UIColor.clearColor;
|
||||
self.tableViewController.view.backgroundColor = UIColor.clearColor;
|
||||
CAGradientLayer *layer = [CAGradientLayer new];
|
||||
layer.frame = UIScreen.mainScreen.bounds;
|
||||
UIColor *gradientStartColor = LKAppModeUtilities.isLightMode ? [UIColor colorWithRGBHex:0xFCFCFC] : [UIColor colorWithRGBHex:0x171717];
|
||||
UIColor *gradientEndColor = LKAppModeUtilities.isLightMode ? [UIColor colorWithRGBHex:0xFFFFFF] : [UIColor colorWithRGBHex:0x121212];
|
||||
layer.colors = @[ (id)gradientStartColor.CGColor, (id)gradientEndColor.CGColor ];
|
||||
[self.tableViewController.view.layer insertSublayer:layer atIndex:0];
|
||||
|
||||
// Loki: Set navigation bar background color
|
||||
UINavigationBar *navigationBar = self.navigationController.navigationBar;
|
||||
[navigationBar setBackgroundImage:[UIImage new] forBarMetrics:UIBarMetricsDefault];
|
||||
navigationBar.shadowImage = [UIImage new];
|
||||
[navigationBar setTranslucent:NO];
|
||||
navigationBar.barTintColor = LKColors.navigationBarBackground;
|
||||
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
- (void)createViews
|
||||
{
|
||||
OWSAssertDebug(self.selectThreadViewDelegate);
|
||||
|
||||
// Table
|
||||
_tableViewController = [OWSTableViewController new];
|
||||
_tableViewController.delegate = self;
|
||||
[self.view addSubview:self.tableViewController.view];
|
||||
[self.tableViewController.view autoPinEdgeToSuperviewSafeArea:ALEdgeLeading];
|
||||
[self.tableViewController.view autoPinEdgeToSuperviewSafeArea:ALEdgeTrailing];
|
||||
[_tableViewController.view autoPinEdgeToSuperviewEdge:ALEdgeTop];
|
||||
[_tableViewController.view autoPinEdgeToSuperviewEdge:ALEdgeBottom];
|
||||
self.tableViewController.tableView.rowHeight = UITableViewAutomaticDimension;
|
||||
self.tableViewController.tableView.estimatedRowHeight = 60;
|
||||
BOOL isIphone6OrSmaller = (UIScreen.mainScreen.bounds.size.height - 667) < 1;
|
||||
CGFloat bottomInset = isIphone6OrSmaller ? LKValues.mediumSpacing : 34.0f;
|
||||
self.tableViewController.tableView.contentInset = UIEdgeInsetsMake(0, 0, bottomInset, 0);
|
||||
}
|
||||
|
||||
- (void)yapDatabaseModifiedExternally:(NSNotification *)notification
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
OWSLogVerbose(@"");
|
||||
|
||||
[self.uiDatabaseConnection beginLongLivedReadTransaction];
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
- (void)yapDatabaseModified:(NSNotification *)notification
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
[self.uiDatabaseConnection beginLongLivedReadTransaction];
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
#pragma mark - UISearchBarDelegate
|
||||
|
||||
- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
|
||||
{
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
- (void)searchBarSearchButtonClicked:(UISearchBar *)searchBar
|
||||
{
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
|
||||
{
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
- (void)searchBarResultsListButtonClicked:(UISearchBar *)searchBar
|
||||
{
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
- (void)searchBar:(UISearchBar *)searchBar selectedScopeButtonIndexDidChange:(NSInteger)selectedScope
|
||||
{
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
#pragma mark - Table Contents
|
||||
|
||||
- (void)updateTableContents
|
||||
{
|
||||
__weak SelectThreadViewController *weakSelf = self;
|
||||
ContactsViewHelper *helper = self.contactsViewHelper;
|
||||
OWSTableContents *contents = [OWSTableContents new];
|
||||
|
||||
// Existing threads are listed first, ordered by most recently active
|
||||
OWSTableSection *recentChatsSection = [OWSTableSection new];
|
||||
recentChatsSection.headerTitle = NSLocalizedString(@"SELECT_THREAD_TABLE_RECENT_CHATS_TITLE", @"");
|
||||
for (TSThread *thread in self.threadViewHelper.threads) {
|
||||
[recentChatsSection
|
||||
addItem:[OWSTableItem
|
||||
itemWithCustomCellBlock:^{
|
||||
SelectThreadViewController *strongSelf = weakSelf;
|
||||
OWSCAssertDebug(strongSelf);
|
||||
|
||||
// To be consistent with the threads (above), we use ContactTableViewCell
|
||||
// instead of HomeViewCell to present contacts and threads.
|
||||
ContactTableViewCell *cell = [ContactTableViewCell new];
|
||||
|
||||
BOOL isBlocked = [SSKEnvironment.shared.blockingManager isThreadBlocked:thread];
|
||||
if (isBlocked) {
|
||||
cell.accessoryMessage = NSLocalizedString(
|
||||
@"CONTACT_CELL_IS_BLOCKED", @"An indicator that a contact has been blocked.");
|
||||
}
|
||||
|
||||
[cell configureWithThread:thread];
|
||||
|
||||
if (!cell.hasAccessoryText) {
|
||||
// Don't add a disappearing messages indicator if we've already added a "blocked" label.
|
||||
__block OWSDisappearingMessagesConfiguration *disappearingMessagesConfiguration;
|
||||
[self.uiDatabaseConnection
|
||||
readWithBlock:^(YapDatabaseReadTransaction *_Nonnull transaction) {
|
||||
disappearingMessagesConfiguration = [OWSDisappearingMessagesConfiguration
|
||||
fetchObjectWithUniqueID:thread.uniqueId
|
||||
transaction:transaction];
|
||||
}];
|
||||
|
||||
if (disappearingMessagesConfiguration && disappearingMessagesConfiguration.isEnabled) {
|
||||
DisappearingTimerConfigurationView *disappearingTimerConfigurationView =
|
||||
[[DisappearingTimerConfigurationView alloc]
|
||||
initWithDurationSeconds:disappearingMessagesConfiguration.durationSeconds];
|
||||
|
||||
disappearingTimerConfigurationView.tintColor = LKColors.text;
|
||||
[disappearingTimerConfigurationView autoSetDimensionsToSize:CGSizeMake(44, 44)];
|
||||
|
||||
[cell ows_setAccessoryView:disappearingTimerConfigurationView];
|
||||
}
|
||||
}
|
||||
|
||||
return cell;
|
||||
}
|
||||
customRowHeight:UITableViewAutomaticDimension
|
||||
actionBlock:^{
|
||||
typeof(self) strongSelf = weakSelf;
|
||||
if (!strongSelf) {
|
||||
return;
|
||||
}
|
||||
|
||||
BOOL isBlocked = [SSKEnvironment.shared.blockingManager isThreadBlocked:thread];
|
||||
if (isBlocked && ![strongSelf.selectThreadViewDelegate canSelectBlockedContact]) {
|
||||
[BlockListUIUtils
|
||||
showUnblockThreadActionSheet:thread
|
||||
fromViewController:strongSelf
|
||||
blockingManager:SSKEnvironment.shared.blockingManager
|
||||
completionBlock:^(BOOL isStillBlocked) {
|
||||
if (!isStillBlocked) {
|
||||
[strongSelf.selectThreadViewDelegate threadWasSelected:thread];
|
||||
}
|
||||
}];
|
||||
return;
|
||||
}
|
||||
|
||||
[strongSelf.selectThreadViewDelegate threadWasSelected:thread];
|
||||
}]];
|
||||
}
|
||||
|
||||
if (recentChatsSection.itemCount > 0) {
|
||||
[contents addSection:recentChatsSection];
|
||||
}
|
||||
|
||||
if (recentChatsSection.itemCount < 1) {
|
||||
OWSTableSection *emptySection = [OWSTableSection new];
|
||||
[emptySection
|
||||
addItem:[OWSTableItem
|
||||
softCenterLabelItemWithText:NSLocalizedString(@"SETTINGS_BLOCK_LIST_NO_CONTACTS",
|
||||
@"A label that indicates the user has no Signal contacts.")]];
|
||||
[contents addSection:emptySection];
|
||||
}
|
||||
|
||||
self.tableViewController.contents = contents;
|
||||
}
|
||||
|
||||
- (void)signalAccountWasSelected:(SignalAccount *)signalAccount
|
||||
{
|
||||
OWSAssertDebug(signalAccount);
|
||||
OWSAssertDebug(self.selectThreadViewDelegate);
|
||||
|
||||
if ([SSKEnvironment.shared.blockingManager isRecipientIdBlocked:signalAccount.recipientId]
|
||||
&& ![self.selectThreadViewDelegate canSelectBlockedContact]) {
|
||||
|
||||
__weak SelectThreadViewController *weakSelf = self;
|
||||
[BlockListUIUtils showUnblockSignalAccountActionSheet:signalAccount
|
||||
fromViewController:self
|
||||
blockingManager:SSKEnvironment.shared.blockingManager
|
||||
completionBlock:^(BOOL isBlocked) {
|
||||
if (!isBlocked) {
|
||||
[weakSelf signalAccountWasSelected:signalAccount];
|
||||
}
|
||||
}];
|
||||
return;
|
||||
}
|
||||
|
||||
__block TSThread *thread = nil;
|
||||
[LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
thread = [TSContactThread getOrCreateThreadWithContactSessionID:signalAccount.recipientId transaction:transaction];
|
||||
}];
|
||||
OWSAssertDebug(thread);
|
||||
|
||||
[self.selectThreadViewDelegate threadWasSelected:thread];
|
||||
}
|
||||
|
||||
#pragma mark - Events
|
||||
|
||||
- (void)dismissPressed:(id)sender
|
||||
{
|
||||
[self.searchBar resignFirstResponder];
|
||||
[self dismissViewControllerAnimated:YES completion:nil];
|
||||
}
|
||||
|
||||
#pragma mark - OWSTableViewControllerDelegate
|
||||
|
||||
- (void)tableViewWillBeginDragging
|
||||
{
|
||||
[self.searchBar resignFirstResponder];
|
||||
}
|
||||
|
||||
#pragma mark - ThreadViewHelperDelegate
|
||||
|
||||
- (void)threadListDidChange
|
||||
{
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
#pragma mark - ContactsViewHelperDelegate
|
||||
|
||||
- (void)contactsViewHelperDidUpdateContacts
|
||||
{
|
||||
[self updateTableContents];
|
||||
}
|
||||
|
||||
- (BOOL)shouldHideLocalNumber
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,21 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import <SignalUtilitiesKit/SelectThreadViewController.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@class SignalAttachment;
|
||||
|
||||
@protocol ShareViewDelegate;
|
||||
|
||||
@interface SharingThreadPickerViewController : SelectThreadViewController
|
||||
|
||||
@property (nonatomic) NSArray<SignalAttachment *> *attachments;
|
||||
|
||||
- (instancetype)initWithShareViewDelegate:(id<ShareViewDelegate>)shareViewDelegate;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -1,458 +0,0 @@
|
|||
//
|
||||
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "SharingThreadPickerViewController.h"
|
||||
#import "SignalApp.h"
|
||||
#import "UIColor+OWS.h"
|
||||
#import "UIFont+OWS.h"
|
||||
#import "UIView+OWS.h"
|
||||
#import <PromiseKit/PromiseKit.h>
|
||||
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
|
||||
#import <SessionUtilitiesKit/NSString+SSK.h>
|
||||
#import <SignalUtilitiesKit/OWSError.h>
|
||||
#import <SessionMessagingKit/SessionMessagingKit.h>
|
||||
#import <SessionUIKit/SessionUIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
typedef void (^SendCompletionBlock)(NSError *_Nullable, TSOutgoingMessage *);
|
||||
typedef void (^SendMessageBlock)(SendCompletionBlock completion);
|
||||
|
||||
@interface SharingThreadPickerViewController () <SelectThreadViewControllerDelegate,
|
||||
AttachmentApprovalViewControllerDelegate,
|
||||
MessageApprovalViewControllerDelegate>
|
||||
|
||||
@property (nonatomic, readonly) OWSMessageSender *messageSender;
|
||||
@property (nonatomic) TSThread *thread;
|
||||
@property (nonatomic, readonly, weak) id<ShareViewDelegate> shareViewDelegate;
|
||||
@property (atomic, nullable) TSOutgoingMessage *outgoingMessage;
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@implementation SharingThreadPickerViewController
|
||||
|
||||
- (instancetype)initWithShareViewDelegate:(id<ShareViewDelegate>)shareViewDelegate
|
||||
{
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return self;
|
||||
}
|
||||
|
||||
_shareViewDelegate = shareViewDelegate;
|
||||
self.selectThreadViewDelegate = self;
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
#pragma mark - Dependencies
|
||||
|
||||
- (YapDatabaseConnection *)dbReadWriteConnection
|
||||
{
|
||||
return OWSPrimaryStorage.sharedManager.dbReadWriteConnection;
|
||||
}
|
||||
|
||||
- (YapDatabaseConnection *)dbReadConnection
|
||||
{
|
||||
return OWSPrimaryStorage.sharedManager.dbReadConnection;
|
||||
}
|
||||
|
||||
#pragma mark - UIViewController overrides
|
||||
|
||||
- (void)loadView
|
||||
{
|
||||
[super loadView];
|
||||
|
||||
self.title = NSLocalizedString(@"SHARE_EXTENSION_VIEW_TITLE", @"Title for the 'share extension' view.");
|
||||
}
|
||||
|
||||
- (void)viewDidLoad
|
||||
{
|
||||
[super viewDidLoad];
|
||||
|
||||
// Loki: Customize title
|
||||
UILabel *titleLabel = [UILabel new];
|
||||
titleLabel.text = NSLocalizedString(@"Share", @"");
|
||||
titleLabel.textColor = LKColors.text;
|
||||
titleLabel.font = [UIFont boldSystemFontOfSize:25];
|
||||
self.navigationItem.titleView = titleLabel;
|
||||
}
|
||||
|
||||
- (BOOL)canSelectBlockedContact
|
||||
{
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (nullable UIView *)createHeaderWithSearchBar:(UISearchBar *)searchBar
|
||||
{
|
||||
OWSAssertDebug(searchBar);
|
||||
|
||||
const CGFloat contentVMargin = 0;
|
||||
|
||||
UIView *header = [UIView new];
|
||||
header.backgroundColor = LKColors.navigationBarBackground;
|
||||
|
||||
UIButton *cancelShareButton = [UIButton buttonWithType:UIButtonTypeSystem];
|
||||
[header addSubview:cancelShareButton];
|
||||
|
||||
[cancelShareButton setTitle:[CommonStrings cancelButton] forState:UIControlStateNormal];
|
||||
cancelShareButton.userInteractionEnabled = YES;
|
||||
|
||||
[cancelShareButton autoPinEdgeToSuperviewMargin:ALEdgeLeading];
|
||||
[cancelShareButton autoPinEdgeToSuperviewMargin:ALEdgeBottom];
|
||||
[cancelShareButton setCompressionResistanceHigh];
|
||||
[cancelShareButton setContentHuggingHigh];
|
||||
|
||||
[cancelShareButton addTarget:self
|
||||
action:@selector(didTapCancelShareButton)
|
||||
forControlEvents:UIControlEventTouchUpInside];
|
||||
|
||||
[header addSubview:searchBar];
|
||||
[searchBar autoPinEdge:ALEdgeLeading toEdge:ALEdgeTrailing ofView:cancelShareButton withOffset:6];
|
||||
[searchBar autoPinEdgeToSuperviewEdge:ALEdgeTrailing];
|
||||
[searchBar autoPinEdgeToSuperviewEdge:ALEdgeTop];
|
||||
[searchBar autoPinEdgeToSuperviewEdge:ALEdgeBottom];
|
||||
|
||||
UIView *borderView = [UIView new];
|
||||
[header addSubview:borderView];
|
||||
|
||||
borderView.backgroundColor = [UIColor colorWithRGBHex:0xbbbbbb];
|
||||
[borderView autoSetDimension:ALDimensionHeight toSize:0.5];
|
||||
[borderView autoPinWidthToSuperview];
|
||||
[borderView autoPinEdgeToSuperviewEdge:ALEdgeBottom];
|
||||
|
||||
// UITableViewController.tableHeaderView must have its height set.
|
||||
header.frame = CGRectMake(0, 0, 0, (contentVMargin * 2 + searchBar.frame.size.height));
|
||||
|
||||
return header;
|
||||
}
|
||||
|
||||
#pragma mark - SelectThreadViewControllerDelegate
|
||||
|
||||
- (nullable NSString *)convertAttachmentToMessageTextIfPossible
|
||||
{
|
||||
if (self.attachments.count > 1) {
|
||||
return nil;
|
||||
}
|
||||
OWSAssertDebug(self.attachments.count == 1);
|
||||
SignalAttachment *attachment = self.attachments.firstObject;
|
||||
if (!attachment.isConvertibleToTextMessage) {
|
||||
return nil;
|
||||
}
|
||||
if (attachment.dataLength >= kOversizeTextMessageSizeThreshold) {
|
||||
return nil;
|
||||
}
|
||||
NSData *data = attachment.data;
|
||||
OWSAssertDebug(data.length < kOversizeTextMessageSizeThreshold);
|
||||
NSString *_Nullable messageText = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
|
||||
OWSLogVerbose(@"messageTextForAttachment: %@", messageText);
|
||||
return [messageText filterStringForDisplay];
|
||||
}
|
||||
|
||||
- (void)threadWasSelected:(TSThread *)thread
|
||||
{
|
||||
OWSAssertDebug(self.attachments.count > 0);
|
||||
OWSAssertDebug(thread);
|
||||
|
||||
self.thread = thread;
|
||||
|
||||
if ([self tryToShareAsMessageText]) {
|
||||
return;
|
||||
}
|
||||
|
||||
OWSNavigationController *approvalModal =
|
||||
[AttachmentApprovalViewController wrappedInNavControllerWithAttachments:self.attachments approvalDelegate:self];
|
||||
[self presentViewController:approvalModal animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (BOOL)tryToShareAsMessageText
|
||||
{
|
||||
OWSAssertDebug(self.attachments.count > 0);
|
||||
|
||||
NSString *_Nullable messageText = [self convertAttachmentToMessageTextIfPossible];
|
||||
if (!messageText) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
MessageApprovalViewController *approvalVC =
|
||||
[[MessageApprovalViewController alloc] initWithMessageText:messageText
|
||||
thread:self.thread
|
||||
delegate:self];
|
||||
|
||||
[self.navigationController pushViewController:approvalVC animated:YES];
|
||||
return YES;
|
||||
}
|
||||
|
||||
// override
|
||||
- (void)dismissPressed:(id)sender
|
||||
{
|
||||
OWSLogDebug(@"tapped dismiss share button");
|
||||
[self cancelShareExperience];
|
||||
}
|
||||
|
||||
- (void)didTapCancelShareButton
|
||||
{
|
||||
OWSLogDebug(@"tapped cancel share button");
|
||||
[self cancelShareExperience];
|
||||
}
|
||||
|
||||
- (void)cancelShareExperience
|
||||
{
|
||||
[self.shareViewDelegate shareViewWasCancelled];
|
||||
}
|
||||
|
||||
#pragma mark - AttachmentApprovalViewControllerDelegate
|
||||
|
||||
- (void)attachmentApproval:(AttachmentApprovalViewController *_Nonnull)attachmentApproval
|
||||
didApproveAttachments:(NSArray<SignalAttachment *> *_Nonnull)attachments
|
||||
messageText:(NSString *_Nullable)messageText
|
||||
{
|
||||
[self tryToSendMessageWithBlock:^(SendCompletionBlock sendCompletion) {
|
||||
SNVisibleMessage *message = [SNVisibleMessage new];
|
||||
message.sentTimestamp = [NSDate millisecondTimestamp];
|
||||
message.text = messageText;
|
||||
TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:self.thread];
|
||||
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[tsMessage saveWithTransaction:transaction];
|
||||
}];
|
||||
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[SNMessageSender sendNonDurably:message withAttachments:attachments inThread:self.thread usingTransaction:transaction]
|
||||
.then(^(id object) {
|
||||
sendCompletion(nil, tsMessage);
|
||||
}).catch(^(NSError *error) {
|
||||
sendCompletion(error, tsMessage);
|
||||
});
|
||||
}];
|
||||
|
||||
// This is necessary to show progress
|
||||
self.outgoingMessage = tsMessage;
|
||||
} fromViewController:attachmentApproval];
|
||||
}
|
||||
|
||||
- (void)attachmentApprovalDidCancel:(AttachmentApprovalViewController *)attachmentApproval
|
||||
{
|
||||
[self cancelShareExperience];
|
||||
}
|
||||
|
||||
- (void)attachmentApproval:(AttachmentApprovalViewController *)attachmentApproval
|
||||
didChangeMessageText:(nullable NSString *)newMessageText
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
#pragma mark - MessageApprovalViewControllerDelegate
|
||||
|
||||
- (void)messageApproval:(MessageApprovalViewController *)approvalViewController
|
||||
didApproveMessage:(NSString *)messageText
|
||||
{
|
||||
[self tryToSendMessageWithBlock:^(SendCompletionBlock sendCompletion) {
|
||||
SNVisibleMessage *message = [SNVisibleMessage new];
|
||||
message.sentTimestamp = [NSDate millisecondTimestamp];
|
||||
message.text = messageText;
|
||||
TSOutgoingMessage *tsMessage = [TSOutgoingMessage from:message associatedWith:self.thread];
|
||||
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[tsMessage saveWithTransaction:transaction];
|
||||
}];
|
||||
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
[SNMessageSender sendNonDurably:message withAttachments:@[] inThread:self.thread usingTransaction:transaction]
|
||||
.then(^(id object) {
|
||||
sendCompletion(nil, tsMessage);
|
||||
}).catch(^(NSError *error) {
|
||||
sendCompletion(error, tsMessage);
|
||||
});
|
||||
}];
|
||||
|
||||
// This is necessary to show progress
|
||||
self.outgoingMessage = tsMessage;
|
||||
} fromViewController:approvalViewController];
|
||||
}
|
||||
|
||||
- (void)messageApprovalDidCancel:(MessageApprovalViewController *)approvalViewController
|
||||
{
|
||||
[self cancelShareExperience];
|
||||
}
|
||||
|
||||
#pragma mark - Helpers
|
||||
|
||||
- (void)tryToSendMessageWithBlock:(SendMessageBlock)sendMessageBlock
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
{
|
||||
|
||||
NSString *progressTitle = NSLocalizedString(@"SHARE_EXTENSION_SENDING_IN_PROGRESS_TITLE", @"Alert title");
|
||||
UIAlertController *progressAlert = [UIAlertController alertControllerWithTitle:progressTitle
|
||||
message:nil
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction *progressCancelAction = [UIAlertAction actionWithTitle:[CommonStrings cancelButton]
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
[self.shareViewDelegate shareViewWasCancelled];
|
||||
}];
|
||||
[progressAlert addAction:progressCancelAction];
|
||||
|
||||
SendCompletionBlock sendCompletion = ^(NSError *_Nullable error, TSOutgoingMessage *message) {
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (error) {
|
||||
[fromViewController
|
||||
dismissViewControllerAnimated:YES
|
||||
completion:^{
|
||||
OWSLogInfo(@"Sending message failed with error: %@", error);
|
||||
[self showSendFailureAlertWithError:error
|
||||
message:message
|
||||
fromViewController:fromViewController];
|
||||
}];
|
||||
return;
|
||||
}
|
||||
|
||||
OWSLogInfo(@"Sending message succeeded.");
|
||||
[self.shareViewDelegate shareViewWasCompleted];
|
||||
});
|
||||
};
|
||||
|
||||
[fromViewController presentAlert:progressAlert
|
||||
completion:^{
|
||||
sendMessageBlock(sendCompletion);
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)showSendFailureAlertWithError:(NSError *)error
|
||||
message:(TSOutgoingMessage *)message
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(error);
|
||||
OWSAssertDebug(message);
|
||||
OWSAssertDebug(fromViewController);
|
||||
|
||||
NSString *failureTitle = NSLocalizedString(@"SHARE_EXTENSION_SENDING_FAILURE_TITLE", @"Alert title");
|
||||
|
||||
if ([error.domain isEqual:OWSSignalServiceKitErrorDomain] && error.code == OWSErrorCodeUntrustedIdentity) {
|
||||
NSString *_Nullable untrustedRecipientId = error.userInfo[OWSErrorRecipientIdentifierKey];
|
||||
|
||||
NSString *failureFormat = NSLocalizedString(@"SHARE_EXTENSION_FAILED_SENDING_BECAUSE_UNTRUSTED_IDENTITY_FORMAT",
|
||||
@"alert body when sharing file failed because of untrusted/changed identity keys");
|
||||
|
||||
SNContactContext context = [SNContact contextForThread:self.thread];
|
||||
NSString *displayName = [[LKStorage.shared getContactWithSessionID:untrustedRecipientId] displayNameFor:context] ?: untrustedRecipientId;
|
||||
NSString *failureMessage = [NSString stringWithFormat:failureFormat, displayName];
|
||||
|
||||
UIAlertController *failureAlert = [UIAlertController alertControllerWithTitle:failureTitle
|
||||
message:failureMessage
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction *failureCancelAction = [UIAlertAction actionWithTitle:[CommonStrings cancelButton]
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
[self.shareViewDelegate shareViewWasCancelled];
|
||||
}];
|
||||
[failureAlert addAction:failureCancelAction];
|
||||
|
||||
if (untrustedRecipientId.length > 0) {
|
||||
UIAlertAction *confirmAction =
|
||||
[UIAlertAction actionWithTitle:[SafetyNumberStrings confirmSendButton]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
[self confirmIdentityAndResendMessage:message
|
||||
recipientId:untrustedRecipientId
|
||||
fromViewController:fromViewController];
|
||||
}];
|
||||
|
||||
[failureAlert addAction:confirmAction];
|
||||
} else {
|
||||
// This shouldn't happen, but if it does we won't offer the user the ability to confirm.
|
||||
// They may have to return to the main app to accept the identity change.
|
||||
OWSFailDebug(@"Untrusted recipient error is missing recipient id.");
|
||||
}
|
||||
|
||||
[fromViewController presentAlert:failureAlert];
|
||||
} else {
|
||||
// Non-identity failure, e.g. network offline, rate limit
|
||||
|
||||
UIAlertController *failureAlert = [UIAlertController alertControllerWithTitle:failureTitle
|
||||
message:error.localizedDescription
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction *failureCancelAction = [UIAlertAction actionWithTitle:[CommonStrings cancelButton]
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
[self.shareViewDelegate shareViewWasCancelled];
|
||||
}];
|
||||
[failureAlert addAction:failureCancelAction];
|
||||
|
||||
UIAlertAction *retryAction =
|
||||
[UIAlertAction actionWithTitle:[CommonStrings retryButton]
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *action) {
|
||||
[self resendMessage:message fromViewController:fromViewController];
|
||||
}];
|
||||
|
||||
[failureAlert addAction:retryAction];
|
||||
[fromViewController presentAlert:failureAlert];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)confirmIdentityAndResendMessage:(TSOutgoingMessage *)message
|
||||
recipientId:(NSString *)recipientId
|
||||
fromViewController:(UIViewController *)fromViewController
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(message);
|
||||
OWSAssertDebug(recipientId.length > 0);
|
||||
OWSAssertDebug(fromViewController);
|
||||
|
||||
OWSLogDebug(@"Confirming identity for recipient: %@", recipientId);
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^(void) {
|
||||
[self resendMessage:message fromViewController:fromViewController];
|
||||
});
|
||||
}
|
||||
|
||||
- (void)resendMessage:(TSOutgoingMessage *)tsMessage fromViewController:(UIViewController *)fromViewController
|
||||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
OWSAssertDebug(tsMessage);
|
||||
OWSAssertDebug(fromViewController);
|
||||
|
||||
NSString *progressTitle = NSLocalizedString(@"SHARE_EXTENSION_SENDING_IN_PROGRESS_TITLE", @"Alert title");
|
||||
UIAlertController *progressAlert = [UIAlertController alertControllerWithTitle:progressTitle
|
||||
message:nil
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
UIAlertAction *progressCancelAction = [UIAlertAction actionWithTitle:[CommonStrings cancelButton]
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
[self.shareViewDelegate shareViewWasCancelled];
|
||||
}];
|
||||
[progressAlert addAction:progressCancelAction];
|
||||
|
||||
[fromViewController
|
||||
presentAlert:progressAlert
|
||||
completion:^{
|
||||
SNVisibleMessage *message = [SNVisibleMessage from:tsMessage];
|
||||
[LKStorage writeWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
|
||||
NSMutableArray<TSAttachmentStream *> *attachments = @[].mutableCopy;
|
||||
for (NSString *attachmentID in tsMessage.attachmentIds) {
|
||||
TSAttachmentStream *stream = [TSAttachmentStream fetchObjectWithUniqueID:attachmentID transaction:transaction];
|
||||
if (![stream isKindOfClass:TSAttachmentStream.class]) { continue; }
|
||||
[attachments addObject:stream];
|
||||
}
|
||||
[SNMessageSender prep:attachments forMessage:message usingTransaction: transaction];
|
||||
[SNMessageSender sendNonDurably:message withAttachmentIDs:tsMessage.attachmentIds inThread:self.thread usingTransaction:transaction]
|
||||
.thenOn(dispatch_get_main_queue(), ^() {
|
||||
[self.shareViewDelegate shareViewWasCompleted];
|
||||
})
|
||||
.catchOn(dispatch_get_main_queue(), ^(NSError *error) {
|
||||
[fromViewController dismissViewControllerAnimated:YES completion:^{
|
||||
[self showSendFailureAlertWithError:error message:tsMessage fromViewController:fromViewController];
|
||||
}];
|
||||
});
|
||||
}];
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
|
@ -14,7 +14,6 @@
|
|||
#import <SessionUtilitiesKit/NSData+Image.h>
|
||||
#import <SessionUtilitiesKit/NSNotificationCenter+OWS.h>
|
||||
#import <SessionUtilitiesKit/NSString+SSK.h>
|
||||
#import <SessionMessagingKit/OWSBlockingManager.h>
|
||||
#import <SessionUtilitiesKit/OWSFileSystem.h>
|
||||
#import <SignalUtilitiesKit/OWSPrimaryStorage+Loki.h>
|
||||
#import <SessionMessagingKit/SSKEnvironment.h>
|
||||
|
@ -102,11 +101,6 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error);
|
|||
return SSKEnvironment.shared.identityManager;
|
||||
}
|
||||
|
||||
- (OWSBlockingManager *)blockingManager
|
||||
{
|
||||
return SSKEnvironment.shared.blockingManager;
|
||||
}
|
||||
|
||||
- (void)updateLocalProfileName:(nullable NSString *)profileName
|
||||
avatarImage:(nullable UIImage *)avatarImage
|
||||
success:(void (^)(void))successBlockParameter
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@
|
|||
#import <SignalUtilitiesKit/OWSDatabaseMigration.h>
|
||||
#import <SignalUtilitiesKit/OWSProfileManager.h>
|
||||
#import <SessionMessagingKit/OWSBackgroundTask.h>
|
||||
#import <SessionMessagingKit/OWSBlockingManager.h>
|
||||
#import <SessionMessagingKit/OWSDisappearingMessagesJob.h>
|
||||
#import <SessionMessagingKit/OWSIdentityManager.h>
|
||||
#import <SessionMessagingKit/OWSOutgoingReceiptManager.h>
|
||||
|
@ -23,7 +22,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@implementation AppSetup
|
||||
|
||||
+ (void)setupEnvironmentWithAppSpecificSingletonBlock:(dispatch_block_t)appSpecificSingletonBlock
|
||||
migrationCompletion:(dispatch_block_t)migrationCompletion
|
||||
migrationCompletion:(OWSDatabaseMigrationCompletion)migrationCompletion
|
||||
{
|
||||
OWSAssertDebug(appSpecificSingletonBlock);
|
||||
OWSAssertDebug(migrationCompletion);
|
||||
|
@ -52,7 +51,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
OWSPreferences *preferences = [OWSPreferences new];
|
||||
|
||||
OWSProfileManager *profileManager = [[OWSProfileManager alloc] initWithPrimaryStorage:primaryStorage];
|
||||
OWSBlockingManager *blockingManager = [[OWSBlockingManager alloc] initWithPrimaryStorage:primaryStorage];
|
||||
OWSIdentityManager *identityManager = [[OWSIdentityManager alloc] initWithPrimaryStorage:primaryStorage];
|
||||
TSAccountManager *tsAccountManager = [[TSAccountManager alloc] initWithPrimaryStorage:primaryStorage];
|
||||
OWSDisappearingMessagesJob *disappearingMessagesJob =
|
||||
|
@ -77,7 +75,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
[SSKEnvironment setShared:[[SSKEnvironment alloc] initWithProfileManager:profileManager
|
||||
primaryStorage:primaryStorage
|
||||
blockingManager:blockingManager
|
||||
identityManager:identityManager
|
||||
tsAccountManager:tsAccountManager
|
||||
disappearingMessagesJob:disappearingMessagesJob
|
||||
|
@ -99,10 +96,10 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
[OWSStorage registerExtensionsWithMigrationBlock:^() {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
// Don't start database migrations until storage is ready.
|
||||
[VersionMigrations performUpdateCheckWithCompletion:^() {
|
||||
[VersionMigrations performUpdateCheckWithCompletion:^(BOOL successful, BOOL needsConfigSync) {
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
migrationCompletion();
|
||||
migrationCompletion(successful, needsConfigSync);
|
||||
|
||||
OWSAssertDebug(backgroundTask);
|
||||
backgroundTask = nil;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
#import "OWSUnreadIndicator.h"
|
||||
#import <SignalUtilitiesKit/OWSProfileManager.h>
|
||||
#import <SessionMessagingKit/SSKEnvironment.h>
|
||||
#import <SessionMessagingKit/OWSBlockingManager.h>
|
||||
#import <SessionMessagingKit/OWSDisappearingMessagesConfiguration.h>
|
||||
#import <SessionMessagingKit/TSAccountManager.h>
|
||||
#import <SessionMessagingKit/TSContactThread.h>
|
||||
|
@ -66,7 +65,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
#pragma mark - Dynamic Interactions
|
||||
|
||||
+ (ThreadDynamicInteractions *)ensureDynamicInteractionsForThread:(TSThread *)thread
|
||||
blockingManager:(OWSBlockingManager *)blockingManager
|
||||
dbConnection:(YapDatabaseConnection *)dbConnection
|
||||
hideUnreadMessagesIndicator:(BOOL)hideUnreadMessagesIndicator
|
||||
lastUnreadIndicator:(nullable OWSUnreadIndicator *)lastUnreadIndicator
|
||||
|
@ -75,7 +73,6 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
{
|
||||
OWSAssertDebug(thread);
|
||||
OWSAssertDebug(dbConnection);
|
||||
OWSAssertDebug(blockingManager);
|
||||
OWSAssertDebug(maxRangeSize > 0);
|
||||
|
||||
ThreadDynamicInteractions *result = [ThreadDynamicInteractions new];
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in a new issue