From 37124c21856d79d3c5b38437644792350cf5c402 Mon Sep 17 00:00:00 2001 From: Morgan Pretty Date: Wed, 28 Sep 2022 18:26:02 +1000 Subject: [PATCH] Updated the alerts to use the custom styled ones Removed some more unused code Moved around some files to make them more reusable --- Session.xcodeproj/project.pbxproj | 44 +--- Session/Closed Groups/EditClosedGroupVC.swift | 13 +- Session/Closed Groups/NewClosedGroupVC.swift | 17 +- .../ConversationVC+Interaction.swift | 248 +++++++++++------- Session/Conversations/ConversationVC.swift | 13 +- .../Settings/ThreadSettingsViewModel.swift | 6 +- Session/Home/HomeVC.swift | 2 +- Session/Home/New Conversation/NewDMVC.swift | 14 +- .../GIFs/GifPickerViewController.swift | 41 +-- .../MediaPageViewController.swift | 5 +- .../MediaTileViewController.swift | 5 +- .../PhotoCaptureViewController.swift | 2 +- .../SendMediaNavigationController.swift | 30 ++- Session/Meta/Signal-Bridging-Header.h | 1 - Session/Onboarding/DisplayNameVC.swift | 17 +- Session/Onboarding/LinkDeviceVC.swift | 15 +- Session/Onboarding/PNModeVC.swift | 14 +- Session/Onboarding/RestoreVC.swift | 2 +- Session/Open Groups/JoinOpenGroupVC.swift | 2 +- .../BlockedContactsViewController.swift | 2 +- Session/Settings/NukeDataModal.swift | 29 +- Session/Settings/QRCodeVC.swift | 15 +- Session/Settings/SettingsViewModel.swift | 6 +- Session/Shared/ScreenLockUI.swift | 16 +- .../Utilities/UIViewController+Permissions.h | 17 -- .../Utilities/UIViewController+Permissions.m | 175 ------------ .../SAEScreenLockViewController.swift | 20 +- SessionShareExtension/ShareVC.swift | 16 +- .../Components}/ConfirmationModal.swift | 15 +- .../Components}/Modal.swift | 43 +-- .../MediaMessageView.swift | 11 +- .../Messaging/BlockListUIUtils.swift | 145 ---------- SignalUtilitiesKit/Utilities/OWSAlerts.swift | 78 ------ SignalUtilitiesKit/Utilities/UIView+OWS.swift | 48 ---- 34 files changed, 395 insertions(+), 732 deletions(-) delete mode 100644 Session/Utilities/UIViewController+Permissions.h delete mode 100644 Session/Utilities/UIViewController+Permissions.m rename {Session/Sheets & Modals => SessionUIKit/Components}/ConfirmationModal.swift (96%) rename {Session/Sheets & Modals => SessionUIKit/Components}/Modal.swift (80%) delete mode 100644 SignalUtilitiesKit/Messaging/BlockListUIUtils.swift delete mode 100644 SignalUtilitiesKit/Utilities/OWSAlerts.swift diff --git a/Session.xcodeproj/project.pbxproj b/Session.xcodeproj/project.pbxproj index b8cf45753..1bd3f72f7 100644 --- a/Session.xcodeproj/project.pbxproj +++ b/Session.xcodeproj/project.pbxproj @@ -155,7 +155,6 @@ 7BC707F227290ACB002817AD /* SessionCallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BC707F127290ACB002817AD /* SessionCallManager.swift */; }; 7BCD116C27016062006330F1 /* WebRTCSession+DataChannel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BCD116B27016062006330F1 /* WebRTCSession+DataChannel.swift */; }; 7BD477A827EC39F5004E2822 /* Atomic.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD477A727EC39F5004E2822 /* Atomic.swift */; }; - 7BD477B027F526FF004E2822 /* BlockListUIUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BD477AF27F526FF004E2822 /* BlockListUIUtils.swift */; }; 7BDCFC08242186E700641C39 /* NotificationServiceExtensionContext.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */; }; 7BDCFC0B2421EB7600641C39 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = B6F509951AA53F760068F56A /* Localizable.strings */; }; 7BFA8AE32831D0D4001876F3 /* ContextMenuVC+EmojiReactsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFA8AE22831D0D4001876F3 /* ContextMenuVC+EmojiReactsView.swift */; }; @@ -205,7 +204,6 @@ B85357C323A1BD1200AAF6CD /* SeedVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B85357C223A1BD1200AAF6CD /* SeedVC.swift */; }; B8569AC325CB5D2900DBA3DB /* ConversationVC+Interaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8569AC225CB5D2900DBA3DB /* ConversationVC+Interaction.swift */; }; B8569AE325CBB19A00DBA3DB /* DocumentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8569AE225CBB19A00DBA3DB /* DocumentView.swift */; }; - B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; }; B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08523399CEF000F5AE3 /* SeedModal.swift */; }; B877E24226CA12910007970A /* CallVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B877E24126CA12910007970A /* CallVC.swift */; }; B877E24626CA13BA0007970A /* CallVC+Camera.swift in Sources */ = {isa = PBXBuildFile; fileRef = B877E24526CA13BA0007970A /* CallVC+Camera.swift */; }; @@ -216,7 +214,6 @@ B8856D08256F10F1001CE70E /* DeviceSleepManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */; }; B8856D11256F112A001CE70E /* OWSAudioSession.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF281255B6D84007E1867 /* OWSAudioSession.swift */; }; B8856D23256F116B001CE70E /* Weak.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2EF255B6DBB007E1867 /* Weak.swift */; }; - B8856D60256F129B001CE70E /* OWSAlerts.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8856D5F256F129B001CE70E /* OWSAlerts.swift */; }; B8856D72256F1421001CE70E /* OWSWindowManager.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */; settings = {ATTRIBUTES = (Public, ); }; }; B8856D7B256F14F4001CE70E /* UIView+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF23E255B6D66007E1867 /* UIView+OWS.m */; }; B8856D8D256F1502001CE70E /* UIView+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF23D255B6D66007E1867 /* UIView+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -513,7 +510,6 @@ D24B5BD5169F568C00681372 /* AudioToolbox.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D24B5BD4169F568C00681372 /* AudioToolbox.framework */; }; D2AEACDC16C426DA00C364C0 /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D2AEACDB16C426DA00C364C0 /* CFNetwork.framework */; }; DA2AE22FA77136442EF669E9 /* Pods_GlobalDependencies_Session_SessionTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B4C92F6ADBECCD47A6B6008E /* Pods_GlobalDependencies_Session_SessionTests.framework */; }; - EF764C351DB67CC5000D9A87 /* UIViewController+Permissions.m in Sources */ = {isa = PBXBuildFile; fileRef = EF764C341DB67CC5000D9A87 /* UIViewController+Permissions.m */; }; FC3BD9881A30A790005B96BB /* Social.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FC3BD9871A30A790005B96BB /* Social.framework */; }; FCB11D8C1A129A76002F93FB /* CoreMedia.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FCB11D8B1A129A76002F93FB /* CoreMedia.framework */; }; FD078E4827E02561000769AF /* CommonMockedExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD078E4727E02561000769AF /* CommonMockedExtensions.swift */; }; @@ -651,7 +647,6 @@ FD52090128AF61BA006098F6 /* OWSBackgroundTask.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB38255A580B00E217F9 /* OWSBackgroundTask.h */; settings = {ATTRIBUTES = (Public, ); }; }; FD52090328B4680F006098F6 /* RadioButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52090228B4680F006098F6 /* RadioButton.swift */; }; FD52090528B4915F006098F6 /* PrivacySettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52090428B4915F006098F6 /* PrivacySettingsViewModel.swift */; }; - FD52090728B49738006098F6 /* ConfirmationModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52090628B49738006098F6 /* ConfirmationModal.swift */; }; FD52090928B59411006098F6 /* ScreenLockUI.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52090828B59411006098F6 /* ScreenLockUI.swift */; }; FD52090B28B59BB4006098F6 /* ScreenLockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52090A28B59BB4006098F6 /* ScreenLockViewController.swift */; }; FD5C72F7284F0E560029977D /* MessageReceiver+ReadReceipts.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5C72F6284F0E560029977D /* MessageReceiver+ReadReceipts.swift */; }; @@ -705,6 +700,8 @@ FD71164E28E3F8CC00B47552 /* SessionCell+Info.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD71164D28E3F8CC00B47552 /* SessionCell+Info.swift */; }; FD71165028E3F9FA00B47552 /* SessionTableViewModel+NavItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD71164F28E3F9FA00B47552 /* SessionTableViewModel+NavItem.swift */; }; FD71165228E410BE00B47552 /* SessionTableSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD71165128E410BE00B47552 /* SessionTableSection.swift */; }; + FD71165828E436E800B47552 /* Modal.swift in Sources */ = {isa = PBXBuildFile; fileRef = B86BD08323399ACF000F5AE3 /* Modal.swift */; }; + FD71165928E436E800B47552 /* ConfirmationModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD52090628B49738006098F6 /* ConfirmationModal.swift */; }; FD7162DB281B6C440060647B /* TypedTableAlias.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD7162DA281B6C440060647B /* TypedTableAlias.swift */; }; FD716E6428502DDD00C96BF4 /* CallManagerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD716E6328502DDD00C96BF4 /* CallManagerProtocol.swift */; }; FD716E6628502EE200C96BF4 /* CurrentCallProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD716E6528502EE200C96BF4 /* CurrentCallProtocol.swift */; }; @@ -1217,7 +1214,6 @@ 7BCD116B27016062006330F1 /* WebRTCSession+DataChannel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "WebRTCSession+DataChannel.swift"; sourceTree = ""; }; 7BD477A727EC39F5004E2822 /* Atomic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = ""; }; 7BD477A927F15F24004E2822 /* OpenGroupServerIdLookup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenGroupServerIdLookup.swift; sourceTree = ""; }; - 7BD477AF27F526FF004E2822 /* BlockListUIUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockListUIUtils.swift; sourceTree = ""; }; 7BDCFC0424206E7300641C39 /* SessionNotificationServiceExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SessionNotificationServiceExtension.entitlements; sourceTree = ""; }; 7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtensionContext.swift; sourceTree = ""; }; 7BFA8AE22831D0D4001876F3 /* ContextMenuVC+EmojiReactsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContextMenuVC+EmojiReactsView.swift"; sourceTree = ""; }; @@ -1290,7 +1286,6 @@ B879D44A247E1D9200DB3608 /* PathStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathStatusView.swift; sourceTree = ""; }; B87EF17026367CF800124B3C /* FileServerAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileServerAPI.swift; sourceTree = ""; }; B87EF18026377A1D00124B3C /* Features.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Features.swift; sourceTree = ""; }; - B8856D5F256F129B001CE70E /* OWSAlerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSAlerts.swift; sourceTree = ""; }; B885D5F52334A32100EE0D8E /* UIView+Constraints.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Constraints.swift"; sourceTree = ""; }; B886B4A62398B23E00211ABE /* QRCodeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeVC.swift; sourceTree = ""; }; B886B4A82398BA1500211ABE /* QRCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCode.swift; sourceTree = ""; }; @@ -1623,8 +1618,6 @@ E1A0AD8B16E13FDD0071E604 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = System/Library/Frameworks/CoreFoundation.framework; sourceTree = SDKROOT; }; E23C1E6B7E0C12BF4ACD9CBE /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionSnodeKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionSnodeKit.debug.xcconfig"; path = "Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionSnodeKit/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionSnodeKit.debug.xcconfig"; sourceTree = ""; }; EC5C23F9D234F558BE5E41DE /* Pods-SessionUIKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionUIKit.debug.xcconfig"; path = "Target Support Files/Pods-SessionUIKit/Pods-SessionUIKit.debug.xcconfig"; sourceTree = ""; }; - EF764C331DB67CC5000D9A87 /* UIViewController+Permissions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+Permissions.h"; sourceTree = ""; }; - EF764C341DB67CC5000D9A87 /* UIViewController+Permissions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+Permissions.m"; sourceTree = ""; }; F705826F79C4A591AB35D68F /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.debug.xcconfig"; path = "Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.debug.xcconfig"; sourceTree = ""; }; 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; }; @@ -1692,7 +1685,6 @@ FD17D7E927F6A1C600122BE0 /* SUKLegacy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SUKLegacy.swift; sourceTree = ""; }; FD1C98E3282E3C5B00B76F9E /* UINavigationBar+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationBar+Utilities.swift"; sourceTree = ""; }; FD245C612850664300B966DD /* Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = ""; }; - FD28A4F327EA79F800FF65E7 /* BlockListUIUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockListUIUtils.swift; sourceTree = ""; }; FD28A4F527EAD44C00FF65E7 /* Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = ""; }; FD37E9C228A1C6F3003AE748 /* ThemeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = ""; }; FD37E9C528A1D4EC003AE748 /* Theme+ClassicDark.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+ClassicDark.swift"; sourceTree = ""; }; @@ -2196,8 +2188,6 @@ FDD2506D283711D600198BDA /* DifferenceKit+Utilities.swift */, 45C0DC1A1E68FE9000E04C47 /* UIApplication+OWS.swift */, 45C0DC1D1E69011F00E04C47 /* UIStoryboard+OWS.swift */, - EF764C331DB67CC5000D9A87 /* UIViewController+Permissions.h */, - EF764C341DB67CC5000D9A87 /* UIViewController+Permissions.m */, 45B5360D206DD8BB00D61655 /* UIResponder+OWS.swift */, 4C586924224FAB83003FD070 /* AVAudioSession+OWS.h */, 4C586925224FAB83003FD070 /* AVAudioSession+OWS.m */, @@ -2828,6 +2818,8 @@ 7BBBDC43286EAD2D00747E59 /* TappableLabel.swift */, FD09B7E228865FDA00ED0B66 /* HighlightMentionBackgroundView.swift */, C38EF3EE255B6DF6007E1867 /* GradientView.swift */, + B86BD08323399ACF000F5AE3 /* Modal.swift */, + FD52090628B49738006098F6 /* ConfirmationModal.swift */, ); path = Components; sourceTree = ""; @@ -2837,7 +2829,6 @@ children = ( C33FD9B7255A54A300E217F9 /* Meta */, C36096ED25AD20FD008B62B2 /* Media Viewing & Editing */, - C38BBA0D255E321C0041B9A3 /* Messaging */, C36096EF25AD2268008B62B2 /* Profile Pictures */, C36096EE25AD21BC008B62B2 /* Screen Lock */, C3851CD225624B060061EEB0 /* Shared Views */, @@ -2944,15 +2935,6 @@ path = "Closed Groups"; sourceTree = ""; }; - C36096AF25AD1932008B62B2 /* Sheets & Modals */ = { - isa = PBXGroup; - children = ( - B86BD08323399ACF000F5AE3 /* Modal.swift */, - FD52090628B49738006098F6 /* ConfirmationModal.swift */, - ); - path = "Sheets & Modals"; - sourceTree = ""; - }; C36096B925AD1ACF008B62B2 /* GIFs */ = { isa = PBXGroup; children = ( @@ -3106,15 +3088,6 @@ path = "Shared Views"; sourceTree = ""; }; - C38BBA0D255E321C0041B9A3 /* Messaging */ = { - isa = PBXGroup; - children = ( - FD28A4F327EA79F800FF65E7 /* BlockListUIUtils.swift */, - 7BD477AF27F526FF004E2822 /* BlockListUIUtils.swift */, - ); - path = Messaging; - sourceTree = ""; - }; C3A721332558BDDF0043A11F /* Open Groups */ = { isa = PBXGroup; children = ( @@ -3328,7 +3301,6 @@ C38EF3E4255B6DF4007E1867 /* CommonStrings.swift */, C38EF304255B6DBE007E1867 /* ImageCache.swift */, C38EF2F2255B6DBC007E1867 /* Searcher.swift */, - B8856D5F256F129B001CE70E /* OWSAlerts.swift */, C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */, C33FDA8B255A57FD00E217F9 /* AppVersion.m */, C33FDB69255A580F00E217F9 /* FeatureFlags.swift */, @@ -3506,7 +3478,6 @@ C360969A25AD17E3008B62B2 /* Path */, C360969125AD1765008B62B2 /* Settings */, B8CCF63B239757C10091D419 /* Shared */, - C36096AF25AD1932008B62B2 /* Sheets & Modals */, 76EB03C118170B33006006FC /* Utilities */, ); path = Session; @@ -5142,7 +5113,9 @@ buildActionMask = 2147483647; files = ( C331FF972558FA6B00070591 /* Fonts.swift in Sources */, + FD71165828E436E800B47552 /* Modal.swift in Sources */, FD37E9D328A1FCDB003AE748 /* Theme+OceanDark.swift in Sources */, + FD71165928E436E800B47552 /* ConfirmationModal.swift in Sources */, 7BBBDC44286EAD2D00747E59 /* TappableLabel.swift in Sources */, FD09B7E328865FDA00ED0B66 /* HighlightMentionBackgroundView.swift in Sources */, C331FFB82558FA8D00070591 /* DeviceUtilities.swift in Sources */, @@ -5237,7 +5210,6 @@ C38EF3C0255B6DE7007E1867 /* ImageEditorCropViewController.swift in Sources */, FD52090B28B59BB4006098F6 /* ScreenLockViewController.swift in Sources */, C38EF401255B6DF7007E1867 /* VideoPlayerView.swift in Sources */, - B8856D60256F129B001CE70E /* OWSAlerts.swift in Sources */, C38EF3BD255B6DE7007E1867 /* ImageEditorTransform.swift in Sources */, C38EF24F255B6D67007E1867 /* UIColor+OWS.m in Sources */, C33FDC9A255A582000E217F9 /* ByteParser.m in Sources */, @@ -5245,7 +5217,6 @@ C33FDC78255A582000E217F9 /* TSConstants.m in Sources */, C38EF324255B6DBF007E1867 /* Bench.swift in Sources */, FDCDB8DE2810F73B00352A0C /* Differentiable+Utilities.swift in Sources */, - 7BD477B027F526FF004E2822 /* BlockListUIUtils.swift in Sources */, C38EF3F9255B6DF7007E1867 /* OWSLayerView.swift in Sources */, C33FDD03255A582000E217F9 /* WeakTimer.swift in Sources */, C38EF3B9255B6DE7007E1867 /* ImageEditorPinchGestureRecognizer.swift in Sources */, @@ -5621,7 +5592,6 @@ C3548F0824456AB6009433A8 /* UIView+Wrapping.swift in Sources */, B82B408A2399EC0600A248E7 /* FakeChatView.swift in Sources */, B82B40882399EB0E00A248E7 /* LandingVC.swift in Sources */, - EF764C351DB67CC5000D9A87 /* UIViewController+Permissions.m in Sources */, 45CD81EF1DC030E7004C9430 /* SyncPushTokensJob.swift in Sources */, B83524A525C3BA4B0089A44F /* InfoMessageCell.swift in Sources */, 7B9F71D82853100A006DFE7B /* EmojiWithSkinTones.swift in Sources */, @@ -5672,7 +5642,6 @@ 7B46AAAF28766DF4001AF2DC /* AllMediaViewController.swift in Sources */, FD71162228D983ED00B47552 /* QRCodeScanningViewController.swift in Sources */, C331FFFE2558FF3B00070591 /* FullConversationCell.swift in Sources */, - FD52090728B49738006098F6 /* ConfirmationModal.swift in Sources */, B8D84EA325DF745A005A043E /* LinkPreviewState.swift in Sources */, 45C0DC1E1E69011F00E04C47 /* UIStoryboard+OWS.swift in Sources */, B82B408E239DC00D00A248E7 /* DisplayNameVC.swift in Sources */, @@ -5783,7 +5752,6 @@ C328251F25CA3A900062D0A7 /* QuoteView.swift in Sources */, FD37E9CC28A1E578003AE748 /* AppearanceViewController.swift in Sources */, B8EB20F02640F7F000773E52 /* OpenGroupInvitationView.swift in Sources */, - B86BD08423399ACF000F5AE3 /* Modal.swift in Sources */, C328254025CA55880062D0A7 /* ContextMenuVC.swift in Sources */, 3427C64320F500E000EEC730 /* OWSMessageTimerView.m in Sources */, B8269D2925C7A4B400488AB4 /* InputView.swift in Sources */, diff --git a/Session/Closed Groups/EditClosedGroupVC.swift b/Session/Closed Groups/EditClosedGroupVC.swift index f40d7df22..0a8a93b55 100644 --- a/Session/Closed Groups/EditClosedGroupVC.swift +++ b/Session/Closed Groups/EditClosedGroupVC.swift @@ -454,8 +454,15 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat // MARK: - Convenience private func showError(title: String, message: String = "") { - let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "BUTTON_OK".localized(), style: .default, handler: nil)) - presentAlert(alert) + let modal: ConfirmationModal = ConfirmationModal( + targetView: self.view, + info: ConfirmationModal.Info( + title: title, + explanation: message, + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) + ) + self.present(modal, animated: true) } } diff --git a/Session/Closed Groups/NewClosedGroupVC.swift b/Session/Closed Groups/NewClosedGroupVC.swift index 743d1e57d..30e568bcb 100644 --- a/Session/Closed Groups/NewClosedGroupVC.swift +++ b/Session/Closed Groups/NewClosedGroupVC.swift @@ -296,7 +296,7 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate title: title, explanation: message, cancelTitle: "BUTTON_OK".localized(), - cancelStyle: .textPrimary + cancelStyle: .alert_text ) ) present(modal, animated: true) @@ -334,11 +334,16 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate .catch(on: DispatchQueue.main) { [weak self] _ in self?.dismiss(animated: true, completion: nil) // Dismiss the loader - let title = "Couldn't Create Group" - let message = "Please check your internet connection and try again." - let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "BUTTON_OK".localized(), style: .default, handler: nil)) - self?.presentAlert(alert) + let modal: ConfirmationModal = ConfirmationModal( + targetView: self?.view, + info: ConfirmationModal.Info( + title: "Couldn't Create Group", + explanation: "Please check your internet connection and try again.", + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) + ) + self?.present(modal, animated: true) } .retainUntilComplete() } diff --git a/Session/Conversations/ConversationVC+Interaction.swift b/Session/Conversations/ConversationVC+Interaction.swift index 100b37078..d9e90db04 100644 --- a/Session/Conversations/ConversationVC+Interaction.swift +++ b/Session/Conversations/ConversationVC+Interaction.swift @@ -262,29 +262,49 @@ extension ConversationVC: } catch { DispatchQueue.main.async { [weak self] in - let alert = UIAlertController(title: "Session", message: "An error occurred.", preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) - - self?.present(alert, animated: true, completion: nil) + let modal: ConfirmationModal = ConfirmationModal( + targetView: self?.view, + info: ConfirmationModal.Info( + title: "Session", + explanation: "An error occurred.", + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) + ) + self?.present(modal, animated: true) } return } let type = urlResourceValues.typeIdentifier ?? (kUTTypeData as String) guard urlResourceValues.isDirectory != true else { - DispatchQueue.main.async { - OWSAlerts.showAlert( - title: "ATTACHMENT_PICKER_DOCUMENTS_PICKED_DIRECTORY_FAILED_ALERT_TITLE".localized(), - message: "ATTACHMENT_PICKER_DOCUMENTS_PICKED_DIRECTORY_FAILED_ALERT_BODY".localized() + DispatchQueue.main.async { [weak self] in + let modal: ConfirmationModal = ConfirmationModal( + targetView: self?.view, + info: ConfirmationModal.Info( + title: "ATTACHMENT_PICKER_DOCUMENTS_PICKED_DIRECTORY_FAILED_ALERT_TITLE".localized(), + explanation: "ATTACHMENT_PICKER_DOCUMENTS_PICKED_DIRECTORY_FAILED_ALERT_BODY".localized(), + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) ) + self?.present(modal, animated: true) } return } let fileName = urlResourceValues.name ?? NSLocalizedString("ATTACHMENT_DEFAULT_FILENAME", comment: "") guard let dataSource = DataSourcePath.dataSource(with: url, shouldDeleteOnDeallocation: false) else { - DispatchQueue.main.async { - OWSAlerts.showAlert(title: "ATTACHMENT_PICKER_DOCUMENTS_FAILED_ALERT_TITLE".localized()) + DispatchQueue.main.async { [weak self] in + let modal: ConfirmationModal = ConfirmationModal( + targetView: self?.view, + info: ConfirmationModal.Info( + title: "ATTACHMENT_PICKER_DOCUMENTS_FAILED_ALERT_TITLE".localized(), + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) + ) + self?.present(modal, animated: true) } return } @@ -364,7 +384,7 @@ extension ConversationVC: explanation: "modal_send_seed_explanation".localized(), confirmTitle: "modal_send_seed_send_button_title".localized(), confirmStyle: .danger, - cancelStyle: .textPrimary, + cancelStyle: .alert_text, onConfirm: { [weak self] _ in self?.sendMessage(hasPermissionToSendSeed: true) } ) ) @@ -487,7 +507,7 @@ extension ConversationVC: explanation: "modal_send_seed_explanation".localized(), confirmTitle: "modal_send_seed_send_button_title".localized(), confirmStyle: .danger, - cancelStyle: .textPrimary, + cancelStyle: .alert_text, onConfirm: { [weak self] _ in self?.sendAttachments(attachments, with: text, hasPermissionToSendSeed: true, onComplete: onComplete) } @@ -1000,24 +1020,25 @@ extension ConversationVC: guard let url: URL = URL(string: urlString) else { return } // URLs can be unsafe, so always ask the user whether they want to open one - let alertVC = UIAlertController( + let actionSheet: UIAlertController = UIAlertController( title: "modal_open_url_title".localized(), message: String(format: "modal_open_url_explanation".localized(), url.absoluteString), preferredStyle: .actionSheet ) - alertVC.addAction(UIAlertAction(title: "modal_open_url_button_title".localized(), style: .default) { [weak self] _ in + actionSheet.addAction(UIAlertAction(title: "modal_open_url_button_title".localized(), style: .default) { [weak self] _ in UIApplication.shared.open(url, options: [:], completionHandler: nil) self?.showInputAccessoryView() }) - alertVC.addAction(UIAlertAction(title: "modal_copy_url_button_title".localized(), style: .default) { [weak self] _ in + actionSheet.addAction(UIAlertAction(title: "modal_copy_url_button_title".localized(), style: .default) { [weak self] _ in UIPasteboard.general.string = url.absoluteString self?.showInputAccessoryView() }) - alertVC.addAction(UIAlertAction(title: "cancel".localized(), style: .cancel) { [weak self] _ in + actionSheet.addAction(UIAlertAction(title: "cancel".localized(), style: .cancel) { [weak self] _ in self?.showInputAccessoryView() }) - self.presentAlert(alertVC) + Modal.setupForIPadIfNeeded(actionSheet, targetView: self.view) + self.present(actionSheet, animated: true) } func handleReplyButtonTapped(for cellViewModel: MessageViewModel) { @@ -1474,7 +1495,7 @@ extension ConversationVC: info: ConfirmationModal.Info( title: "Couldn't Join", cancelTitle: "BUTTON_OK".localized(), - cancelStyle: .textPrimary + cancelStyle: .alert_text ) ) @@ -1502,7 +1523,7 @@ extension ConversationVC: title: "Couldn't Join", explanation: error.localizedDescription, cancelTitle: "BUTTON_OK".localized(), - cancelStyle: .textPrimary + cancelStyle: .alert_text ) ) @@ -1746,8 +1767,8 @@ extension ConversationVC: return } - let alertVC = UIAlertController.init(title: nil, message: nil, preferredStyle: .actionSheet) - alertVC.addAction(UIAlertAction(title: "delete_message_for_me".localized(), style: .destructive) { [weak self] _ in + let actionSheet: UIAlertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) + actionSheet.addAction(UIAlertAction(title: "delete_message_for_me".localized(), style: .destructive) { [weak self] _ in Storage.shared.writeAsync { db in _ = try Interaction .filter(id: cellViewModel.id) @@ -1765,7 +1786,7 @@ extension ConversationVC: self?.showInputAccessoryView() }) - alertVC.addAction(UIAlertAction( + actionSheet.addAction(UIAlertAction( title: (cellViewModel.threadVariant == .closedGroup ? "delete_message_for_everyone".localized() : String(format: "delete_message_for_me_and_recipient".localized(), threadName) @@ -1799,13 +1820,14 @@ extension ConversationVC: } }) - alertVC.addAction(UIAlertAction.init(title: "TXT_CANCEL_TITLE".localized(), style: .cancel) { [weak self] _ in + actionSheet.addAction(UIAlertAction.init(title: "TXT_CANCEL_TITLE".localized(), style: .cancel) { [weak self] _ in self?.showInputAccessoryView() }) self.inputAccessoryView?.isHidden = true self.inputAccessoryView?.alpha = 0 - self.presentAlert(alertVC) + Modal.setupForIPadIfNeeded(actionSheet, targetView: self.view) + self.present(actionSheet, animated: true) } } @@ -1871,78 +1893,98 @@ extension ConversationVC: guard cellViewModel.threadVariant == .openGroup else { return } let threadId: String = self.viewModel.threadData.threadId - let alert: UIAlertController = UIAlertController( - title: "Session", - message: "This will ban the selected user from this room. It won't ban them from other rooms.", - preferredStyle: .alert - ) - alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak self] _ in - Storage.shared - .read { db -> Promise in - guard let openGroup: OpenGroup = try OpenGroup.fetchOne(db, id: threadId) else { - return Promise(error: StorageError.objectNotFound) - } + let modal: ConfirmationModal = ConfirmationModal( + targetView: self.view, + info: ConfirmationModal.Info( + title: "Session", + explanation: "This will ban the selected user from this room. It won't ban them from other rooms.", + confirmTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text, + onConfirm: { [weak self] _ in + Storage.shared + .read { db -> Promise in + guard let openGroup: OpenGroup = try OpenGroup.fetchOne(db, id: threadId) else { + return Promise(error: StorageError.objectNotFound) + } + + return OpenGroupAPI + .userBan( + db, + sessionId: cellViewModel.authorId, + from: [openGroup.roomToken], + on: openGroup.server + ) + .map { _ in () } + } + .catch(on: DispatchQueue.main) { _ in + let modal: ConfirmationModal = ConfirmationModal( + targetView: self?.view, + info: ConfirmationModal.Info( + title: CommonStrings.errorAlertTitle, + explanation: "context_menu_ban_user_error_alert_message".localized(), + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) + ) + self?.present(modal, animated: true) + } + .retainUntilComplete() - return OpenGroupAPI - .userBan( - db, - sessionId: cellViewModel.authorId, - from: [openGroup.roomToken], - on: openGroup.server - ) - .map { _ in () } - } - .catch(on: DispatchQueue.main) { _ in - OWSAlerts.showErrorAlert(message: "context_menu_ban_user_error_alert_message".localized()) - } - .retainUntilComplete() - - self?.becomeFirstResponder() - })) - alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { [weak self] _ in - self?.becomeFirstResponder() - })) - - present(alert, animated: true, completion: nil) + self?.becomeFirstResponder() + }, + afterClosed: { [weak self] in self?.becomeFirstResponder() } + ) + ) + self.present(modal, animated: true) } func banAndDeleteAllMessages(_ cellViewModel: MessageViewModel) { guard cellViewModel.threadVariant == .openGroup else { return } let threadId: String = self.viewModel.threadData.threadId - let alert: UIAlertController = UIAlertController( - title: "Session", - message: "This will ban the selected user from this room and delete all messages sent by them. It won't ban them from other rooms or delete the messages they sent there.", - preferredStyle: .alert + let modal: ConfirmationModal = ConfirmationModal( + targetView: self.view, + info: ConfirmationModal.Info( + title: "Session", + explanation: "This will ban the selected user from this room and delete all messages sent by them. It won't ban them from other rooms or delete the messages they sent there.", + confirmTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text, + onConfirm: { [weak self] _ in + Storage.shared + .read { db -> Promise in + guard let openGroup: OpenGroup = try OpenGroup.fetchOne(db, id: threadId) else { + return Promise(error: StorageError.objectNotFound) + } + + return OpenGroupAPI + .userBanAndDeleteAllMessages( + db, + sessionId: cellViewModel.authorId, + in: openGroup.roomToken, + on: openGroup.server + ) + .map { _ in () } + } + .catch(on: DispatchQueue.main) { _ in + let modal: ConfirmationModal = ConfirmationModal( + targetView: self?.view, + info: ConfirmationModal.Info( + title: CommonStrings.errorAlertTitle, + explanation: "context_menu_ban_user_error_alert_message".localized(), + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) + ) + self?.present(modal, animated: true) + } + .retainUntilComplete() + + self?.becomeFirstResponder() + }, + afterClosed: { [weak self] in self?.becomeFirstResponder() } + ) ) - alert.addAction(UIAlertAction(title: "OK", style: .default, handler: { [weak self] _ in - Storage.shared - .read { db -> Promise in - guard let openGroup: OpenGroup = try OpenGroup.fetchOne(db, id: threadId) else { - return Promise(error: StorageError.objectNotFound) - } - - return OpenGroupAPI - .userBanAndDeleteAllMessages( - db, - sessionId: cellViewModel.authorId, - in: openGroup.roomToken, - on: openGroup.server - ) - .map { _ in () } - } - .catch(on: DispatchQueue.main) { _ in - OWSAlerts.showErrorAlert(message: "context_menu_ban_user_error_alert_message".localized()) - } - .retainUntilComplete() - - self?.becomeFirstResponder() - })) - alert.addAction(UIAlertAction(title: "Cancel", style: .default, handler: { [weak self] _ in - self?.becomeFirstResponder() - })) - - present(alert, animated: true, completion: nil) + self.present(modal, animated: true) } // MARK: - VoiceMessageRecordingViewDelegate @@ -2032,10 +2074,16 @@ extension ConversationVC: guard duration > 1 else { self.audioRecorder = nil - OWSAlerts.showAlert( - title: "VOICE_MESSAGE_TOO_SHORT_ALERT_TITLE".localized(), - message: "VOICE_MESSAGE_TOO_SHORT_ALERT_MESSAGE".localized() + let modal: ConfirmationModal = ConfirmationModal( + targetView: self.view, + info: ConfirmationModal.Info( + title: "VOICE_MESSAGE_TOO_SHORT_ALERT_TITLE".localized(), + explanation: "VOICE_MESSAGE_TOO_SHORT_ALERT_MESSAGE".localized(), + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) ) + self.present(modal, animated: true) return } @@ -2096,13 +2144,17 @@ extension ConversationVC: // MARK: - Convenience func showErrorAlert(for attachment: SignalAttachment, onDismiss: (() -> ())?) { - OWSAlerts.showAlert( - title: "ATTACHMENT_ERROR_ALERT_TITLE".localized(), - message: (attachment.localizedErrorDescription ?? SignalAttachment.missingDataErrorMessage), - buttonTitle: nil - ) { _ in - onDismiss?() - } + let modal: ConfirmationModal = ConfirmationModal( + targetView: self.view, + info: ConfirmationModal.Info( + title: "ATTACHMENT_ERROR_ALERT_TITLE".localized(), + explanation: (attachment.localizedErrorDescription ?? SignalAttachment.missingDataErrorMessage), + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text, + afterClosed: onDismiss + ) + ) + self.present(modal, animated: true) } } diff --git a/Session/Conversations/ConversationVC.swift b/Session/Conversations/ConversationVC.swift index e13954ab1..4ef01d631 100644 --- a/Session/Conversations/ConversationVC.swift +++ b/Session/Conversations/ConversationVC.swift @@ -1181,9 +1181,18 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl with: cellViewModel, mediaCache: mediaCache, playbackInfo: viewModel.playbackInfo(for: cellViewModel) { updatedInfo, error in - DispatchQueue.main.async { + DispatchQueue.main.async { [weak self] in guard error == nil else { - OWSAlerts.showErrorAlert(message: "INVALID_AUDIO_FILE_ALERT_ERROR_MESSAGE".localized()) + let modal: ConfirmationModal = ConfirmationModal( + targetView: self?.view, + info: ConfirmationModal.Info( + title: CommonStrings.errorAlertTitle, + explanation: "INVALID_AUDIO_FILE_ALERT_ERROR_MESSAGE".localized(), + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) + ) + self?.present(modal, animated: true) return } diff --git a/Session/Conversations/Settings/ThreadSettingsViewModel.swift b/Session/Conversations/Settings/ThreadSettingsViewModel.swift index c7d40a8c9..ca75e8a25 100644 --- a/Session/Conversations/Settings/ThreadSettingsViewModel.swift +++ b/Session/Conversations/Settings/ThreadSettingsViewModel.swift @@ -380,7 +380,7 @@ class ThreadSettingsViewModel: SessionTableViewModel #import #import diff --git a/Session/Onboarding/DisplayNameVC.swift b/Session/Onboarding/DisplayNameVC.swift index 45f47ffac..fd4084d4b 100644 --- a/Session/Onboarding/DisplayNameVC.swift +++ b/Session/Onboarding/DisplayNameVC.swift @@ -152,16 +152,23 @@ final class DisplayNameVC: BaseVC { @objc private func register() { func showError(title: String, message: String = "") { - let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_OK", comment: ""), style: .default, handler: nil)) - presentAlert(alert) + let modal: ConfirmationModal = ConfirmationModal( + targetView: self.view, + info: ConfirmationModal.Info( + title: title, + explanation: message, + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) + ) + self.present(modal, animated: true) } let displayName = displayNameTextField.text!.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) guard !displayName.isEmpty else { - return showError(title: NSLocalizedString("vc_display_name_display_name_missing_error", comment: "")) + return showError(title: "vc_display_name_display_name_missing_error".localized()) } guard !ProfileManager.isToLong(profileName: displayName) else { - return showError(title: NSLocalizedString("vc_display_name_display_name_too_long_error", comment: "")) + return showError(title: "vc_display_name_display_name_too_long_error".localized()) } // Try to save the user name but ignore the result diff --git a/Session/Onboarding/LinkDeviceVC.swift b/Session/Onboarding/LinkDeviceVC.swift index dfff99192..4a81ee495 100644 --- a/Session/Onboarding/LinkDeviceVC.swift +++ b/Session/Onboarding/LinkDeviceVC.swift @@ -143,7 +143,7 @@ final class LinkDeviceVC: BaseVC, UIPageViewControllerDataSource, UIPageViewCont title: "invalid_recovery_phrase".localized(), explanation: "INVALID_RECOVERY_PHRASE_MESSAGE".localized(), cancelTitle: "BUTTON_OK".localized(), - cancelStyle: .textPrimary, + cancelStyle: .alert_text, afterClosed: { [weak self] in self?.scanQRCodeWrapperVC.startCapture() } @@ -308,9 +308,16 @@ private final class RecoveryPhraseVC: UIViewController { @objc private func handleContinueButtonTapped() { func showError(title: String, message: String = "") { - let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "BUTTON_OK".localized(), style: .default, handler: nil)) - presentAlert(alert) + let modal: ConfirmationModal = ConfirmationModal( + targetView: self.view, + info: ConfirmationModal.Info( + title: title, + explanation: message, + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) + ) + self.present(modal, animated: true) } let mnemonic = mnemonicTextView.text!.lowercased() do { diff --git a/Session/Onboarding/PNModeVC.swift b/Session/Onboarding/PNModeVC.swift index d14d2170c..8864fb26c 100644 --- a/Session/Onboarding/PNModeVC.swift +++ b/Session/Onboarding/PNModeVC.swift @@ -115,10 +115,16 @@ final class PNModeVC: BaseVC, OptionViewDelegate { @objc private func register() { guard selectedOptionView != nil else { - let title = "vc_pn_mode_no_option_picked_modal_title".localized() - let alert = UIAlertController(title: title, message: nil, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "BUTTON_OK".localized(), style: .default, handler: nil)) - return presentAlert(alert) + let modal: ConfirmationModal = ConfirmationModal( + targetView: self.view, + info: ConfirmationModal.Info( + title: "vc_pn_mode_no_option_picked_modal_title".localized(), + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) + ) + self.present(modal, animated: true) + return } UserDefaults.standard[.isUsingFullAPNs] = (selectedOptionView == apnsOptionView) diff --git a/Session/Onboarding/RestoreVC.swift b/Session/Onboarding/RestoreVC.swift index 768f5cbaf..0e6496757 100644 --- a/Session/Onboarding/RestoreVC.swift +++ b/Session/Onboarding/RestoreVC.swift @@ -188,7 +188,7 @@ final class RestoreVC: BaseVC { title: title, explanation: message, cancelTitle: "BUTTON_OK".localized(), - cancelStyle: .textPrimary + cancelStyle: .alert_text ) ) present(modal, animated: true) diff --git a/Session/Open Groups/JoinOpenGroupVC.swift b/Session/Open Groups/JoinOpenGroupVC.swift index 1acc23f7f..e0ed47b2c 100644 --- a/Session/Open Groups/JoinOpenGroupVC.swift +++ b/Session/Open Groups/JoinOpenGroupVC.swift @@ -199,7 +199,7 @@ final class JoinOpenGroupVC: BaseVC, UIPageViewControllerDataSource, UIPageViewC title: title, explanation: message, cancelTitle: "BUTTON_OK".localized(), - cancelStyle: .textPrimary + cancelStyle: .alert_text ) ) self.navigationController?.present(confirmationModal, animated: true, completion: nil) diff --git a/Session/Settings/BlockedContactsViewController.swift b/Session/Settings/BlockedContactsViewController.swift index f8c305364..9a4d0fcad 100644 --- a/Session/Settings/BlockedContactsViewController.swift +++ b/Session/Settings/BlockedContactsViewController.swift @@ -487,7 +487,7 @@ class BlockedContactsViewController: BaseVC, UITableViewDelegate, UITableViewDat title: confirmationTitle, confirmTitle: "CONVERSATION_SETTINGS_BLOCKED_CONTACTS_UNBLOCK_CONFIRMATION_ACTON".localized(), confirmStyle: .danger, - cancelStyle: .textPrimary + cancelStyle: .alert_text ) { _ in // Unblock the contacts Storage.shared.write { db in diff --git a/Session/Settings/NukeDataModal.swift b/Session/Settings/NukeDataModal.swift index 45c717fa1..e08698410 100644 --- a/Session/Settings/NukeDataModal.swift +++ b/Session/Settings/NukeDataModal.swift @@ -138,7 +138,7 @@ final class NukeDataModal: Modal { explanation: "modal_clear_all_data_explanation_2".localized(), confirmTitle: "modal_clear_all_data_confirm".localized(), confirmStyle: .danger, - cancelStyle: .textPrimary, + cancelStyle: .alert_text, dismissOnConfirm: false ) { [weak self] confirmationModal in self?.clearEntireAccount(presentedViewController: confirmationModal) @@ -180,18 +180,31 @@ final class NukeDataModal: Modal { message = String(format: "dialog_clear_all_data_deletion_failed_2".localized(), String(potentiallyMaliciousSnodes.count), potentiallyMaliciousSnodes.joined(separator: ", ")) } - let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "BUTTON_OK".localized(), style: .default, handler: nil)) - - self?.presentAlert(alert) + let modal: ConfirmationModal = ConfirmationModal( + targetView: self?.view, + info: ConfirmationModal.Info( + title: "Error", + explanation: message, + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) + ) + self?.present(modal, animated: true) } } .catch(on: DispatchQueue.main) { error in self?.dismiss(animated: true, completion: nil) // Dismiss the loader - let alert = UIAlertController(title: "Error", message: error.localizedDescription, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "BUTTON_OK".localized(), style: .default, handler: nil)) - self?.presentAlert(alert) + let modal: ConfirmationModal = ConfirmationModal( + targetView: self?.view, + info: ConfirmationModal.Info( + title: "Error", + explanation: error.localizedDescription, + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) + ) + self?.present(modal, animated: true) } } } diff --git a/Session/Settings/QRCodeVC.swift b/Session/Settings/QRCodeVC.swift index 19fa728a2..c1b34d08e 100644 --- a/Session/Settings/QRCodeVC.swift +++ b/Session/Settings/QRCodeVC.swift @@ -124,11 +124,16 @@ final class QRCodeVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControl fileprivate func startNewPrivateChatIfPossible(with hexEncodedPublicKey: String) { if !ECKeyPair.isValidHexEncodedPublicKey(candidate: hexEncodedPublicKey) { - let alert = UIAlertController( - title: "invalid_session_id".localized(), - message: "INVALID_SESSION_ID_MESSAGE".localized(), preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "BUTTON_OK".localized(), style: .default, handler: nil)) - presentAlert(alert) + let modal: ConfirmationModal = ConfirmationModal( + targetView: self.view, + info: ConfirmationModal.Info( + title: "invalid_session_id".localized(), + explanation: "INVALID_SESSION_ID_MESSAGE".localized(), + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) + ) + self.present(modal, animated: true) } else { let maybeThread: SessionThread? = Storage.shared.write { db in diff --git a/Session/Settings/SettingsViewModel.swift b/Session/Settings/SettingsViewModel.swift index ae84288ac..f1faab4c7 100644 --- a/Session/Settings/SettingsViewModel.swift +++ b/Session/Settings/SettingsViewModel.swift @@ -89,7 +89,7 @@ class SettingsViewModel: SessionTableViewModel - -NS_ASSUME_NONNULL_BEGIN - -@interface UIViewController (Permissions) - -- (void)ows_askForCameraPermissions:(void (^)(BOOL granted))callback; -- (void)ows_askForMediaLibraryPermissions:(void (^)(BOOL granted))callbackParam; -- (void)ows_askForMicrophonePermissions:(void (^)(BOOL granted))callback; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Session/Utilities/UIViewController+Permissions.m b/Session/Utilities/UIViewController+Permissions.m deleted file mode 100644 index 9dce25003..000000000 --- a/Session/Utilities/UIViewController+Permissions.m +++ /dev/null @@ -1,175 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -#import "UIViewController+Permissions.h" -#import "Session-Swift.h" -#import -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -@implementation UIViewController (Permissions) - -- (void)ows_askForCameraPermissions:(void (^)(BOOL granted))callbackParam -{ - OWSLogVerbose(@"[%@] ows_askForCameraPermissions", NSStringFromClass(self.class)); - - // Ensure callback is invoked on main thread. - void (^callback)(BOOL) = ^(BOOL granted) { - DispatchMainThreadSafe(^{ - callbackParam(granted); - }); - }; - - if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) { - OWSLogError(@"Skipping camera permissions request when app is in background."); - callback(NO); - return; - } - - if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) { - OWSLogError(@"Camera ImagePicker source not available"); - callback(NO); - return; - } - - AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; - if (status == AVAuthorizationStatusDenied) { - UIAlertController *alert = [UIAlertController - alertControllerWithTitle:NSLocalizedString(@"Session needs camera access to scan QR codes.", @"") - message:NSLocalizedString(@"You can enable camera access in your device settings.", @"") - preferredStyle:UIAlertControllerStyleAlert]; - - UIAlertAction *openSettingsAction = - [UIAlertAction actionWithTitle:CommonStrings.openSettingsButton - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - [[UIApplication sharedApplication] openSystemSettings]; - callback(NO); - }]; - [alert addAction:openSettingsAction]; - - UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:CommonStrings.dismissButton - style:UIAlertActionStyleCancel - handler:^(UIAlertAction *action) { - callback(NO); - }]; - [alert addAction:dismissAction]; - - [self presentAlert:alert]; - } else if (status == AVAuthorizationStatusAuthorized) { - callback(YES); - } else if (status == AVAuthorizationStatusNotDetermined) { - [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo - completionHandler:callback]; - } else { - OWSLogError(@"Unknown AVAuthorizationStatus: %ld", (long)status); - callback(NO); - } -} - -- (void)ows_askForMediaLibraryPermissions:(void (^)(BOOL granted))callbackParam -{ - OWSLogVerbose(@"[%@] ows_askForMediaLibraryPermissions", NSStringFromClass(self.class)); - - // Ensure callback is invoked on main thread. - void (^completionCallback)(BOOL) = ^(BOOL granted) { - DispatchMainThreadSafe(^{ - callbackParam(granted); - }); - }; - - void (^presentSettingsDialog)(void) = ^(void) { - DispatchMainThreadSafe(^{ - UIAlertController *alert = [UIAlertController - alertControllerWithTitle:NSLocalizedString(@"MISSING_MEDIA_LIBRARY_PERMISSION_TITLE", - @"Alert title when user has previously denied media library access") - message:NSLocalizedString(@"MISSING_MEDIA_LIBRARY_PERMISSION_MESSAGE", - @"Alert body when user has previously denied media library access") - preferredStyle:UIAlertControllerStyleAlert]; - - UIAlertAction *openSettingsAction = - [UIAlertAction actionWithTitle:CommonStrings.openSettingsButton - style:UIAlertActionStyleDefault - handler:^(UIAlertAction *_Nonnull action) { - [[UIApplication sharedApplication] openSystemSettings]; - completionCallback(NO); - }]; - [alert addAction:openSettingsAction]; - - UIAlertAction *dismissAction = [UIAlertAction actionWithTitle:CommonStrings.dismissButton - style:UIAlertActionStyleCancel - handler:^(UIAlertAction *action) { - completionCallback(NO); - }]; - [alert addAction:dismissAction]; - - [self presentAlert:alert]; - }); - }; - - if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) { - OWSLogError(@"Skipping media library permissions request when app is in background."); - completionCallback(NO); - return; - } - - if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypePhotoLibrary]) { - OWSLogError(@"PhotoLibrary ImagePicker source not available"); - completionCallback(NO); - } - - PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus]; - - switch (status) { - case PHAuthorizationStatusAuthorized: { - completionCallback(YES); - return; - } - case PHAuthorizationStatusDenied: { - presentSettingsDialog(); - return; - } - case PHAuthorizationStatusNotDetermined: { - [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus newStatus) { - if (newStatus == PHAuthorizationStatusAuthorized) { - completionCallback(YES); - } else { - presentSettingsDialog(); - } - }]; - return; - } - case PHAuthorizationStatusRestricted: { - // when does this happen? - OWSFailDebug(@"PHAuthorizationStatusRestricted"); - return; - } - } -} - -- (void)ows_askForMicrophonePermissions:(void (^)(BOOL granted))callbackParam -{ - OWSLogVerbose(@"[%@] ows_askForMicrophonePermissions", NSStringFromClass(self.class)); - - // Ensure callback is invoked on main thread. - void (^callback)(BOOL) = ^(BOOL granted) { - DispatchMainThreadSafe(^{ - callbackParam(granted); - }); - }; - - if ([UIApplication sharedApplication].applicationState == UIApplicationStateBackground) { - OWSLogError(@"Skipping microphone permissions request when app is in background."); - callback(NO); - return; - } - - [[AVAudioSession sharedInstance] requestRecordPermission:callback]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SessionShareExtension/SAEScreenLockViewController.swift b/SessionShareExtension/SAEScreenLockViewController.swift index 68b0d71c1..ab735e459 100644 --- a/SessionShareExtension/SAEScreenLockViewController.swift +++ b/SessionShareExtension/SAEScreenLockViewController.swift @@ -159,17 +159,17 @@ final class SAEScreenLockViewController: ScreenLockViewController { private func showScreenLockFailureAlert(message: String) { AssertIsOnMainThread() - OWSAlerts.showAlert( - // Title for alert indicating that screen lock could not be unlocked. - title: "SCREEN_LOCK_UNLOCK_FAILED".localized(), - message: message, - buttonTitle: nil, - buttonAction: { [weak self] action in - // After the alert, update the UI - self?.ensureUI() - }, - fromViewController: self + let modal: ConfirmationModal = ConfirmationModal( + targetView: self.view, + info: ConfirmationModal.Info( + title: "SCREEN_LOCK_UNLOCK_FAILED".localized(), + explanation: message, + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text, + afterClosed: { [weak self] in self?.ensureUI() } // After the alert, update the UI + ) ) + self.present(modal, animated: true) } func unlockButtonWasTapped() { diff --git a/SessionShareExtension/ShareVC.swift b/SessionShareExtension/ShareVC.swift index e19a89cf9..07c83873c 100644 --- a/SessionShareExtension/ShareVC.swift +++ b/SessionShareExtension/ShareVC.swift @@ -222,11 +222,17 @@ final class ShareVC: UINavigationController, ShareViewDelegate { return } - let alert = UIAlertController(title: "Session", message: error.localizedDescription, preferredStyle: .alert) - alert.addAction(UIAlertAction(title: "BUTTON_OK".localized(), style: .default, handler: { _ in - self.extensionContext!.cancelRequest(withError: error) - })) - presentAlert(alert) + let modal: ConfirmationModal = ConfirmationModal( + targetView: self.view, + info: ConfirmationModal.Info( + title: "Session", + explanation: error.localizedDescription, + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text, + afterClosed: { [weak self] in self?.extensionContext?.cancelRequest(withError: error) } + ) + ) + self.present(modal, animated: true) } // MARK: Attachment Prep diff --git a/Session/Sheets & Modals/ConfirmationModal.swift b/SessionUIKit/Components/ConfirmationModal.swift similarity index 96% rename from Session/Sheets & Modals/ConfirmationModal.swift rename to SessionUIKit/Components/ConfirmationModal.swift index fed3bb4a5..5c75e5851 100644 --- a/Session/Sheets & Modals/ConfirmationModal.swift +++ b/SessionUIKit/Components/ConfirmationModal.swift @@ -1,16 +1,15 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit -import SessionUIKit public class ConfirmationModal: Modal { public struct Info: Equatable, Hashable { - enum State { + public enum State { case whenEnabled case whenDisabled case always - func shouldShow(for value: Bool) -> Bool { + public func shouldShow(for value: Bool) -> Bool { switch self { case .whenEnabled: return (value == true) case .whenDisabled: return (value == false) @@ -22,7 +21,7 @@ public class ConfirmationModal: Modal { let title: String let explanation: String? let attributedExplanation: NSAttributedString? - let stateToShow: State + public let stateToShow: State let confirmTitle: String? let confirmStyle: ThemeValue let cancelTitle: String @@ -33,7 +32,7 @@ public class ConfirmationModal: Modal { // MARK: - Initialization - init( + public init( title: String, explanation: String? = nil, attributedExplanation: NSAttributedString? = nil, @@ -159,9 +158,9 @@ public class ConfirmationModal: Modal { result.isLayoutMarginsRelativeArrangement = true result.layoutMargins = UIEdgeInsets( top: Values.largeSpacing, - leading: Values.largeSpacing, + left: Values.largeSpacing, bottom: Values.verySmallSpacing, - trailing: Values.largeSpacing + right: Values.largeSpacing ) return result @@ -177,7 +176,7 @@ public class ConfirmationModal: Modal { // MARK: - Lifecycle - init(targetView: UIView? = nil, info: Info) { + public init(targetView: UIView? = nil, info: Info) { self.internalOnConfirm = { viewController in if info.dismissOnConfirm { viewController.dismiss(animated: true) diff --git a/Session/Sheets & Modals/Modal.swift b/SessionUIKit/Components/Modal.swift similarity index 80% rename from Session/Sheets & Modals/Modal.swift rename to SessionUIKit/Components/Modal.swift index dce86cf7f..436f04242 100644 --- a/Session/Sheets & Modals/Modal.swift +++ b/SessionUIKit/Components/Modal.swift @@ -1,16 +1,16 @@ // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. import UIKit -import SessionUIKit +import SessionUtilitiesKit -public class Modal: BaseVC, UIGestureRecognizerDelegate { +open class Modal: UIViewController, UIGestureRecognizerDelegate { private static let cornerRadius: CGFloat = 11 private let afterClosed: (() -> ())? // MARK: - Components - lazy var dimmingView: UIView = { + private lazy var dimmingView: UIView = { let result = UIVisualEffectView() ThemeManager.onThemeChange(observer: result) { [weak result] theme, _ in @@ -37,7 +37,7 @@ public class Modal: BaseVC, UIGestureRecognizerDelegate { return result }() - lazy var contentView: UIView = { + public lazy var contentView: UIView = { let result: UIView = UIView() result.clipsToBounds = true result.layer.cornerRadius = Modal.cornerRadius @@ -45,7 +45,7 @@ public class Modal: BaseVC, UIGestureRecognizerDelegate { return result }() - lazy var cancelButton: UIButton = { + public lazy var cancelButton: UIButton = { let result: UIButton = Modal.createButton(title: "cancel".localized(), titleColor: .textPrimary) result.addTarget(self, action: #selector(close), for: .touchUpInside) @@ -60,22 +60,21 @@ public class Modal: BaseVC, UIGestureRecognizerDelegate { super.init(nibName: nil, bundle: nil) // Ensure the modal doesn't crash on iPad when being presented - if UIDevice.current.isIPad { - self.popoverPresentationController?.permittedArrowDirections = [] - self.popoverPresentationController?.sourceView = (targetView ?? self.view) - self.popoverPresentationController?.sourceRect = (targetView ?? self.view).bounds - } + Modal.setupForIPadIfNeeded(self, targetView: (targetView ?? self.view)) } - required init?(coder: NSCoder) { - fatalError("Use init(afterClosed:) instead") + required public init?(coder: NSCoder) { + fatalError("Use init(targetView:afterClosed:) instead") } public override func viewDidLoad() { super.viewDidLoad() - // Need to remove the background color which is added by the BaseVC + navigationItem.backButtonTitle = "" view.themeBackgroundColor = .clear + ThemeManager.applyNavigationStylingIfNeeded(to: self) + + setNeedsStatusBarAppearanceUpdate() view.addSubview(dimmingView) view.addSubview(containerView) @@ -112,12 +111,12 @@ public class Modal: BaseVC, UIGestureRecognizerDelegate { } /// To be overridden by subclasses. - func populateContentView() { + open func populateContentView() { preconditionFailure("populateContentView() is abstract and must be overridden.") } - static func createButton(title: String, titleColor: ThemeValue) -> UIButton { - let result: UIButton = UIButton() + public static func createButton(title: String, titleColor: ThemeValue) -> UIButton { + let result: UIButton = UIButton() // TODO: NEED to fix the font (looks bad) result.titleLabel?.font = .systemFont(ofSize: Values.mediumFontSize, weight: UIFont.Weight(600)) result.setTitle(title, for: .normal) result.setThemeTitleColor(titleColor, for: .normal) @@ -152,3 +151,15 @@ public class Modal: BaseVC, UIGestureRecognizerDelegate { return !contentView.point(inside: location, with: nil) } } + +// MARK: - Convenience + +public extension Modal { + static func setupForIPadIfNeeded(_ viewController: UIViewController, targetView: UIView) { + if UIDevice.current.isIPad { + viewController.popoverPresentationController?.permittedArrowDirections = [] + viewController.popoverPresentationController?.sourceView = targetView + viewController.popoverPresentationController?.sourceRect = targetView.bounds + } + } +} diff --git a/SignalUtilitiesKit/Media Viewing & Editing/MediaMessageView.swift b/SignalUtilitiesKit/Media Viewing & Editing/MediaMessageView.swift index d6be01f6d..929660f3d 100644 --- a/SignalUtilitiesKit/Media Viewing & Editing/MediaMessageView.swift +++ b/SignalUtilitiesKit/Media Viewing & Editing/MediaMessageView.swift @@ -649,7 +649,16 @@ public class MediaMessageView: UIView, OWSAudioPlayerDelegate { } public func showInvalidAudioFileAlert() { - OWSAlerts.showErrorAlert(message: NSLocalizedString("INVALID_AUDIO_FILE_ALERT_ERROR_MESSAGE", comment: "Message for the alert indicating that an audio file is invalid.")) + let modal: ConfirmationModal = ConfirmationModal( + targetView: CurrentAppContext().frontmostViewController()?.view, + info: ConfirmationModal.Info( + title: CommonStrings.errorAlertTitle, + explanation: "INVALID_AUDIO_FILE_ALERT_ERROR_MESSAGE".localized(), + cancelTitle: "BUTTON_OK".localized(), + cancelStyle: .alert_text + ) + ) + CurrentAppContext().frontmostViewController()?.present(modal, animated: true) } public func audioPlayerDidFinishPlaying(_ player: OWSAudioPlayer, successfully flag: Bool) { diff --git a/SignalUtilitiesKit/Messaging/BlockListUIUtils.swift b/SignalUtilitiesKit/Messaging/BlockListUIUtils.swift deleted file mode 100644 index 8f0126117..000000000 --- a/SignalUtilitiesKit/Messaging/BlockListUIUtils.swift +++ /dev/null @@ -1,145 +0,0 @@ -// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. - -import UIKit -import GRDB -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(_ threadId: String, from viewController: UIViewController, completionBlock: ((Bool) -> ())? = nil) { - let userPublicKey = getUserHexEncodedPublicKey() - - guard threadId != userPublicKey else { - completionBlock?(false) - return - } - - let displayName: String = Profile.displayName(id: threadId) - 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.shared.writeAsync( - updates: { db in - try Contact - .fetchOrCreate(db, id: threadId) - .with(isBlocked: true) - .save(db) - }, - completion: { _, _ in - 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(_ threadId: String, from viewController: UIViewController, completionBlock: ((Bool) -> ())? = nil) { - let displayName: String = Profile.displayName(id: threadId) - 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.shared.writeAsync( - updates: { db in - try Contact - .fetchOrCreate(db, id: threadId) - .with(isBlocked: false) - .save(db) - }, - completion: { _, _ in - self.showOkAlert( - title: String( - format: "BLOCK_LIST_VIEW_UNBLOCKED_ALERT_TITLE_FORMAT".localized(), - self.formatForAlertMessage(displayName: displayName) - ), - message: nil, - from: viewController, - completionBlock: { _ in completionBlock?(false) } - ) - }) - } - )) - actionSheet.addAction(UIAlertAction( - title: CommonStrings.cancelButton, - accessibilityIdentifier: "\(type(of: self).self).dismiss", - style: .cancel, - handler: { _ in completionBlock?(true) } - )) - - viewController.presentAlert(actionSheet) - } - - // MARK: - UI - - @objc public static func showOkAlert(title: String, message: String?, from viewController: UIViewController, completionBlock: @escaping (UIAlertAction) -> ()) { - let alertController: UIAlertController = UIAlertController(title: title, message: message, preferredStyle: .alert) - alertController.addAction(UIAlertAction( - title: "BUTTON_OK".localized(), - accessibilityIdentifier: "\(type(of: self).self).ok", - style: .default, - handler: completionBlock - )) - - viewController.presentAlert(alertController) - } - - @objc public static func formatForAlertTitle(displayName: String) -> String { - return format(displayName: displayName, maxLength: 20) - } - - @objc public static func formatForAlertMessage(displayName: String) -> String { - return format(displayName: displayName, maxLength: 127) - } - - @objc public static func format(displayName: String, maxLength: Int) -> String { - guard displayName.count <= maxLength else { - return "\(displayName.substring(to: maxLength))…" - } - - return displayName - } -} diff --git a/SignalUtilitiesKit/Utilities/OWSAlerts.swift b/SignalUtilitiesKit/Utilities/OWSAlerts.swift deleted file mode 100644 index f8cc99beb..000000000 --- a/SignalUtilitiesKit/Utilities/OWSAlerts.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// Copyright (c) 2019 Open Whisper Systems. All rights reserved. -// - -import Foundation -import SessionUtilitiesKit - -@objc public class OWSAlerts: NSObject { - @objc - public class func showAlert(_ alert: UIAlertController) { - guard let frontmostViewController = CurrentAppContext().frontmostViewController() else { - owsFailDebug("frontmostViewController was unexpectedly nil") - return - } - frontmostViewController.presentAlert(alert) - } - - @objc - public class func showAlert(title: String) { - self.showAlert(title: title, message: nil, buttonTitle: nil) - } - - @objc - public class func showAlert(title: String?, message: String) { - self.showAlert(title: title, message: message, buttonTitle: nil) - } - - @objc - public class func showAlert(title: String?, message: String? = nil, buttonTitle: String? = nil, buttonAction: ((UIAlertAction) -> Void)? = nil) { - guard let fromViewController = CurrentAppContext().frontmostViewController() else { - return - } - showAlert(title: title, message: message, buttonTitle: buttonTitle, buttonAction: buttonAction, - fromViewController: fromViewController) - } - - @objc - public class func showAlert(title: String?, message: String? = nil, buttonTitle: String? = nil, buttonAction: ((UIAlertAction) -> Void)? = nil, fromViewController: UIViewController?) { - - let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - - let actionTitle = buttonTitle ?? NSLocalizedString("BUTTON_OK", comment: "") - let okAction = UIAlertAction(title: actionTitle, style: .default, handler: buttonAction) - okAction.accessibilityIdentifier = "OWSAlerts.\("ok")" - alert.addAction(okAction) - fromViewController?.presentAlert(alert) - } - - @objc - public class func showConfirmationAlert(title: String, message: String? = nil, proceedTitle: String? = nil, proceedAction: @escaping (UIAlertAction) -> Void) { - assert(title.count > 0) - - let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) - alert.addAction(self.cancelAction) - - let actionTitle = proceedTitle ?? NSLocalizedString("BUTTON_OK", comment: "") - let okAction = UIAlertAction(title: actionTitle, style: .default, handler: proceedAction) - okAction.accessibilityIdentifier = "OWSAlerts.\("ok")" - alert.addAction(okAction) - - CurrentAppContext().frontmostViewController()?.presentAlert(alert) - } - - @objc - public class func showErrorAlert(message: String) { - self.showAlert(title: CommonStrings.errorAlertTitle, message: message, buttonTitle: nil) - } - - @objc - public class var cancelAction: UIAlertAction { - let action = UIAlertAction(title: CommonStrings.cancelButton, style: .cancel) { _ in - Logger.debug("Cancel item") - // Do nothing. - } - action.accessibilityIdentifier = "OWSAlerts.\("cancel")" - return action - } -} diff --git a/SignalUtilitiesKit/Utilities/UIView+OWS.swift b/SignalUtilitiesKit/Utilities/UIView+OWS.swift index 0914f8ec8..a2a257324 100644 --- a/SignalUtilitiesKit/Utilities/UIView+OWS.swift +++ b/SignalUtilitiesKit/Utilities/UIView+OWS.swift @@ -85,54 +85,6 @@ public extension UIView { // MARK: - -@objc -public extension UIViewController { - func presentAlert(_ alert: UIAlertController) { - self.presentAlert(alert, animated: true) - } - - func presentAlert(_ alert: UIAlertController, animated: Bool) { - guard Thread.isMainThread else { - DispatchQueue.main.async { [weak self] in - self?.presentAlert(alert, animated: animated) - } - return - } - - setupForIPadIfNeeded(alert: alert) - - self.present(alert, animated: animated) { - alert.applyAccessibilityIdentifiers() - } - } - - func presentAlert(_ alert: UIAlertController, completion: @escaping (() -> Void)) { - guard Thread.isMainThread else { - DispatchQueue.main.async { [weak self] in - self?.presentAlert(alert, completion: completion) - } - return - } - - setupForIPadIfNeeded(alert: alert) - - self.present(alert, animated: true) { - alert.applyAccessibilityIdentifiers() - completion() - } - } - - private func setupForIPadIfNeeded(alert: UIAlertController) { - if UIDevice.current.isIPad { - alert.popoverPresentationController?.permittedArrowDirections = [] - alert.popoverPresentationController?.sourceView = self.view - alert.popoverPresentationController?.sourceRect = self.view.bounds - } - } -} - -// MARK: - - public extension CGFloat { func clamp(_ minValue: CGFloat, _ maxValue: CGFloat) -> CGFloat { return CGFloatClamp(self, minValue, maxValue)