Updated the alerts to use the custom styled ones

Removed some more unused code
Moved around some files to make them more reusable
This commit is contained in:
Morgan Pretty 2022-09-28 18:26:02 +10:00
parent 40109e0bea
commit 37124c2185
34 changed files with 395 additions and 732 deletions

View File

@ -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 = "<group>"; };
7BD477A727EC39F5004E2822 /* Atomic.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Atomic.swift; sourceTree = "<group>"; };
7BD477A927F15F24004E2822 /* OpenGroupServerIdLookup.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenGroupServerIdLookup.swift; sourceTree = "<group>"; };
7BD477AF27F526FF004E2822 /* BlockListUIUtils.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BlockListUIUtils.swift; sourceTree = "<group>"; };
7BDCFC0424206E7300641C39 /* SessionNotificationServiceExtension.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = SessionNotificationServiceExtension.entitlements; sourceTree = "<group>"; };
7BDCFC07242186E700641C39 /* NotificationServiceExtensionContext.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtensionContext.swift; sourceTree = "<group>"; };
7BFA8AE22831D0D4001876F3 /* ContextMenuVC+EmojiReactsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContextMenuVC+EmojiReactsView.swift"; sourceTree = "<group>"; };
@ -1290,7 +1286,6 @@
B879D44A247E1D9200DB3608 /* PathStatusView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathStatusView.swift; sourceTree = "<group>"; };
B87EF17026367CF800124B3C /* FileServerAPI.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileServerAPI.swift; sourceTree = "<group>"; };
B87EF18026377A1D00124B3C /* Features.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Features.swift; sourceTree = "<group>"; };
B8856D5F256F129B001CE70E /* OWSAlerts.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWSAlerts.swift; sourceTree = "<group>"; };
B885D5F52334A32100EE0D8E /* UIView+Constraints.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Constraints.swift"; sourceTree = "<group>"; };
B886B4A62398B23E00211ABE /* QRCodeVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeVC.swift; sourceTree = "<group>"; };
B886B4A82398BA1500211ABE /* QRCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCode.swift; sourceTree = "<group>"; };
@ -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 = "<group>"; };
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 = "<group>"; };
EF764C331DB67CC5000D9A87 /* UIViewController+Permissions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIViewController+Permissions.h"; sourceTree = "<group>"; };
EF764C341DB67CC5000D9A87 /* UIViewController+Permissions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIViewController+Permissions.m"; sourceTree = "<group>"; };
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 = "<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; };
@ -1692,7 +1685,6 @@
FD17D7E927F6A1C600122BE0 /* SUKLegacy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SUKLegacy.swift; sourceTree = "<group>"; };
FD1C98E3282E3C5B00B76F9E /* UINavigationBar+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UINavigationBar+Utilities.swift"; sourceTree = "<group>"; };
FD245C612850664300B966DD /* Configuration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
FD28A4F327EA79F800FF65E7 /* BlockListUIUtils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BlockListUIUtils.swift; sourceTree = "<group>"; };
FD28A4F527EAD44C00FF65E7 /* Storage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Storage.swift; sourceTree = "<group>"; };
FD37E9C228A1C6F3003AE748 /* ThemeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = "<group>"; };
FD37E9C528A1D4EC003AE748 /* Theme+ClassicDark.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Theme+ClassicDark.swift"; sourceTree = "<group>"; };
@ -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 = "<group>";
@ -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 = "<group>";
};
C36096AF25AD1932008B62B2 /* Sheets & Modals */ = {
isa = PBXGroup;
children = (
B86BD08323399ACF000F5AE3 /* Modal.swift */,
FD52090628B49738006098F6 /* ConfirmationModal.swift */,
);
path = "Sheets & Modals";
sourceTree = "<group>";
};
C36096B925AD1ACF008B62B2 /* GIFs */ = {
isa = PBXGroup;
children = (
@ -3106,15 +3088,6 @@
path = "Shared Views";
sourceTree = "<group>";
};
C38BBA0D255E321C0041B9A3 /* Messaging */ = {
isa = PBXGroup;
children = (
FD28A4F327EA79F800FF65E7 /* BlockListUIUtils.swift */,
7BD477AF27F526FF004E2822 /* BlockListUIUtils.swift */,
);
path = Messaging;
sourceTree = "<group>";
};
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 */,

View File

@ -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)
}
}

View File

@ -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()
}

View File

@ -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<Void> 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<Void> 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<Void> 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<Void> 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)
}
}

View File

@ -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
}

View File

@ -380,7 +380,7 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
),
confirmTitle: "LEAVE_BUTTON_TITLE".localized(),
confirmStyle: .danger,
cancelStyle: .textPrimary
cancelStyle: .alert_text
),
onTap: { [weak self] in
Storage.shared.writeAsync { db in
@ -515,7 +515,7 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
"BLOCK_LIST_BLOCK_BUTTON".localized()
),
confirmStyle: .danger,
cancelStyle: .textPrimary
cancelStyle: .alert_text
),
onTap: {
let isBlocked: Bool = (threadViewModel.threadIsBlocked == true)
@ -646,7 +646,7 @@ class ThreadSettingsViewModel: SessionTableViewModel<ThreadSettingsViewModel.Nav
nil
),
cancelTitle: "BUTTON_OK".localized(),
cancelStyle: .textPrimary
cancelStyle: .alert_text
)
)

View File

@ -623,7 +623,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, SeedRemi
),
confirmTitle: "TXT_DELETE_TITLE".localized(),
confirmStyle: .danger,
cancelStyle: .textPrimary,
cancelStyle: .alert_text,
dismissOnConfirm: true,
onConfirm: { [weak self] _ in
self?.viewModel.delete(

View File

@ -196,9 +196,17 @@ final class NewDMVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControlle
"Please check the Session ID or ONS name and try again"
)
}()
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)
}
}
}

View File

@ -385,24 +385,20 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
strongSelf.delegate?.gifPickerDidSelect(attachment: attachment)
}
}.catch { [weak self] error in
guard let strongSelf = self else {
Logger.info("ignoring failure, since VC was dismissed before fetching finished.")
return
}
let alert = UIAlertController(
title: "GIF_PICKER_FAILURE_ALERT_TITLE".localized(),
message: error.localizedDescription,
preferredStyle: .alert
let modal: ConfirmationModal = ConfirmationModal(
targetView: self?.view,
info: ConfirmationModal.Info(
title: "GIF_PICKER_FAILURE_ALERT_TITLE".localized(),
explanation: error.localizedDescription,
confirmTitle: CommonStrings.retryButton,
cancelTitle: CommonStrings.dismissButton,
cancelStyle: .alert_text,
onConfirm: { _ in
self?.getFileForCell(cell)
}
)
)
alert.addAction(UIAlertAction(title: CommonStrings.retryButton, style: .default) { _ in
strongSelf.getFileForCell(cell)
})
alert.addAction(UIAlertAction(title: CommonStrings.dismissButton, style: .cancel) { _ in
strongSelf.dismiss(animated: true, completion: nil)
})
strongSelf.presentAlert(alert)
self?.present(modal, animated: true)
}.retainUntilComplete()
}
@ -458,7 +454,16 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
guard let text: String = searchBar.text else {
// Alert message shown when user tries to search for GIFs without entering any search terms
OWSAlerts.showErrorAlert(message: "GIF_PICKER_VIEW_MISSING_QUERY".localized())
let modal: ConfirmationModal = ConfirmationModal(
targetView: self.view,
info: ConfirmationModal.Info(
title: CommonStrings.errorAlertTitle,
explanation: "GIF_PICKER_VIEW_MISSING_QUERY".localized(),
cancelTitle: "BUTTON_OK".localized(),
cancelStyle: .alert_text
)
)
self.present(modal, animated: true)
return
}

View File

@ -584,10 +584,11 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
.deleteAll(db)
}
}
actionSheet.addAction(OWSAlerts.cancelAction)
actionSheet.addAction(UIAlertAction(title: "TXT_CANCEL_TITLE".localized(), style: .cancel))
actionSheet.addAction(deleteAction)
self.presentAlert(actionSheet)
Modal.setupForIPadIfNeeded(actionSheet, targetView: self.view)
self.present(actionSheet, animated: true)
}
// MARK: - Video interaction

View File

@ -708,9 +708,10 @@ public class MediaTileViewController: UIViewController, UICollectionViewDataSour
let actionSheet = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
actionSheet.addAction(deleteAction)
actionSheet.addAction(OWSAlerts.cancelAction)
actionSheet.addAction(UIAlertAction(title: "TXT_CANCEL_TITLE".localized(), style: .cancel))
presentAlert(actionSheet)
Modal.setupForIPadIfNeeded(actionSheet, targetView: self.view)
self.present(actionSheet, animated: true)
}
}

View File

@ -317,7 +317,7 @@ class PhotoCaptureViewController: OWSViewController {
title: CommonStrings.errorAlertTitle,
explanation: error.localizedDescription,
cancelTitle: CommonStrings.dismissButton,
cancelStyle: .textPrimary,
cancelStyle: .alert_text,
afterClosed: { [weak self] in self?.dismiss(animated: true) }
)
)

View File

@ -132,19 +132,15 @@ class SendMediaNavigationController: OWSNavigationController {
}
private func didTapCameraModeButton() {
self.ows_ask(forCameraPermissions: { granted in
if (granted) {
self.fadeTo(viewControllers: [self.captureViewController])
}
})
Permissions.requestCameraPermissionIfNeeded { [weak self] in
self?.fadeTo(viewControllers: ((self?.captureViewController).map { [$0] } ?? []))
}
}
private func didTapMediaLibraryModeButton() {
self.ows_ask(forMediaLibraryPermissions: { granted in
if (granted) {
self.fadeTo(viewControllers: [self.mediaLibraryViewController])
}
})
Permissions.requestLibraryPermissionIfNeeded { [weak self] in
self?.fadeTo(viewControllers: ((self?.mediaLibraryViewController).map { [$0] } ?? []))
}
}
// MARK: Views
@ -265,7 +261,7 @@ class SendMediaNavigationController: OWSNavigationController {
title: "SEND_MEDIA_ABANDON_TITLE".localized(),
confirmTitle: "SEND_MEDIA_CONFIRM_ABANDON_ALBUM".localized(),
confirmStyle: .danger,
cancelStyle: .textPrimary,
cancelStyle: .alert_text,
onConfirm: { [weak self] _ in
self?.sendMediaNavDelegate?.sendMediaNavDidCancel(self)
}
@ -354,8 +350,16 @@ extension SendMediaNavigationController: ImagePickerGridControllerDelegate {
}
.catch { error in
Logger.error("failed to prepare attachments. error: \(error)")
modal.dismiss {
OWSAlerts.showAlert(title: NSLocalizedString("IMAGE_PICKER_FAILED_TO_PROCESS_ATTACHMENTS", comment: "alert title"))
modal.dismiss { [weak self] in
let modal: ConfirmationModal = ConfirmationModal(
targetView: self?.view,
info: ConfirmationModal.Info(
title: "IMAGE_PICKER_FAILED_TO_PROCESS_ATTACHMENTS".localized(),
cancelTitle: "BUTTON_OK".localized(),
cancelStyle: .alert_text
)
)
self?.present(modal, animated: true)
}
}
.retainUntilComplete()

View File

@ -14,7 +14,6 @@
#import "OWSNavigationController.h"
#import "OWSWindowManager.h"
#import "MainAppContext.h"
#import "UIViewController+Permissions.h"
#import <PureLayout/PureLayout.h>
#import <Reachability/Reachability.h>
#import <SignalCoreKit/Cryptography.h>

View File

@ -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

View File

@ -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 {

View File

@ -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)

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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)
}
}
}

View File

@ -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

View File

@ -89,7 +89,7 @@ class SettingsViewModel: SessionTableViewModel<SettingsViewModel.NavButton, Sett
info: ConfirmationModal.Info(
title: "vc_settings_display_name_missing_error".localized(),
cancelTitle: "BUTTON_OK".localized(),
cancelStyle: .textPrimary
cancelStyle: .alert_text
)
),
transitionType: .present
@ -102,7 +102,7 @@ class SettingsViewModel: SessionTableViewModel<SettingsViewModel.NavButton, Sett
info: ConfirmationModal.Info(
title: "vc_settings_display_name_too_long_error".localized(),
cancelTitle: "BUTTON_OK".localized(),
cancelStyle: .textPrimary
cancelStyle: .alert_text
)
),
transitionType: .present
@ -479,7 +479,7 @@ class SettingsViewModel: SessionTableViewModel<SettingsViewModel.NavButton, Sett
"Please check your internet connection and try again"
),
cancelTitle: "BUTTON_OK".localized(),
cancelStyle: .textPrimary
cancelStyle: .alert_text
)
),
transitionType: .present

View File

@ -272,13 +272,17 @@ class ScreenLockUI {
}
private func showScreenLockFailureAlert(message: String) {
OWSAlerts.showAlert(
title: "SCREEN_LOCK_UNLOCK_FAILED".localized(),
message: message,
buttonTitle: nil,
buttonAction: { [weak self] _ in self?.ensureUI() }, // After the alert, update the UI
fromViewController: screenBlockingWindow.rootViewController
let modal: ConfirmationModal = ConfirmationModal(
targetView: screenBlockingWindow.rootViewController?.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
)
)
screenBlockingWindow.rootViewController?.present(modal, animated: true)
}
/// 'Screen Blocking' window obscures the app screen:

View File

@ -1,17 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <UIKit/UIKit.h>
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

View File

@ -1,175 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "UIViewController+Permissions.h"
#import "Session-Swift.h"
#import <AVFoundation/AVFoundation.h>
#import <Photos/Photos.h>
#import <SignalCoreKit/Threading.h>
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

View File

@ -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() {

View File

@ -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

View File

@ -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)

View File

@ -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
}
}
}

View File

@ -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) {

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -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)