Finished removing usages to non-theme colour variables

Updated theming throughout
Fixed a couple of bugs with the media gallery
This commit is contained in:
Morgan Pretty 2022-09-20 16:06:01 +10:00
parent 1bc6b0bdba
commit f7fd15dae0
128 changed files with 2196 additions and 5278 deletions

View File

@ -9,11 +9,8 @@
/* Begin PBXBuildFile section */
1FFD68A448D5A1439F2F02FD /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DBA125424EDD2417B515C63A /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionShareExtension.framework */; };
3289CA2E9E89DA9D4D52A90C /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0BF4561630A52BE96F164CF6 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SignalUtilitiesKit.framework */; };
340FC8B6204DAC8D007AEB0F /* OWSQRCodeScanningViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 340FC896204DAC8C007AEB0F /* OWSQRCodeScanningViewController.m */; };
3427C64320F500E000EEC730 /* OWSMessageTimerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3427C64220F500DF00EEC730 /* OWSMessageTimerView.m */; };
3430FE181F7751D4000EC51B /* GiphyAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3430FE171F7751D4000EC51B /* GiphyAPI.swift */; };
34330AA31E79686200DF2FB9 /* OWSProgressView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34330AA21E79686200DF2FB9 /* OWSProgressView.m */; };
34386A54207D271D009F5D9C /* NeverClearView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34386A53207D271C009F5D9C /* NeverClearView.swift */; };
34661FB820C1C0D60056EDD6 /* message_sent.aiff in Resources */ = {isa = PBXBuildFile; fileRef = 34661FB720C1C0D60056EDD6 /* message_sent.aiff */; };
346B66311F4E29B200E5122F /* CropScaleImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346B66301F4E29B200E5122F /* CropScaleImageViewController.swift */; };
3478504C1FD7496D007B8332 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B66DBF4919D5BBC8006EA940 /* Images.xcassets */; };
@ -37,7 +34,6 @@
34D1F0521F7E8EA30066283D /* GiphyDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D1F0511F7E8EA30066283D /* GiphyDownloader.swift */; };
34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */; };
34D99CE4217509C2000AFB39 /* AppEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D99CE3217509C1000AFB39 /* AppEnvironment.swift */; };
34E3E5681EC4B19400495BAC /* AudioProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34E3E5671EC4B19400495BAC /* AudioProgressView.swift */; };
34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F308A11ECB469700BB7697 /* OWSBezierPathView.m */; };
4503F1BE20470A5B00CEE724 /* classic-quiet.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 4503F1BB20470A5B00CEE724 /* classic-quiet.aifc */; };
4503F1BF20470A5B00CEE724 /* classic.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 4503F1BC20470A5B00CEE724 /* classic.aifc */; };
@ -54,7 +50,6 @@
455A16DE1F1FEA0000F86704 /* MetalKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 455A16DC1F1FEA0000F86704 /* MetalKit.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
45847E871E4283C30080EAB3 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45847E861E4283C30080EAB3 /* Intents.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
45A2F005204473A3002E978A /* NewMessage.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 45A2F004204473A3002E978A /* NewMessage.aifc */; };
45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A6DAD51EBBF85500893231 /* ReminderView.swift */; };
45B5360E206DD8BB00D61655 /* UIResponder+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45B5360D206DD8BB00D61655 /* UIResponder+OWS.swift */; };
45B74A742044AAB600CD42F8 /* aurora-quiet.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 45B74A5B2044AAB300CD42F8 /* aurora-quiet.aifc */; };
45B74A752044AAB600CD42F8 /* synth-quiet.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 45B74A5C2044AAB300CD42F8 /* synth-quiet.aifc */; };
@ -85,13 +80,11 @@
45C0DC1E1E69011F00E04C47 /* UIStoryboard+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45C0DC1D1E69011F00E04C47 /* UIStoryboard+OWS.swift */; };
45CB2FA81CB7146C00E1B343 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */; };
45CD81EF1DC030E7004C9430 /* SyncPushTokensJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45CD81EE1DC030E7004C9430 /* SyncPushTokensJob.swift */; };
45E5A6991F61E6DE001E4A8A /* MarqueeLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */; };
45F32C232057297A00A300D5 /* MediaPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F32C1D205718B000A300D5 /* MediaPageViewController.swift */; };
4C090A1B210FD9C7001FD7F9 /* HapticFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */; };
4C1885D2218F8E1C00B67051 /* PhotoGridViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1885D1218F8E1C00B67051 /* PhotoGridViewCell.swift */; };
4C21D5D8223AC60F00EF8A77 /* PhotoCapture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C21D5D7223AC60F00EF8A77 /* PhotoCapture.swift */; };
4C4AE6A1224AF35700D4AF6F /* SendMediaNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4AE69F224AF21900D4AF6F /* SendMediaNavigationController.swift */; };
4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */; };
4C586926224FAB83003FD070 /* AVAudioSession+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C586925224FAB83003FD070 /* AVAudioSession+OWS.m */; };
4C63CC00210A620B003AE45C /* SignalTSan.supp in Resources */ = {isa = PBXBuildFile; fileRef = 4C63CBFF210A620B003AE45C /* SignalTSan.supp */; };
4C6F527C20FFE8400097DEEE /* SignalUBSan.supp in Resources */ = {isa = PBXBuildFile; fileRef = 4C6F527B20FFE8400097DEEE /* SignalUBSan.supp */; };
@ -154,8 +147,8 @@
7BAF54D427ACCF01003D12F8 /* SAEScreenLockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BAF54D227ACCF01003D12F8 /* SAEScreenLockViewController.swift */; };
7BAF54D827ACD0E3003D12F8 /* ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BAF54D527ACD0E2003D12F8 /* ReusableView.swift */; };
7BAF54DC27ACD12B003D12F8 /* UIColor+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BAF54DB27ACD12B003D12F8 /* UIColor+Extensions.swift */; };
7BBBDC462875600700747E59 /* DocumentTitleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBBDC452875600700747E59 /* DocumentTitleViewController.swift */; };
7BBBDC44286EAD2D00747E59 /* TappableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBBDC43286EAD2D00747E59 /* TappableLabel.swift */; };
7BBBDC462875600700747E59 /* DocumentTitleViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BBBDC452875600700747E59 /* DocumentTitleViewController.swift */; };
7BC01A3E241F40AB00BC7C55 /* NotificationServiceExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BC01A3D241F40AB00BC7C55 /* NotificationServiceExtension.swift */; };
7BC01A42241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 7BC01A3B241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
7BC707F227290ACB002817AD /* SessionCallManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BC707F127290ACB002817AD /* SessionCallManager.swift */; };
@ -279,7 +272,6 @@
C300A5F22554B09800555489 /* MessageSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5F12554B09800555489 /* MessageSender.swift */; };
C300A60D2554B31900555489 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5CE2553860700C340D1 /* Logging.swift */; };
C302093E25DCBF08001F572D /* MentionSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C302093D25DCBF07001F572D /* MentionSelectionView.swift */; };
C31A6C5A247F214E001123EF /* UIView+Glow.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31A6C59247F214E001123EF /* UIView+Glow.swift */; };
C31A6C5C247F2CF3001123EF /* CGRect+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31A6C5B247F2CF3001123EF /* CGRect+Utilities.swift */; };
C31D1DE32521718E005D4DA8 /* UserSelectionVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DE22521718E005D4DA8 /* UserSelectionVC.swift */; };
C32824D325C9F9790062D0A7 /* SessionSnodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */; };
@ -309,7 +301,6 @@
C32C6018256E07F9003C73A2 /* NSUserDefaults+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB51255A580D00E217F9 /* NSUserDefaults+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; };
C33100082558FF6D00070591 /* NewConversationButtonSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83F2B85240C7B8F000A54AB /* NewConversationButtonSet.swift */; };
C33100092558FF6D00070591 /* UserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DDC25217014005D4DA8 /* UserCell.swift */; };
C33100142558FFC200070591 /* UIImage+Tinting.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33100132558FFC200070591 /* UIImage+Tinting.swift */; };
C33100282559000A00070591 /* UIView+Rendering.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33100272559000A00070591 /* UIView+Rendering.swift */; };
C3310033255900A400070591 /* Notification+AppMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3310032255900A400070591 /* Notification+AppMode.swift */; };
C331FF1F2558F9D300070591 /* SessionUIKit.h in Headers */ = {isa = PBXBuildFile; fileRef = C331FF1D2558F9D300070591 /* SessionUIKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -389,11 +380,9 @@
C38EF00C255B61CC007E1867 /* SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; };
C38EF22B255B6D5D007E1867 /* ShareViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF226255B6D5D007E1867 /* ShareViewDelegate.swift */; };
C38EF22C255B6D5D007E1867 /* OWSVideoPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF227255B6D5D007E1867 /* OWSVideoPlayer.swift */; };
C38EF243255B6D67007E1867 /* UIViewController+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF236255B6D65007E1867 /* UIViewController+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF245255B6D67007E1867 /* UIFont+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF238255B6D66007E1867 /* UIFont+OWS.m */; };
C38EF246255B6D67007E1867 /* UIFont+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF239255B6D66007E1867 /* UIFont+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF247255B6D67007E1867 /* NSAttributedString+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF23A255B6D66007E1867 /* NSAttributedString+OWS.m */; };
C38EF248255B6D67007E1867 /* UIViewController+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF23B255B6D66007E1867 /* UIViewController+OWS.m */; };
C38EF249255B6D67007E1867 /* UIColor+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF23C255B6D66007E1867 /* UIColor+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF24C255B6D67007E1867 /* NSAttributedString+OWS.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF23F255B6D67007E1867 /* NSAttributedString+OWS.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF24D255B6D67007E1867 /* UIView+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF240255B6D67007E1867 /* UIView+OWS.swift */; };
@ -406,15 +395,11 @@
C38EF2B4255B6D9C007E1867 /* UIView+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */; };
C38EF30C255B6DBF007E1867 /* ScreenLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2E2255B6DB9007E1867 /* ScreenLock.swift */; };
C38EF31C255B6DBF007E1867 /* Searcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F2255B6DBC007E1867 /* Searcher.swift */; };
C38EF31D255B6DBF007E1867 /* UIImage+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F3255B6DBC007E1867 /* UIImage+OWS.swift */; };
C38EF324255B6DBF007E1867 /* Bench.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2FA255B6DBD007E1867 /* Bench.swift */; };
C38EF32A255B6DBF007E1867 /* UIUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF300255B6DBD007E1867 /* UIUtil.m */; };
C38EF32B255B6DBF007E1867 /* OWSFormat.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF301255B6DBD007E1867 /* OWSFormat.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF32E255B6DBF007E1867 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF304255B6DBE007E1867 /* ImageCache.swift */; };
C38EF32F255B6DBF007E1867 /* OWSFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF305255B6DBE007E1867 /* OWSFormat.m */; };
C38EF331255B6DBF007E1867 /* UIGestureRecognizer+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */; };
C38EF334255B6DBF007E1867 /* UIUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF30A255B6DBE007E1867 /* UIUtil.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF359255B6DCC007E1867 /* SheetViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF33F255B6DC5007E1867 /* SheetViewController.swift */; };
C38EF35D255B6DCC007E1867 /* OWSNavigationController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF343255B6DC5007E1867 /* OWSNavigationController.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF35E255B6DCC007E1867 /* OWSViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = C38EF344255B6DC5007E1867 /* OWSViewController.h */; settings = {ATTRIBUTES = (Public, ); }; };
C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF349255B6DC7007E1867 /* ModalActivityIndicatorViewController.swift */; };
@ -429,7 +414,6 @@
C38EF38A255B6DD2007E1867 /* AttachmentCaptionToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF381255B6DD1007E1867 /* AttachmentCaptionToolbar.swift */; };
C38EF38B255B6DD2007E1867 /* AttachmentPrepViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF382255B6DD1007E1867 /* AttachmentPrepViewController.swift */; };
C38EF38C255B6DD2007E1867 /* ApprovalRailCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF383255B6DD1007E1867 /* ApprovalRailCellView.swift */; };
C38EF38D255B6DD2007E1867 /* AttachmentCaptionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */; };
C38EF3B8255B6DE7007E1867 /* ImageEditorTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */; };
C38EF3B9255B6DE7007E1867 /* ImageEditorPinchGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */; };
C38EF3BA255B6DE7007E1867 /* ImageEditorItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3AA255B6DE4007E1867 /* ImageEditorItem.swift */; };
@ -460,7 +444,6 @@
C38EF402255B6DF7007E1867 /* CommonStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3E4255B6DF4007E1867 /* CommonStrings.swift */; };
C38EF405255B6DF7007E1867 /* OWSButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3E7255B6DF5007E1867 /* OWSButton.swift */; };
C38EF407255B6DF7007E1867 /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3E9255B6DF6007E1867 /* Toast.swift */; };
C38EF40A255B6DF7007E1867 /* OWSFlatButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3EC255B6DF6007E1867 /* OWSFlatButton.swift */; };
C38EF40B255B6DF7007E1867 /* TappableStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3ED255B6DF6007E1867 /* TappableStackView.swift */; };
C38EF40C255B6DF7007E1867 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3EE255B6DF6007E1867 /* GradientView.swift */; };
C38EF48A255B7E3F007E1867 /* SessionUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C331FF1B2558F9D300070591 /* SessionUIKit.framework */; };
@ -533,7 +516,6 @@
C3D9E50E25677A510040E4F3 /* DataSource.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB54255A580D00E217F9 /* DataSource.h */; settings = {ATTRIBUTES = (Public, ); }; };
C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */; };
C3DB66C3260ACCE6001EFC55 /* OpenGroupPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DB66C2260ACCE6001EFC55 /* OpenGroupPoller.swift */; };
C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */; };
C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; };
C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */; };
CEE449BA3596483519120D91 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionMessagingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7A8A44E3F8AC9282AC5E6E5A /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionMessagingKit.framework */; };
@ -721,6 +703,9 @@
FD71161728D00DA400B47552 /* ThreadSettingsViewModelSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD71161628D00DA400B47552 /* ThreadSettingsViewModelSpec.swift */; };
FD71161A28D00E1100B47552 /* NotificationContentViewModelSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD71161928D00E1100B47552 /* NotificationContentViewModelSpec.swift */; };
FD71161C28D194FB00B47552 /* MentionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD71161B28D194FB00B47552 /* MentionInfo.swift */; };
FD71161E28D9772700B47552 /* UIViewController+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD71161D28D9772700B47552 /* UIViewController+OWS.swift */; };
FD71162028D97ABC00B47552 /* UIImage+Tinting.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD71161F28D97ABC00B47552 /* UIImage+Tinting.swift */; };
FD71162228D983ED00B47552 /* QRCodeScanningViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD71162128D983ED00B47552 /* QRCodeScanningViewController.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 */; };
@ -1065,14 +1050,9 @@
2581AFACDDDC1404866D7B8C /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.app store release.xcconfig"; path = "Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit.app store release.xcconfig"; sourceTree = "<group>"; };
2691123A7F231EDD8226C4B5 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionMessagingKit_SessionMessagingKitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionMessagingKit_SessionMessagingKitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
29CF8C79F41BF00B1C2E59A0 /* Pods-SessionUIKit.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-SessionUIKit.app store release.xcconfig"; path = "Target Support Files/Pods-SessionUIKit/Pods-SessionUIKit.app store release.xcconfig"; sourceTree = "<group>"; };
340FC888204DAC8C007AEB0F /* OWSQRCodeScanningViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSQRCodeScanningViewController.h; sourceTree = "<group>"; };
340FC896204DAC8C007AEB0F /* OWSQRCodeScanningViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSQRCodeScanningViewController.m; sourceTree = "<group>"; };
3427C64120F500DE00EEC730 /* OWSMessageTimerView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageTimerView.h; sourceTree = "<group>"; };
3427C64220F500DF00EEC730 /* OWSMessageTimerView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageTimerView.m; sourceTree = "<group>"; };
3430FE171F7751D4000EC51B /* GiphyAPI.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GiphyAPI.swift; sourceTree = "<group>"; };
34330AA11E79686200DF2FB9 /* OWSProgressView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSProgressView.h; sourceTree = "<group>"; };
34330AA21E79686200DF2FB9 /* OWSProgressView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSProgressView.m; sourceTree = "<group>"; };
34386A53207D271C009F5D9C /* NeverClearView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NeverClearView.swift; sourceTree = "<group>"; };
34480B371FD092A900BC14EF /* SignalShareExtension-Bridging-Header.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SignalShareExtension-Bridging-Header.h"; sourceTree = "<group>"; };
34480B381FD092E300BC14EF /* SessionShareExtension-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "SessionShareExtension-Prefix.pch"; sourceTree = "<group>"; };
34661FB720C1C0D60056EDD6 /* message_sent.aiff */ = {isa = PBXFileReference; lastKnownFileType = audio.aiff; name = message_sent.aiff; path = Session/Meta/AudioFiles/message_sent.aiff; sourceTree = SOURCE_ROOT; };
@ -1099,7 +1079,6 @@
34D5CCA71EAE3D30005515DB /* AvatarViewHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AvatarViewHelper.h; sourceTree = "<group>"; };
34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AvatarViewHelper.m; sourceTree = "<group>"; };
34D99CE3217509C1000AFB39 /* AppEnvironment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppEnvironment.swift; sourceTree = "<group>"; };
34E3E5671EC4B19400495BAC /* AudioProgressView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioProgressView.swift; sourceTree = "<group>"; };
34F308A01ECB469700BB7697 /* OWSBezierPathView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBezierPathView.h; sourceTree = "<group>"; };
34F308A11ECB469700BB7697 /* OWSBezierPathView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSBezierPathView.m; sourceTree = "<group>"; };
4503F1BB20470A5B00CEE724 /* classic-quiet.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; path = "classic-quiet.aifc"; sourceTree = "<group>"; };
@ -1119,7 +1098,6 @@
455A16DC1F1FEA0000F86704 /* MetalKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MetalKit.framework; path = System/Library/Frameworks/MetalKit.framework; sourceTree = SDKROOT; };
45847E861E4283C30080EAB3 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; };
45A2F004204473A3002E978A /* NewMessage.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; name = NewMessage.aifc; path = Session/Meta/AudioFiles/NewMessage.aifc; sourceTree = SOURCE_ROOT; };
45A6DAD51EBBF85500893231 /* ReminderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReminderView.swift; sourceTree = "<group>"; };
45B201741DAECBFD00C461E0 /* Signal-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Signal-Bridging-Header.h"; sourceTree = "<group>"; };
45B5360D206DD8BB00D61655 /* UIResponder+OWS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIResponder+OWS.swift"; sourceTree = "<group>"; };
45B74A5B2044AAB300CD42F8 /* aurora-quiet.aifc */ = {isa = PBXFileReference; lastKnownFileType = file; path = "aurora-quiet.aifc"; sourceTree = "<group>"; };
@ -1151,7 +1129,6 @@
45C0DC1D1E69011F00E04C47 /* UIStoryboard+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIStoryboard+OWS.swift"; sourceTree = "<group>"; };
45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; name = "Launch Screen.storyboard"; path = "Session/Meta/Launch Screen.storyboard"; sourceTree = SOURCE_ROOT; };
45CD81EE1DC030E7004C9430 /* SyncPushTokensJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncPushTokensJob.swift; sourceTree = "<group>"; };
45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MarqueeLabel.swift; sourceTree = "<group>"; };
45F32C1D205718B000A300D5 /* MediaPageViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = MediaPageViewController.swift; path = "Session/Media Viewing & Editing/MediaPageViewController.swift"; sourceTree = SOURCE_ROOT; };
48AD214D67ABED845101E795 /* Pods_GlobalDependencies_Session.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GlobalDependencies_Session.framework; sourceTree = BUILT_PRODUCTS_DIR; };
4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HapticFeedback.swift; sourceTree = "<group>"; };
@ -1159,7 +1136,6 @@
4C1D2337218B6BA000A0598F /* it */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = it; path = it.lproj/Localizable.strings; sourceTree = "<group>"; };
4C21D5D7223AC60F00EF8A77 /* PhotoCapture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoCapture.swift; sourceTree = "<group>"; };
4C4AE69F224AF21900D4AF6F /* SendMediaNavigationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SendMediaNavigationController.swift; sourceTree = "<group>"; };
4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DismissableTextField.swift; sourceTree = "<group>"; };
4C586924224FAB83003FD070 /* AVAudioSession+OWS.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AVAudioSession+OWS.h"; sourceTree = "<group>"; };
4C586925224FAB83003FD070 /* AVAudioSession+OWS.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = "AVAudioSession+OWS.m"; sourceTree = "<group>"; };
4C63CBFF210A620B003AE45C /* SignalTSan.supp */ = {isa = PBXFileReference; lastKnownFileType = text; path = SignalTSan.supp; sourceTree = "<group>"; };
@ -1233,8 +1209,8 @@
7BAF54D227ACCF01003D12F8 /* SAEScreenLockViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SAEScreenLockViewController.swift; sourceTree = "<group>"; };
7BAF54D527ACD0E2003D12F8 /* ReusableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReusableView.swift; sourceTree = "<group>"; };
7BAF54DB27ACD12B003D12F8 /* UIColor+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIColor+Extensions.swift"; sourceTree = "<group>"; };
7BBBDC452875600700747E59 /* DocumentTitleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentTitleViewController.swift; sourceTree = "<group>"; };
7BBBDC43286EAD2D00747E59 /* TappableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TappableLabel.swift; sourceTree = "<group>"; };
7BBBDC452875600700747E59 /* DocumentTitleViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DocumentTitleViewController.swift; sourceTree = "<group>"; };
7BC01A3B241F40AB00BC7C55 /* SessionNotificationServiceExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = SessionNotificationServiceExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; };
7BC01A3D241F40AB00BC7C55 /* NotificationServiceExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationServiceExtension.swift; sourceTree = "<group>"; };
7BC01A3F241F40AB00BC7C55 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@ -1377,7 +1353,6 @@
C300A5F12554B09800555489 /* MessageSender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageSender.swift; sourceTree = "<group>"; };
C300A5FB2554B0A000555489 /* MessageReceiver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MessageReceiver.swift; sourceTree = "<group>"; };
C302093D25DCBF07001F572D /* MentionSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionSelectionView.swift; sourceTree = "<group>"; };
C31A6C59247F214E001123EF /* UIView+Glow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Glow.swift"; sourceTree = "<group>"; };
C31A6C5B247F2CF3001123EF /* CGRect+Utilities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CGRect+Utilities.swift"; sourceTree = "<group>"; };
C31D1DDC25217014005D4DA8 /* UserCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserCell.swift; sourceTree = "<group>"; };
C31D1DE22521718E005D4DA8 /* UserSelectionVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserSelectionVC.swift; sourceTree = "<group>"; };
@ -1388,7 +1363,6 @@
C328254825CA60E60062D0A7 /* ContextMenuVC+Action.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContextMenuVC+Action.swift"; sourceTree = "<group>"; };
C328255125CA64470062D0A7 /* ContextMenuVC+ActionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContextMenuVC+ActionView.swift"; sourceTree = "<group>"; };
C32C5A87256DBCF9003C73A2 /* MessageReceiver+ClosedGroups.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MessageReceiver+ClosedGroups.swift"; sourceTree = "<group>"; };
C33100132558FFC200070591 /* UIImage+Tinting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Tinting.swift"; sourceTree = "<group>"; };
C33100272559000A00070591 /* UIView+Rendering.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIView+Rendering.swift"; sourceTree = "<group>"; };
C3310032255900A400070591 /* Notification+AppMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Notification+AppMode.swift"; sourceTree = "<group>"; };
C331FF1B2558F9D300070591 /* SessionUIKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = SessionUIKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@ -1491,12 +1465,10 @@
C38EF224255B6D5D007E1867 /* SignalAttachment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SignalAttachment.swift; path = "SessionMessagingKit/Sending & Receiving/Attachments/SignalAttachment.swift"; sourceTree = SOURCE_ROOT; };
C38EF226255B6D5D007E1867 /* ShareViewDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ShareViewDelegate.swift; path = SignalUtilitiesKit/Utilities/ShareViewDelegate.swift; sourceTree = SOURCE_ROOT; };
C38EF227255B6D5D007E1867 /* OWSVideoPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSVideoPlayer.swift; path = "SignalUtilitiesKit/Media Viewing & Editing/OWSVideoPlayer.swift"; sourceTree = SOURCE_ROOT; };
C38EF236255B6D65007E1867 /* UIViewController+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIViewController+OWS.h"; path = "SignalUtilitiesKit/Utilities/UIViewController+OWS.h"; sourceTree = SOURCE_ROOT; };
C38EF237255B6D65007E1867 /* UIDevice+featureSupport.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIDevice+featureSupport.swift"; path = "SessionUtilitiesKit/General/UIDevice+featureSupport.swift"; sourceTree = SOURCE_ROOT; };
C38EF238255B6D66007E1867 /* UIFont+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIFont+OWS.m"; path = "SignalUtilitiesKit/Utilities/UIFont+OWS.m"; sourceTree = SOURCE_ROOT; };
C38EF239255B6D66007E1867 /* UIFont+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIFont+OWS.h"; path = "SignalUtilitiesKit/Utilities/UIFont+OWS.h"; sourceTree = SOURCE_ROOT; };
C38EF23A255B6D66007E1867 /* NSAttributedString+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSAttributedString+OWS.m"; path = "SignalUtilitiesKit/Utilities/NSAttributedString+OWS.m"; sourceTree = SOURCE_ROOT; };
C38EF23B255B6D66007E1867 /* UIViewController+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIViewController+OWS.m"; path = "SignalUtilitiesKit/Utilities/UIViewController+OWS.m"; sourceTree = SOURCE_ROOT; };
C38EF23C255B6D66007E1867 /* UIColor+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIColor+OWS.h"; path = "SignalUtilitiesKit/Utilities/UIColor+OWS.h"; sourceTree = SOURCE_ROOT; };
C38EF23D255B6D66007E1867 /* UIView+OWS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIView+OWS.h"; path = "SessionUtilitiesKit/General/UIView+OWS.h"; sourceTree = SOURCE_ROOT; };
C38EF23E255B6D66007E1867 /* UIView+OWS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIView+OWS.m"; path = "SessionUtilitiesKit/General/UIView+OWS.m"; sourceTree = SOURCE_ROOT; };
@ -1514,20 +1486,16 @@
C38EF2EC255B6DBA007E1867 /* ProximityMonitoringManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ProximityMonitoringManager.swift; path = SessionMessagingKit/Utilities/ProximityMonitoringManager.swift; sourceTree = SOURCE_ROOT; };
C38EF2EF255B6DBB007E1867 /* Weak.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Weak.swift; path = SessionUtilitiesKit/General/Weak.swift; sourceTree = SOURCE_ROOT; };
C38EF2F2255B6DBC007E1867 /* Searcher.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Searcher.swift; path = SignalUtilitiesKit/Utilities/Searcher.swift; sourceTree = SOURCE_ROOT; };
C38EF2F3255B6DBC007E1867 /* UIImage+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIImage+OWS.swift"; path = "SignalUtilitiesKit/Utilities/UIImage+OWS.swift"; sourceTree = SOURCE_ROOT; };
C38EF2F5255B6DBC007E1867 /* OWSAudioPlayer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSAudioPlayer.h; path = SessionMessagingKit/Utilities/OWSAudioPlayer.h; sourceTree = SOURCE_ROOT; };
C38EF2F7255B6DBC007E1867 /* OWSAudioPlayer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSAudioPlayer.m; path = SessionMessagingKit/Utilities/OWSAudioPlayer.m; sourceTree = SOURCE_ROOT; };
C38EF2FA255B6DBD007E1867 /* Bench.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Bench.swift; path = SignalUtilitiesKit/Utilities/Bench.swift; sourceTree = SOURCE_ROOT; };
C38EF2FB255B6DBD007E1867 /* OWSWindowManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSWindowManager.h; path = SessionMessagingKit/Utilities/OWSWindowManager.h; sourceTree = SOURCE_ROOT; };
C38EF300255B6DBD007E1867 /* UIUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = UIUtil.m; path = SignalUtilitiesKit/Utilities/UIUtil.m; sourceTree = SOURCE_ROOT; };
C38EF301255B6DBD007E1867 /* OWSFormat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSFormat.h; path = SignalUtilitiesKit/Utilities/OWSFormat.h; sourceTree = SOURCE_ROOT; };
C38EF304255B6DBE007E1867 /* ImageCache.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageCache.swift; path = SignalUtilitiesKit/Utilities/ImageCache.swift; sourceTree = SOURCE_ROOT; };
C38EF305255B6DBE007E1867 /* OWSFormat.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSFormat.m; path = SignalUtilitiesKit/Utilities/OWSFormat.m; sourceTree = SOURCE_ROOT; };
C38EF306255B6DBE007E1867 /* OWSWindowManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWSWindowManager.m; path = SessionMessagingKit/Utilities/OWSWindowManager.m; sourceTree = SOURCE_ROOT; };
C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "UIGestureRecognizer+OWS.swift"; path = "SignalUtilitiesKit/Utilities/UIGestureRecognizer+OWS.swift"; sourceTree = SOURCE_ROOT; };
C38EF309255B6DBE007E1867 /* DeviceSleepManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DeviceSleepManager.swift; path = SessionMessagingKit/Utilities/DeviceSleepManager.swift; sourceTree = SOURCE_ROOT; };
C38EF30A255B6DBE007E1867 /* UIUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = UIUtil.h; path = SignalUtilitiesKit/Utilities/UIUtil.h; sourceTree = SOURCE_ROOT; };
C38EF33F255B6DC5007E1867 /* SheetViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SheetViewController.swift; path = "SignalUtilitiesKit/Shared View Controllers/SheetViewController.swift"; sourceTree = SOURCE_ROOT; };
C38EF343255B6DC5007E1867 /* OWSNavigationController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSNavigationController.h; path = "SignalUtilitiesKit/Shared View Controllers/OWSNavigationController.h"; sourceTree = SOURCE_ROOT; };
C38EF344255B6DC5007E1867 /* OWSViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWSViewController.h; path = "SignalUtilitiesKit/Shared View Controllers/OWSViewController.h"; sourceTree = SOURCE_ROOT; };
C38EF349255B6DC7007E1867 /* ModalActivityIndicatorViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ModalActivityIndicatorViewController.swift; path = "SignalUtilitiesKit/Shared View Controllers/ModalActivityIndicatorViewController.swift"; sourceTree = SOURCE_ROOT; };
@ -1542,7 +1510,6 @@
C38EF381255B6DD1007E1867 /* AttachmentCaptionToolbar.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentCaptionToolbar.swift; path = "SignalUtilitiesKit/Media Viewing & Editing/Attachment Approval/AttachmentCaptionToolbar.swift"; sourceTree = SOURCE_ROOT; };
C38EF382255B6DD1007E1867 /* AttachmentPrepViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentPrepViewController.swift; path = "SignalUtilitiesKit/Media Viewing & Editing/Attachment Approval/AttachmentPrepViewController.swift"; sourceTree = SOURCE_ROOT; };
C38EF383255B6DD1007E1867 /* ApprovalRailCellView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ApprovalRailCellView.swift; path = "SignalUtilitiesKit/Shared Views/ApprovalRailCellView.swift"; sourceTree = SOURCE_ROOT; };
C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AttachmentCaptionViewController.swift; path = "SignalUtilitiesKit/Media Viewing & Editing/Attachment Approval/AttachmentCaptionViewController.swift"; sourceTree = SOURCE_ROOT; };
C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorTextViewController.swift; path = "SignalUtilitiesKit/Media Viewing & Editing/Image Editing/ImageEditorTextViewController.swift"; sourceTree = SOURCE_ROOT; };
C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorPinchGestureRecognizer.swift; path = "SignalUtilitiesKit/Media Viewing & Editing/Image Editing/ImageEditorPinchGestureRecognizer.swift"; sourceTree = SOURCE_ROOT; };
C38EF3AA255B6DE4007E1867 /* ImageEditorItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ImageEditorItem.swift; path = "SignalUtilitiesKit/Media Viewing & Editing/Image Editing/ImageEditorItem.swift"; sourceTree = SOURCE_ROOT; };
@ -1573,7 +1540,6 @@
C38EF3E4255B6DF4007E1867 /* CommonStrings.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CommonStrings.swift; path = SignalUtilitiesKit/Utilities/CommonStrings.swift; sourceTree = SOURCE_ROOT; };
C38EF3E7255B6DF5007E1867 /* OWSButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSButton.swift; path = "SignalUtilitiesKit/Shared Views/OWSButton.swift"; sourceTree = SOURCE_ROOT; };
C38EF3E9255B6DF6007E1867 /* Toast.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Toast.swift; path = "SignalUtilitiesKit/Shared Views/Toast.swift"; sourceTree = SOURCE_ROOT; };
C38EF3EC255B6DF6007E1867 /* OWSFlatButton.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = OWSFlatButton.swift; path = "SignalUtilitiesKit/Shared Views/OWSFlatButton.swift"; sourceTree = SOURCE_ROOT; };
C38EF3ED255B6DF6007E1867 /* TappableStackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = TappableStackView.swift; path = "SignalUtilitiesKit/Shared Views/TappableStackView.swift"; sourceTree = SOURCE_ROOT; };
C38EF3EE255B6DF6007E1867 /* GradientView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GradientView.swift; path = "SignalUtilitiesKit/Shared Views/GradientView.swift"; sourceTree = SOURCE_ROOT; };
C38EF458255B710A007E1867 /* SignalUtilitiesKit-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SignalUtilitiesKit-Prefix.pch"; sourceTree = "<group>"; };
@ -1649,7 +1615,6 @@
C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SRCopyableLabel.swift; sourceTree = "<group>"; };
C3DB66AB260ACA42001EFC55 /* OpenGroupManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupManager.swift; sourceTree = "<group>"; };
C3DB66C2260ACCE6001EFC55 /* OpenGroupPoller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenGroupPoller.swift; sourceTree = "<group>"; };
C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Sheet.swift; sourceTree = "<group>"; };
C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EditClosedGroupVC.swift; sourceTree = "<group>"; };
C3ECBF7A257056B700EA7FCE /* Threading.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Threading.swift; sourceTree = "<group>"; };
C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoopNotificationsManager.swift; sourceTree = "<group>"; };
@ -1822,6 +1787,9 @@
FD71161628D00DA400B47552 /* ThreadSettingsViewModelSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadSettingsViewModelSpec.swift; sourceTree = "<group>"; };
FD71161928D00E1100B47552 /* NotificationContentViewModelSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationContentViewModelSpec.swift; sourceTree = "<group>"; };
FD71161B28D194FB00B47552 /* MentionInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MentionInfo.swift; sourceTree = "<group>"; };
FD71161D28D9772700B47552 /* UIViewController+OWS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+OWS.swift"; sourceTree = "<group>"; };
FD71161F28D97ABC00B47552 /* UIImage+Tinting.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Tinting.swift"; sourceTree = "<group>"; };
FD71162128D983ED00B47552 /* QRCodeScanningViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = QRCodeScanningViewController.swift; sourceTree = "<group>"; };
FD7162DA281B6C440060647B /* TypedTableAlias.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TypedTableAlias.swift; sourceTree = "<group>"; };
FD716E6328502DDD00C96BF4 /* CallManagerProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CallManagerProtocol.swift; sourceTree = "<group>"; };
FD716E6528502EE200C96BF4 /* CurrentCallProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentCallProtocol.swift; sourceTree = "<group>"; };
@ -2247,7 +2215,6 @@
B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */,
FD1C98E3282E3C5B00B76F9E /* UINavigationBar+Utilities.swift */,
FD848B8E283EF2A8000E298B /* UIScrollView+Utilities.swift */,
C31A6C59247F214E001123EF /* UIView+Glow.swift */,
C3548F0724456AB6009433A8 /* UIView+Wrapping.swift */,
7BAADFCD27B215FE007BCF92 /* UIView+Draggable.swift */,
7BFD1A892745C4F000FB91B9 /* Permissions.swift */,
@ -2589,19 +2556,12 @@
isa = PBXGroup;
children = (
4CA46F4B219CCC630038ABDE /* CaptionView.swift */,
4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */,
45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */,
34386A53207D271C009F5D9C /* NeverClearView.swift */,
34F308A01ECB469700BB7697 /* OWSBezierPathView.h */,
34F308A11ECB469700BB7697 /* OWSBezierPathView.m */,
34330AA11E79686200DF2FB9 /* OWSProgressView.h */,
34330AA21E79686200DF2FB9 /* OWSProgressView.m */,
45A6DAD51EBBF85500893231 /* ReminderView.swift */,
C354E75923FE2A7600CE22E3 /* BaseVC.swift */,
B8BB82AA238F669C00BA5194 /* FullConversationCell.swift */,
4542DF53208D40AC007B4E76 /* LoadingViewController.swift */,
340FC888204DAC8C007AEB0F /* OWSQRCodeScanningViewController.h */,
340FC896204DAC8C007AEB0F /* OWSQRCodeScanningViewController.m */,
FD71162128D983ED00B47552 /* QRCodeScanningViewController.swift */,
B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */,
C31D1DDC25217014005D4DA8 /* UserCell.swift */,
C31D1DE22521718E005D4DA8 /* UserSelectionVC.swift */,
@ -2841,9 +2801,9 @@
children = (
B8544E3023D16CA500299F14 /* DeviceUtilities.swift */,
FD37E9D628A20B5D003AE748 /* UIColor+Utilities.swift */,
C33100132558FFC200070591 /* UIImage+Tinting.swift */,
B885D5F52334A32100EE0D8E /* UIView+Constraints.swift */,
C33100272559000A00070591 /* UIView+Rendering.swift */,
FD71161F28D97ABC00B47552 /* UIImage+Tinting.swift */,
);
path = Utilities;
sourceTree = "<group>";
@ -2990,7 +2950,6 @@
isa = PBXGroup;
children = (
B86BD08323399ACF000F5AE3 /* Modal.swift */,
C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */,
FD52090628B49738006098F6 /* ConfirmationModal.swift */,
);
path = "Sheets & Modals";
@ -3019,7 +2978,6 @@
45F32C1D205718B000A300D5 /* MediaPageViewController.swift */,
454A84032059C787008B8C75 /* MediaTileViewController.swift */,
7BBBDC452875600700747E59 /* DocumentTitleViewController.swift */,
34E3E5671EC4B19400495BAC /* AudioProgressView.swift */,
346B66301F4E29B200E5122F /* CropScaleImageViewController.swift */,
34969559219B605E00DCFE74 /* ImagePickerController.swift */,
34A6C27F21E503E600B5B12E /* OWSImagePickerController.swift */,
@ -3085,7 +3043,6 @@
C38EF356255B6DCB007E1867 /* OWSNavigationController.m */,
C38EF344255B6DC5007E1867 /* OWSViewController.h */,
C38EF355255B6DCB007E1867 /* OWSViewController.m */,
C38EF33F255B6DC5007E1867 /* SheetViewController.swift */,
);
path = "Shared View Controllers";
sourceTree = "<group>";
@ -3127,7 +3084,6 @@
C38EF37D255B6DCF007E1867 /* AttachmentApprovalInputAccessoryView.swift */,
C38EF37F255B6DD0007E1867 /* AttachmentApprovalViewController.swift */,
C38EF381255B6DD1007E1867 /* AttachmentCaptionToolbar.swift */,
C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */,
C38EF37E255B6DD0007E1867 /* AttachmentItemCollection.swift */,
C38EF382255B6DD1007E1867 /* AttachmentPrepViewController.swift */,
C38EF37C255B6DCF007E1867 /* AttachmentTextToolbar.swift */,
@ -3142,7 +3098,6 @@
B8C2B2C72563685C00551B4D /* CircleView.swift */,
C38EF383255B6DD1007E1867 /* ApprovalRailCellView.swift */,
C38EF3E7255B6DF5007E1867 /* OWSButton.swift */,
C38EF3EC255B6DF6007E1867 /* OWSFlatButton.swift */,
C38EF3DB255B6DF1007E1867 /* OWSLayerView.swift */,
C38EF3D9255B6DF1007E1867 /* OWSNavigationBar.swift */,
C38EF3D7255B6DF0007E1867 /* OWSTextField.h */,
@ -3358,16 +3313,12 @@
7BAF54DB27ACD12B003D12F8 /* UIColor+Extensions.swift */,
C38EF3DC255B6DF1007E1867 /* DirectionalPanGestureRecognizer.swift */,
C38EF240255B6D67007E1867 /* UIView+OWS.swift */,
C38EF236255B6D65007E1867 /* UIViewController+OWS.h */,
C38EF23B255B6D66007E1867 /* UIViewController+OWS.m */,
FD71161D28D9772700B47552 /* UIViewController+OWS.swift */,
C38EF23C255B6D66007E1867 /* UIColor+OWS.h */,
C38EF242255B6D67007E1867 /* UIColor+OWS.m */,
C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */,
C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */,
C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */,
C38EF2F3255B6DBC007E1867 /* UIImage+OWS.swift */,
C38EF30A255B6DBE007E1867 /* UIUtil.h */,
C38EF300255B6DBD007E1867 /* UIUtil.m */,
C38EF239255B6D66007E1867 /* UIFont+OWS.h */,
C38EF238255B6D66007E1867 /* UIFont+OWS.m */,
C33FDA96255A57FE00E217F9 /* OWSDispatch.h */,
@ -4213,7 +4164,6 @@
files = (
C33FDDB0255A582000E217F9 /* NSURLSessionDataTask+StatusCode.h in Headers */,
C33FDDD0255A582000E217F9 /* FunctionalUtil.h in Headers */,
C38EF334255B6DBF007E1867 /* UIUtil.h in Headers */,
C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */,
C33FDD7C255A582000E217F9 /* SSKAsserts.h in Headers */,
C38EF3F6255B6DF7007E1867 /* OWSTextView.h in Headers */,
@ -4221,7 +4171,6 @@
C38EF32B255B6DBF007E1867 /* OWSFormat.h in Headers */,
C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */,
C33FDDBD255A582000E217F9 /* ByteParser.h in Headers */,
C38EF243255B6D67007E1867 /* UIViewController+OWS.h in Headers */,
C38EF35D255B6DCC007E1867 /* OWSNavigationController.h in Headers */,
C38EF249255B6D67007E1867 /* UIColor+OWS.h in Headers */,
C38EF3F5255B6DF7007E1867 /* OWSTextField.h in Headers */,
@ -5192,13 +5141,13 @@
C331FF982558FA6B00070591 /* AppMode.swift in Sources */,
FD52090328B4680F006098F6 /* RadioButton.swift in Sources */,
C331FFE82558FB0000070591 /* TextView.swift in Sources */,
FD71162028D97ABC00B47552 /* UIImage+Tinting.swift in Sources */,
FD37E9D728A20B5D003AE748 /* UIColor+Utilities.swift in Sources */,
FD37E9F928A5F14A003AE748 /* _001_ThemePreferences.swift in Sources */,
FD37E9C328A1C6F3003AE748 /* ThemeManager.swift in Sources */,
C331FF9A2558FA6B00070591 /* Values.swift in Sources */,
FD37E9C628A1D4EC003AE748 /* Theme+ClassicDark.swift in Sources */,
C331FFE42558FB0000070591 /* OutlineButton.swift in Sources */,
C33100142558FFC200070591 /* UIImage+Tinting.swift in Sources */,
C3310033255900A400070591 /* Notification+AppMode.swift in Sources */,
C331FFE92558FB0000070591 /* Separator.swift in Sources */,
C33100282559000A00070591 /* UIView+Rendering.swift in Sources */,
@ -5220,6 +5169,7 @@
C38EF2A5255B6D93007E1867 /* Identicon+ObjC.swift in Sources */,
C38EF385255B6DD2007E1867 /* AttachmentTextToolbar.swift in Sources */,
C33FDD23255A582000E217F9 /* FeatureFlags.swift in Sources */,
FD71161E28D9772700B47552 /* UIViewController+OWS.swift in Sources */,
C38EF389255B6DD2007E1867 /* AttachmentTextView.swift in Sources */,
C38EF3FF255B6DF7007E1867 /* TappableView.swift in Sources */,
C38EF3C2255B6DE7007E1867 /* ImageEditorPaletteView.swift in Sources */,
@ -5230,7 +5180,6 @@
C38EF30C255B6DBF007E1867 /* ScreenLock.swift in Sources */,
C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */,
C38EF38A255B6DD2007E1867 /* AttachmentCaptionToolbar.swift in Sources */,
C38EF40A255B6DF7007E1867 /* OWSFlatButton.swift in Sources */,
C33FDCD1255A582000E217F9 /* FunctionalUtil.m in Sources */,
C38EF402255B6DF7007E1867 /* CommonStrings.swift in Sources */,
C38EF3C1255B6DE7007E1867 /* ImageEditorBrushViewController.swift in Sources */,
@ -5243,7 +5192,6 @@
C33FDC29255A581F00E217F9 /* ReachabilityManager.swift in Sources */,
C38EF407255B6DF7007E1867 /* Toast.swift in Sources */,
C38EF38C255B6DD2007E1867 /* ApprovalRailCellView.swift in Sources */,
C38EF32A255B6DBF007E1867 /* UIUtil.m in Sources */,
C38EF2A6255B6D93007E1867 /* PlaceholderIcon.swift in Sources */,
C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */,
C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */,
@ -5254,7 +5202,6 @@
FD87DD0428B8727D00AF0F98 /* Configuration.swift in Sources */,
C38EF3BA255B6DE7007E1867 /* ImageEditorItem.swift in Sources */,
C38EF3F7255B6DF7007E1867 /* OWSNavigationBar.swift in Sources */,
C38EF248255B6D67007E1867 /* UIViewController+OWS.m in Sources */,
C33FDD3A255A582000E217F9 /* Notification+Loki.swift in Sources */,
7BAF54DC27ACD12B003D12F8 /* UIColor+Extensions.swift in Sources */,
C38EF370255B6DCC007E1867 /* OWSNavigationController.m in Sources */,
@ -5291,14 +5238,11 @@
C33FDC98255A582000E217F9 /* SwiftSingletons.swift in Sources */,
C38EF3B8255B6DE7007E1867 /* ImageEditorTextViewController.swift in Sources */,
C38EF40B255B6DF7007E1867 /* TappableStackView.swift in Sources */,
C38EF31D255B6DBF007E1867 /* UIImage+OWS.swift in Sources */,
C38EF359255B6DCC007E1867 /* SheetViewController.swift in Sources */,
C38EF386255B6DD2007E1867 /* AttachmentApprovalInputAccessoryView.swift in Sources */,
B8C2B2C82563685C00551B4D /* CircleView.swift in Sources */,
C38EF331255B6DBF007E1867 /* UIGestureRecognizer+OWS.swift in Sources */,
C33FDDC5255A582000E217F9 /* OWSError.m in Sources */,
FD848B9C284435D7000E298B /* AppSetup.swift in Sources */,
C38EF38D255B6DD2007E1867 /* AttachmentCaptionViewController.swift in Sources */,
C38EF31C255B6DBF007E1867 /* Searcher.swift in Sources */,
C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */,
C38EF3BE255B6DE7007E1867 /* OrderedDictionary.swift in Sources */,
@ -5668,7 +5612,6 @@
B83524A525C3BA4B0089A44F /* InfoMessageCell.swift in Sources */,
7B9F71D82853100A006DFE7B /* EmojiWithSkinTones.swift in Sources */,
B84A89BC25DE328A0040017D /* ProfilePictureVC.swift in Sources */,
34386A54207D271D009F5D9C /* NeverClearView.swift in Sources */,
FDCDB8E02811007F00352A0C /* HomeViewModel.swift in Sources */,
7B0EFDF62755CC5400FFAAE7 /* CallMissedTipsModal.swift in Sources */,
C374EEF425DB31D40073A857 /* VoiceMessageRecordingView.swift in Sources */,
@ -5682,7 +5625,6 @@
34B0796D1FCF46B100E248C2 /* MainAppContext.m in Sources */,
34A8B3512190A40E00218A25 /* MediaAlbumView.swift in Sources */,
FD09C5E828264937000CE219 /* MediaDetailViewController.swift in Sources */,
4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */,
3496955E219B605E00DCFE74 /* PhotoLibrary.swift in Sources */,
7B1B52E028580D51006069F2 /* EmojiSkinTonePicker.swift in Sources */,
B849789625D4A2F500D0D0B3 /* LinkPreviewView.swift in Sources */,
@ -5693,7 +5635,6 @@
7BA68909272A27BE00EFC32F /* SessionCall.swift in Sources */,
B835247925C38D880089A44F /* MessageCell.swift in Sources */,
B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */,
34E3E5681EC4B19400495BAC /* AudioProgressView.swift in Sources */,
B8D0A26925E4A2C200C1835E /* Onboarding.swift in Sources */,
34D1F0521F7E8EA30066283D /* GiphyDownloader.swift in Sources */,
4CC613362227A00400E21A3A /* ConversationSearch.swift in Sources */,
@ -5709,17 +5650,14 @@
7BA6890F27325CE300EFC32F /* SessionCallManager+CXProvider.swift in Sources */,
34BECE301F7ABCF800D7438D /* GifPickerLayout.swift in Sources */,
7B46AAAF28766DF4001AF2DC /* AllMediaViewController.swift in Sources */,
FD71162228D983ED00B47552 /* QRCodeScanningViewController.swift in Sources */,
C331FFFE2558FF3B00070591 /* FullConversationCell.swift in Sources */,
FD52090728B49738006098F6 /* ConfirmationModal.swift in Sources */,
C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */,
B8D84EA325DF745A005A043E /* LinkPreviewState.swift in Sources */,
45C0DC1E1E69011F00E04C47 /* UIStoryboard+OWS.swift in Sources */,
45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */,
B82B408E239DC00D00A248E7 /* DisplayNameVC.swift in Sources */,
B835246E25C38ABF0089A44F /* ConversationVC.swift in Sources */,
7B7037432834B81F000DCF35 /* ReactionContainerView.swift in Sources */,
B8AF4BB426A5204600583500 /* SendSeedModal.swift in Sources */,
B821494625D4D6FF009C0F2A /* URLModal.swift in Sources */,
7BBBDC462875600700747E59 /* DocumentTitleViewController.swift in Sources */,
B877E24226CA12910007970A /* CallVC.swift in Sources */,
7BA6890D27325CCC00EFC32F /* SessionCallManager+CXCallController.swift in Sources */,
@ -5730,7 +5668,6 @@
FD37EA1928AC5CCA003AE748 /* NotificationSoundViewModel.swift in Sources */,
FD7115EE28C5D79B00B47552 /* SettingsAvatarCell.swift in Sources */,
4CA485BB2232339F004B9E7D /* PhotoCaptureViewController.swift in Sources */,
34330AA31E79686200DF2FB9 /* OWSProgressView.m in Sources */,
C328254925CA60E60062D0A7 /* ContextMenuVC+Action.swift in Sources */,
4542DF54208D40AC007B4E76 /* LoadingViewController.swift in Sources */,
34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */,
@ -5794,14 +5731,12 @@
FD4B200E283492210034334B /* InsetLockableTableView.swift in Sources */,
B8269D3325C7A8C600488AB4 /* InputViewButton.swift in Sources */,
B8269D3D25C7B34D00488AB4 /* InputTextView.swift in Sources */,
340FC8B6204DAC8D007AEB0F /* OWSQRCodeScanningViewController.m in Sources */,
7B0EFDF0275084AA00FFAAE7 /* CallMessageCell.swift in Sources */,
FD37EA0B28AB12E2003AE748 /* SettingsCell.swift in Sources */,
7B93D06A27CF173D00811CB6 /* MessageRequestsViewController.swift in Sources */,
C33100082558FF6D00070591 /* NewConversationButtonSet.swift in Sources */,
C3AAFFF225AE99710089E6DD /* AppDelegate.swift in Sources */,
B8BB82A5238F627000BA5194 /* HomeVC.swift in Sources */,
C31A6C5A247F214E001123EF /* UIView+Glow.swift in Sources */,
4521C3C01F59F3BA00B4C582 /* TextFieldHelper.swift in Sources */,
FD37E9D128A1F2EB003AE748 /* ThemeSelectionView.swift in Sources */,
7B9F71D22852EEE2006DFE7B /* Emoji+SkinTones.swift in Sources */,
@ -5821,7 +5756,6 @@
FDD2506E283711D600198BDA /* DifferenceKit+Utilities.swift in Sources */,
B897621C25D201F7004F83B2 /* ScrollToBottomButton.swift in Sources */,
346B66311F4E29B200E5122F /* CropScaleImageViewController.swift in Sources */,
45E5A6991F61E6DE001E4A8A /* MarqueeLabel.swift in Sources */,
FD1C98E4282E3C5B00B76F9E /* UINavigationBar+Utilities.swift in Sources */,
C302093E25DCBF08001F572D /* MentionSelectionView.swift in Sources */,
C328251F25CA3A900062D0A7 /* QuoteView.swift in Sources */,

View File

@ -1,6 +1,7 @@
// Copyright © 2021 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import AVFoundation
import CoreMedia
class RenderView: UIView {

View File

@ -111,8 +111,8 @@ extension ContextMenuVC {
else {
if didTouchDownInside {
themeBackgroundColor = .clear
iconImageView.themeTintColor = .textPrimary
titleLabel.themeTextColor = .textPrimary
iconImageView.themeTintColor = .contextMenu_text
titleLabel.themeTextColor = .contextMenu_text
}
return
}
@ -125,8 +125,8 @@ extension ContextMenuVC {
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if didTouchDownInside {
themeBackgroundColor = .clear
iconImageView.themeTintColor = .textPrimary
titleLabel.themeTextColor = .textPrimary
iconImageView.themeTintColor = .contextMenu_text
titleLabel.themeTextColor = .contextMenu_text
}
didTouchDownInside = false
@ -135,8 +135,8 @@ extension ContextMenuVC {
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
if didTouchDownInside {
themeBackgroundColor = .clear
iconImageView.themeTintColor = .textPrimary
titleLabel.themeTextColor = .textPrimary
iconImageView.themeTintColor = .contextMenu_text
titleLabel.themeTextColor = .contextMenu_text
}
didTouchDownInside = false

View File

@ -340,17 +340,35 @@ final class ContextMenuVC: UIViewController {
func snDismiss() {
let currentFrame: CGRect = self.snapshot.frame
let currentLabelFrame: CGRect = self.timestampLabel.frame
let originalFrame: CGRect = self.frame
let frameDiff: CGRect = CGRect(
x: (currentFrame.minX - originalFrame.minX),
y: (currentFrame.minY - originalFrame.minY),
width: (currentFrame.width - originalFrame.width),
height: (currentFrame.height - originalFrame.height)
)
let endLabelFrame: CGRect = CGRect(
x: (currentLabelFrame.minX - (frameDiff.origin.x + frameDiff.width)),
y: (currentLabelFrame.minY - (frameDiff.origin.y + frameDiff.height)),
width: currentLabelFrame.width,
height: currentLabelFrame.height
)
// Remove the snapshot view from the view hierarchy to remove its constaints (and prevent
// them from causing animation bugs - also need to turn 'translatesAutoresizingMaskIntoConstraints'
// back on so autod layout doesn't mess with the frame manipulation)
// Remove the snapshot view and it's timestampLabel from the view hierarchy to remove its
// constaints (and prevent them from causing animation bugs - also need to turn
// 'translatesAutoresizingMaskIntoConstraints' back on so autod layout doesn't mess with
// the frame manipulation)
let oldSuperview: UIView? = self.snapshot.superview
self.snapshot.removeFromSuperview()
self.timestampLabel.removeFromSuperview()
oldSuperview?.insertSubview(self.snapshot, aboveSubview: self.blurView)
oldSuperview?.insertSubview(self.timestampLabel, aboveSubview: self.blurView)
self.snapshot.translatesAutoresizingMaskIntoConstraints = true
self.timestampLabel.translatesAutoresizingMaskIntoConstraints = true
self.snapshot.frame = currentFrame
self.timestampLabel.frame = currentLabelFrame
UIView.animate(
withDuration: 0.15,
@ -358,6 +376,7 @@ final class ContextMenuVC: UIViewController {
options: .curveEaseOut,
animations: { [weak self] in
self?.snapshot.frame = originalFrame
self?.timestampLabel.frame = endLabelFrame
},
completion: nil
)

View File

@ -126,43 +126,49 @@ public final class SearchResultsBar: UIView {
private lazy var label: UILabel = {
let result = UILabel()
result.font = .boldSystemFont(ofSize: Values.smallFontSize)
result.textColor = Colors.text
result.themeTextColor = .textPrimary
return result
}()
private lazy var upButton: UIButton = {
let icon = #imageLiteral(resourceName: "ic_chevron_up").withRenderingMode(.alwaysTemplate)
let result = UIButton()
let result: UIButton = UIButton()
result.setImage(icon, for: UIControl.State.normal)
result.tintColor = Colors.accent
result.themeTintColor = .primary
result.addTarget(self, action: #selector(handleUpButtonTapped), for: UIControl.Event.touchUpInside)
return result
}()
private lazy var downButton: UIButton = {
let icon = #imageLiteral(resourceName: "ic_chevron_down").withRenderingMode(.alwaysTemplate)
let result = UIButton()
let result: UIButton = UIButton()
result.setImage(icon, for: UIControl.State.normal)
result.tintColor = Colors.accent
result.themeTintColor = .primary
result.addTarget(self, action: #selector(handleDownButtonTapped), for: UIControl.Event.touchUpInside)
return result
}()
private lazy var loadingIndicator: UIActivityIndicatorView = {
let result = UIActivityIndicatorView(style: .medium)
result.tintColor = Colors.text
result.themeTintColor = .textPrimary
result.alpha = 0.5
result.hidesWhenStopped = true
return result
}()
override init(frame: CGRect) {
super.init(frame: frame)
setUpViewHierarchy()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setUpViewHierarchy()
}
@ -171,7 +177,7 @@ public final class SearchResultsBar: UIView {
// Background & blur
let backgroundView = UIView()
backgroundView.backgroundColor = isLightMode ? .white : .black
backgroundView.themeBackgroundColor = .backgroundSecondary
backgroundView.alpha = Values.lowOpacity
addSubview(backgroundView)
backgroundView.pin(to: self)
@ -189,8 +195,8 @@ public final class SearchResultsBar: UIView {
// Separator
let separator = UIView()
separator.backgroundColor = Colors.text.withAlphaComponent(0.2)
separator.set(.height, to: 1 / UIScreen.main.scale)
separator.themeBackgroundColor = .borderSeparator
separator.set(.height, to: Values.separatorThickness)
addSubview(separator)
separator.pin([ UIView.HorizontalEdge.leading, UIView.VerticalEdge.top, UIView.HorizontalEdge.trailing ], to: self)

View File

@ -148,7 +148,7 @@ extension ConversationVC:
// MARK: - SendMediaNavDelegate
func sendMediaNavDidCancel(_ sendMediaNavigationController: SendMediaNavigationController) {
func sendMediaNavDidCancel(_ sendMediaNavigationController: SendMediaNavigationController?) {
dismiss(animated: true, completion: nil)
}
@ -795,7 +795,7 @@ extension ConversationVC:
)
}
self.contextMenuWindow?.backgroundColor = .clear
self.contextMenuWindow?.themeBackgroundColor = .clear
self.contextMenuWindow?.rootViewController = self.contextMenuVC
self.contextMenuWindow?.overrideUserInterfaceStyle = (isDarkMode ? .dark : .light)
self.contextMenuWindow?.makeKeyAndVisible()

View File

@ -137,7 +137,7 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
lazy var tableView: InsetLockableTableView = {
let result: InsetLockableTableView = InsetLockableTableView()
result.separatorStyle = .none
result.backgroundColor = .clear
result.themeBackgroundColor = .clear
result.showsVerticalScrollIndicator = false
result.contentInsetAdjustmentBehavior = .never
result.keyboardDismissMode = .interactive
@ -257,7 +257,7 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
result.clipsToBounds = true
result.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
result.setTitle("TXT_BLOCK_USER_TITLE".localized(), for: .normal)
result.setTitleColor(Colors.destructive, for: .normal)
result.setThemeTitleColor(.danger, for: .normal)
result.addTarget(self, action: #selector(block), for: .touchUpInside)
return result
@ -1058,7 +1058,7 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
self.view.layoutIfNeeded()
}
}
let keyboardTop = (UIScreen.main.bounds.height - keyboardRect.minY)
let messageRequestsOffset: CGFloat = (messageRequestView.isHidden ? 0 : messageRequestView.bounds.height + 16)
let oldContentInset: UIEdgeInsets = tableView.contentInset
@ -1210,7 +1210,7 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
switch section.model {
case .loadOlder, .loadNewer:
let loadingIndicator: UIActivityIndicatorView = UIActivityIndicatorView(style: .medium)
loadingIndicator.tintColor = Colors.text
loadingIndicator.themeTintColor = .textPrimary
loadingIndicator.alpha = 0.5
loadingIndicator.startAnimating()
@ -1386,7 +1386,7 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
let ipadCancelButton = UIButton()
ipadCancelButton.setTitle("cancel".localized(), for: .normal)
ipadCancelButton.addTarget(self, action: #selector(hideSearchUI), for: .touchUpInside)
ipadCancelButton.setTitleColor(Colors.text, for: .normal)
ipadCancelButton.setThemeTitleColor(.textPrimary, for: .normal)
searchBarContainer.addSubview(ipadCancelButton)
ipadCancelButton.pin(.trailing, to: .trailing, of: searchBarContainer)
ipadCancelButton.autoVCenterInSuperview()

View File

@ -1,5 +1,7 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import UIKit
import SessionUIKit
class EmojiSkinTonePicker: UIView {
let emoji: Emoji
@ -116,12 +118,12 @@ class EmojiSkinTonePicker: UIView {
layer.shadowOpacity = 0.25
layer.shadowRadius = 4
referenceOverlay.backgroundColor = Colors.modalBackground
referenceOverlay.themeBackgroundColor = .backgroundSecondary
referenceOverlay.layer.cornerRadius = 9
addSubview(referenceOverlay)
containerView.layoutMargins = UIEdgeInsets(top: 9, leading: 16, bottom: 9, trailing: 16)
containerView.backgroundColor = Colors.modalBackground
containerView.themeBackgroundColor = .backgroundSecondary
containerView.layer.cornerRadius = 11
addSubview(containerView)
containerView.autoPinWidthToSuperview()
@ -129,7 +131,8 @@ class EmojiSkinTonePicker: UIView {
if emoji.baseEmoji!.allowsMultipleSkinTones {
prepareForMultipleSkinTones()
} else {
}
else {
prepareForSingleSkinTone()
}
}
@ -159,7 +162,7 @@ class EmojiSkinTonePicker: UIView {
let divider = UIView()
divider.autoSetDimension(.width, toSize: 1)
divider.backgroundColor = isDarkMode ? .ows_gray75 : .ows_gray05
divider.themeBackgroundColor = .borderSeparator
hStack.addArrangedSubview(divider)
hStack.addArrangedSubview(.spacer(withWidth: 2))
@ -266,7 +269,7 @@ class EmojiSkinTonePicker: UIView {
let divider = UIView()
divider.autoSetDimension(.height, toSize: 1)
divider.backgroundColor = isDarkMode ? .ows_gray75 : .ows_gray05
divider.themeBackgroundColor = .borderSeparator
vStack.addArrangedSubview(divider)
let leftSpacer = UIView.hStretchingSpacer()
@ -296,7 +299,7 @@ class EmojiSkinTonePicker: UIView {
let button = OWSButton { handler(emoji) }
button.titleLabel?.font = .boldSystemFont(ofSize: 32)
button.setTitle(emoji.rawValue, for: .normal)
button.setBackgroundImage(UIImage(color: isDarkMode ? .ows_gray60 : .ows_gray25), for: .selected)
button.setThemeBackgroundColor(.backgroundPrimary, for: .selected)
button.layer.cornerRadius = 6
button.clipsToBounds = true
button.autoSetDimensions(to: CGSize(width: 38, height: 38))

View File

@ -381,7 +381,7 @@ extension VoiceMessageRecordingView {
private func setUpViewHierarchy() {
// Background & blur
let backgroundView: UIView = UIView()
backgroundView.themeBackgroundColor = .backgroundSecondary// .backgroundColor = isLightMode ? .white : .black
backgroundView.themeBackgroundColor = .backgroundSecondary
backgroundView.alpha = Values.lowOpacity
addSubview(backgroundView)
backgroundView.pin(to: self)

View File

@ -65,10 +65,13 @@ final class LinkPreviewView: UIView {
private lazy var hStackView: UIStackView = UIStackView()
private lazy var cancelButton: UIButton = {
// FIXME: This will have issues with theme transitions
let result: UIButton = UIButton(type: .custom)
result.setImage(UIImage(named: "X")?.withRenderingMode(.alwaysTemplate), for: UIControl.State.normal)
result.tintColor = (isLightMode ? .black : .white)
result.setImage(
UIImage(named: "X")?
.withRenderingMode(.alwaysTemplate),
for: .normal
)
result.themeTintColor = .textPrimary
let cancelButtonSize = LinkPreviewView.cancelButtonSize
result.set(.width, to: cancelButtonSize)

View File

@ -30,10 +30,10 @@ public class MessageCell: UITableViewCell {
}
func setUpViewHierarchy() {
backgroundColor = .clear
themeBackgroundColor = .clear
let selectedBackgroundView = UIView()
selectedBackgroundView.backgroundColor = .clear
selectedBackgroundView.themeBackgroundColor = .clear
self.selectedBackgroundView = selectedBackgroundView
}

View File

@ -1118,8 +1118,8 @@ final class VisibleMessageCell: MessageCell, TappableLabelDelegate {
)
.forEach { range in
let legacyRange: NSRange = NSRange(range, in: normalizedBody)
attributedText.addAttribute(.backgroundColor, value: backgroundPrimaryColor, range: legacyRange)
attributedText.addAttribute(.foregroundColor, value: textPrimaryColor, range: legacyRange)
attributedText.addThemeAttribute(.background(backgroundPrimaryColor), range: legacyRange)
attributedText.addThemeAttribute(.foreground(textPrimaryColor), range: legacyRange)
}
}
}

View File

@ -125,7 +125,7 @@ final class ConversationTitleView: UIView {
}
guard !onlyNotifyForMentions else {
let imageAttachment = NSTextAttachment()
imageAttachment.image = UIImage(named: "NotifyMentions.png")?.asTintedImage(color: textPrimary)
imageAttachment.image = UIImage(named: "NotifyMentions.png")?.withTint(textPrimary)
imageAttachment.bounds = CGRect(
x: 0,
y: -2,

View File

@ -122,7 +122,7 @@ final class ReactionListSheet: BaseVC {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .clear
view.themeBackgroundColor = .clear
let swipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(close))
swipeGestureRecognizer.direction = .down
@ -133,6 +133,7 @@ final class ReactionListSheet: BaseVC {
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
reactionContainer.scrollToItem(
at: IndexPath(item: lastSelectedReactionIndex, section: 0),
at: .centeredHorizontally,
@ -150,7 +151,7 @@ final class ReactionListSheet: BaseVC {
view.addSubview(contentView)
contentView.pin([ UIView.HorizontalEdge.leading, UIView.HorizontalEdge.trailing, UIView.VerticalEdge.bottom ], to: view)
// Emoji collectionView height + seleted emoji detail height + 5 × user cell height + footer cell height + bottom safe area inset
let contentViewHeight: CGFloat = 100 + 5 * 65 + 45 + UIApplication.shared.keyWindow!.safeAreaInsets.bottom
let contentViewHeight: CGFloat = 100 + 5 * 65 + 45 + (UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? 0)
contentView.set(.height, to: contentViewHeight)
populateContentView()
}
@ -163,7 +164,7 @@ final class ReactionListSheet: BaseVC {
// Seperator
let seperator = UIView()
seperator.backgroundColor = Colors.border.withAlphaComponent(0.1)
seperator.themeBackgroundColor = .borderSeparator
seperator.set(.height, to: 0.5)
contentView.addSubview(seperator)
seperator.pin(.leading, to: .leading, of: contentView, withInset: Values.smallSpacing)
@ -180,7 +181,7 @@ final class ReactionListSheet: BaseVC {
// Line
let line = UIView()
line.set(.height, to: 0.5)
line.backgroundColor = Colors.border.withAlphaComponent(0.5)
line.themeBackgroundColor = .borderSeparator
contentView.addSubview(line)
line.pin([ UIView.HorizontalEdge.leading, UIView.HorizontalEdge.trailing ], to: contentView)
line.pin(.top, to: .bottom, of: stackView, withInset: Values.smallSpacing)
@ -541,12 +542,12 @@ extension ReactionListSheet {
}
fileprivate final class FooterCell: UITableViewCell {
private lazy var label: UILabel = {
let result = UILabel()
result.textAlignment = .center
let result: UILabel = UILabel()
result.font = .systemFont(ofSize: Values.smallFontSize)
result.textColor = Colors.grey.withAlphaComponent(0.8)
result.themeTextColor = .textSecondary
result.textAlignment = .center
return result
}()
@ -554,17 +555,19 @@ extension ReactionListSheet {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setUpViewHierarchy()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setUpViewHierarchy()
}
private func setUpViewHierarchy() {
// Background color
backgroundColor = Colors.cellBackground
themeBackgroundColor = .backgroundSecondary
contentView.addSubview(label)
label.pin(to: contentView)
@ -572,9 +575,10 @@ extension ReactionListSheet {
}
func update(moreReactorCount: Int, emoji: String) {
label.text = (moreReactorCount == 1) ?
label.text = (moreReactorCount == 1 ?
String(format: "EMOJI_REACTS_MORE_REACTORS_ONE".localized(), "\(emoji)") :
String(format: "EMOJI_REACTS_MORE_REACTORS_MUTIPLE".localized(), "\(moreReactorCount)" ,"\(emoji)")
)
}
}
}

View File

@ -1,13 +1,15 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import AVFoundation
import GRDB
import Curve25519Kit
import SessionUIKit
import SessionMessagingKit
import SessionUtilitiesKit
import SignalUtilitiesKit
final class NewDMVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControllerDelegate, OWSQRScannerDelegate {
final class NewDMVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControllerDelegate, QRScannerDelegate {
private let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
private var pages: [UIViewController] = []
private var targetVCIndex: Int?
@ -38,7 +40,7 @@ final class NewDMVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControlle
private lazy var scanQRCodePlaceholderVC: ScanQRCodePlaceholderVC = {
let result = ScanQRCodePlaceholderVC()
result.NewDMVC = self
result.newDMVC = self
return result
}()
@ -142,7 +144,7 @@ final class NewDMVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControlle
dismiss(animated: true, completion: nil)
}
func controller(_ controller: OWSQRCodeScanningViewController, didDetectQRCodeWith string: String) {
func controller(_ controller: QRCodeScanningViewController, didDetectQRCodeWith string: String) {
let hexEncodedPublicKey = string
startNewDMIfPossible(with: hexEncodedPublicKey)
}
@ -450,7 +452,7 @@ private final class EnterPublicKeyVC: UIViewController {
// MARK: - ScanQRCodePlaceholderVC
private final class ScanQRCodePlaceholderVC: UIViewController {
weak var NewDMVC: NewDMVC!
weak var newDMVC: NewDMVC!
override func viewDidLoad() {
// Remove background color
@ -493,12 +495,8 @@ private final class ScanQRCodePlaceholderVC: UIViewController {
}
@objc private func requestCameraAccess() {
ows_ask(forCameraPermissions: { [weak self] hasCameraAccess in
if hasCameraAccess {
self?.NewDMVC.handleCameraAccessGranted()
} else {
// Do nothing
}
})
Permissions.requestLibraryPermissionIfNeeded { [weak self] in
self?.newDMVC.handleCameraAccessGranted()
}
}
}

View File

@ -38,7 +38,7 @@ class MessageRequestsViewController: BaseVC, UITableViewDelegate, UITableViewDat
private lazy var tableView: UITableView = {
let result: UITableView = UITableView()
result.translatesAutoresizingMaskIntoConstraints = false
result.backgroundColor = .clear
result.themeBackgroundColor = .clear
result.separatorStyle = .none
result.register(view: FullConversationCell.self)
result.dataSource = self
@ -277,7 +277,7 @@ class MessageRequestsViewController: BaseVC, UITableViewDelegate, UITableViewDat
switch section.model {
case .loadMore:
let loadingIndicator: UIActivityIndicatorView = UIActivityIndicatorView(style: .medium)
loadingIndicator.tintColor = Colors.text
loadingIndicator.themeTintColor = .textPrimary
loadingIndicator.alpha = 0.5
loadingIndicator.startAnimating()

View File

@ -12,22 +12,27 @@ public class AllMediaViewController: UIViewController, UIPageViewControllerDataS
private var pages: [UIViewController] = []
private var targetVCIndex: Int?
// MARK: Components
// MARK: - Components
private lazy var tabBar: TabBar = {
let tabs = [
TabBar.Tab(title: MediaStrings.media) { [weak self] in
guard let self = self else { return }
self.pageVC.setViewControllers([ self.pages[0] ], direction: .forward, animated: false, completion: nil)
self.updateSelectButton(updatedData: self.mediaTitleViewController.viewModel.galleryData, inBatchSelectMode: self.mediaTitleViewController.isInBatchSelectMode)
},
TabBar.Tab(title: MediaStrings.document) { [weak self] in
guard let self = self else { return }
self.pageVC.setViewControllers([ self.pages[1] ], direction: .forward, animated: false, completion: nil)
self.endSelectMode()
self.navigationItem.rightBarButtonItem = nil
}
]
return TabBar(tabs: tabs)
let result: TabBar = TabBar(
tabs: [
TabBar.Tab(title: MediaStrings.media) { [weak self] in
guard let self = self else { return }
self.pageVC.setViewControllers([ self.pages[0] ], direction: .forward, animated: false, completion: nil)
self.updateSelectButton(updatedData: self.mediaTitleViewController.viewModel.galleryData, inBatchSelectMode: self.mediaTitleViewController.isInBatchSelectMode)
},
TabBar.Tab(title: MediaStrings.document) { [weak self] in
guard let self = self else { return }
self.pageVC.setViewControllers([ self.pages[1] ], direction: .forward, animated: false, completion: nil)
self.endSelectMode()
self.navigationItem.rightBarButtonItem = nil
}
]
)
result.themeBackgroundColor = .backgroundPrimary
return result
}()
private var mediaTitleViewController: MediaTileViewController
@ -54,11 +59,11 @@ public class AllMediaViewController: UIViewController, UIPageViewControllerDataS
public override func viewDidLoad() {
super.viewDidLoad()
view.themeBackgroundColor = .backgroundPrimary
view.themeBackgroundColor = .backgroundSecondary
// Add a custom back button if this is the only view controller
if self.navigationController?.viewControllers.first == self {
let backButton = OWSViewController.createOWSBackButton(withTarget: self, selector: #selector(didPressDismissButton))
let backButton = UIViewController.createOWSBackButton(target: self, selector: #selector(didPressDismissButton))
self.navigationItem.leftBarButtonItem = backButton
}

View File

@ -1,99 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import UIKit
import SignalUtilitiesKit
@objc public class AudioProgressView: UIView {
@objc public override var bounds: CGRect {
didSet {
if oldValue != bounds {
updateSubviews()
}
}
}
@objc public override var frame: CGRect {
didSet {
if oldValue != frame {
updateSubviews()
}
}
}
@objc public var horizontalBarColor = UIColor.black {
didSet {
updateContent()
}
}
@objc public var progressColor = UIColor.blue {
didSet {
updateContent()
}
}
private let horizontalBarLayer: CAShapeLayer
private let progressLayer: CAShapeLayer
@objc public var progress: CGFloat = 0 {
didSet {
if oldValue != progress {
updateContent()
}
}
}
@available(*, unavailable, message:"use other constructor instead.")
@objc public required init?(coder aDecoder: NSCoder) {
notImplemented()
}
public required init() {
self.horizontalBarLayer = CAShapeLayer()
self.progressLayer = CAShapeLayer()
super.init(frame: CGRect.zero)
self.layer.addSublayer(self.horizontalBarLayer)
self.layer.addSublayer(self.progressLayer)
}
internal func updateSubviews() {
AssertIsOnMainThread()
self.horizontalBarLayer.frame = self.bounds
self.progressLayer.frame = self.bounds
updateContent()
}
internal func updateContent() {
AssertIsOnMainThread()
// Prevent the shape layer from animating changes.
CATransaction.begin()
CATransaction.setDisableActions(true)
let horizontalBarPath = UIBezierPath()
let horizontalBarHeightFraction = CGFloat(0.25)
let horizontalBarHeight = bounds.size.height * horizontalBarHeightFraction
horizontalBarPath.append(UIBezierPath(rect: CGRect(x: 0, y: (bounds.size.height - horizontalBarHeight) * 0.5, width: bounds.size.width, height: horizontalBarHeight)))
horizontalBarLayer.path = horizontalBarPath.cgPath
horizontalBarLayer.fillColor = horizontalBarColor.cgColor
let progressHeight = bounds.self.height
let progressWidth = progressHeight * 0.15
let progressX = (bounds.self.width - progressWidth) * max(0.0, min(1.0, progress))
let progressBounds = CGRect(x: progressX, y: 0, width: progressWidth, height: progressHeight)
let progressCornerRadius = progressWidth * 0.5
let progressPath = UIBezierPath()
progressPath.append(UIBezierPath(roundedRect: progressBounds, cornerRadius: progressCornerRadius))
progressLayer.path = progressPath.cgPath
progressLayer.fillColor = progressColor.cgColor
CATransaction.commit()
}
}

View File

@ -4,6 +4,7 @@
import Foundation
import MediaPlayer
import SessionUIKit
import SignalUtilitiesKit
// This kind of view is tricky. I've tried to organize things in the
@ -145,13 +146,37 @@ import SignalUtilitiesKit
// MARK: - Create Views
private func createViews() {
view.backgroundColor = .black
view.themeBackgroundColor = .backgroundPrimary
let contentView = UIView()
contentView.backgroundColor = .black
contentView.themeBackgroundColor = .backgroundPrimary
self.view.addSubview(contentView)
contentView.autoPinEdgesToSuperviewEdges()
let titleLabel: UILabel = UILabel()
titleLabel.font = .boldSystemFont(ofSize: Values.veryLargeFontSize)
titleLabel.text = "CROP_SCALE_IMAGE_VIEW_TITLE".localized()
titleLabel.themeTextColor = .textPrimary
titleLabel.textAlignment = .center
contentView.addSubview(titleLabel)
titleLabel.autoPinWidthToSuperview()
let titleLabelMargin = ScaleFromIPhone5(16)
titleLabel.autoPinEdge(toSuperviewSafeArea: .top, withInset: titleLabelMargin)
let buttonRow: UIView = createButtonRow()
contentView.addSubview(buttonRow)
buttonRow.pin(.leading, to: .leading, of: contentView)
buttonRow.pin(.trailing, to: .trailing, of: contentView)
buttonRow.pin(.bottom, to: .bottom, of: contentView)
buttonRow.set(
.height,
to: (
ScaleFromIPhone5To7Plus(35, 45) +
Values.mediumSpacing +
(UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? Values.mediumSpacing)
)
)
let imageView = OWSLayerView(frame: CGRect.zero, layoutCallback: { [weak self] _ in
guard let strongSelf = self else { return }
@ -160,7 +185,10 @@ import SignalUtilitiesKit
imageView.clipsToBounds = true
self.imageView = imageView
contentView.addSubview(imageView)
imageView.autoPinEdgesToSuperviewEdges()
imageView.pin(.top, to: .top, of: contentView, withInset: (Values.massiveSpacing + Values.smallSpacing))
imageView.pin(.leading, to: .leading, of: contentView)
imageView.pin(.trailing, to: .trailing, of: contentView)
imageView.pin(.bottom, to: .top, of: buttonRow)
let imageLayer = CALayer()
self.imageLayer = imageLayer
@ -185,23 +213,13 @@ import SignalUtilitiesKit
layer.path = path.cgPath
layer.fillRule = .evenOdd
layer.fillColor = UIColor.black.cgColor
layer.themeFillColor = .black
layer.opacity = 0.75
}
maskingView.autoPinEdgesToSuperviewEdges()
let titleLabel = UILabel()
titleLabel.textColor = .white
titleLabel.textAlignment = .center
titleLabel.font = .boldSystemFont(ofSize: Values.veryLargeFontSize)
titleLabel.text = NSLocalizedString("CROP_SCALE_IMAGE_VIEW_TITLE",
comment: "Title for the 'crop/scale image' dialog.")
contentView.addSubview(titleLabel)
titleLabel.autoPinWidthToSuperview()
let titleLabelMargin = ScaleFromIPhone5(16)
titleLabel.autoPinEdge(toSuperviewSafeArea: .top, withInset: titleLabelMargin)
createButtonRow(contentView: contentView)
maskingView.pin(.top, to: .top, of: contentView, withInset: (Values.massiveSpacing + Values.smallSpacing))
maskingView.pin(.leading, to: .leading, of: contentView)
maskingView.pin(.trailing, to: .trailing, of: contentView)
maskingView.pin(.bottom, to: .top, of: buttonRow)
contentView.isUserInteractionEnabled = true
contentView.addGestureRecognizer(UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(sender:))))
@ -427,45 +445,35 @@ import SignalUtilitiesKit
updateImageLayout()
}
private func createButtonRow(contentView: UIView) {
let buttonTopMargin = ScaleFromIPhone5To7Plus(30, 40)
let buttonBottomMargin = ScaleFromIPhone5To7Plus(25, 40)
private func createButtonRow() -> UIView {
let result: UIStackView = UIStackView()
result.axis = .horizontal
result.distribution = .fillEqually
result.alignment = .fill
let buttonRow = UIView()
self.view.addSubview(buttonRow)
buttonRow.autoPinWidthToSuperview()
buttonRow.autoPinEdge(toSuperviewEdge: .bottom, withInset: buttonBottomMargin)
buttonRow.autoPinEdge(.top, to: .bottom, of: contentView, withOffset: buttonTopMargin)
let cancelButton = createButton(title: CommonStrings.cancelButton, action: #selector(cancelPressed))
result.addArrangedSubview(cancelButton)
let cancelButton = createButton(title: CommonStrings.cancelButton,
action: #selector(cancelPressed))
cancelButton.titleLabel!.font = .systemFont(ofSize: 18) // Match iOS UI
buttonRow.addSubview(cancelButton)
cancelButton.autoPinEdge(toSuperviewEdge: .top)
cancelButton.autoPinEdge(toSuperviewEdge: .bottom)
cancelButton.autoPinEdge(toSuperviewEdge: .left)
let doneButton = createButton(title: CommonStrings.doneButton,
action: #selector(donePressed))
doneButton.titleLabel!.font = .systemFont(ofSize: 18) // Match iOS UI
buttonRow.addSubview(doneButton)
doneButton.autoPinEdge(toSuperviewEdge: .top)
doneButton.autoPinEdge(toSuperviewEdge: .bottom)
doneButton.autoPinEdge(toSuperviewEdge: .right)
let doneButton = createButton(title: CommonStrings.doneButton, action: #selector(donePressed))
result.addArrangedSubview(doneButton)
return result
}
private func createButton(title: String, action: Selector) -> UIButton {
let buttonFont = UIFont.ows_mediumFont(withSize: ScaleFromIPhone5To7Plus(18, 22))
let buttonWidth = ScaleFromIPhone5To7Plus(110, 140)
let buttonHeight = ScaleFromIPhone5To7Plus(35, 45)
let button = UIButton()
let button: UIButton = UIButton()
button.titleLabel?.font = .systemFont(ofSize: 18)
button.setTitle(title, for: .normal)
button.setTitleColor(UIColor.white, for: .normal)
button.titleLabel!.font = buttonFont
button.setThemeTitleColor(.textPrimary, for: .normal)
button.setThemeBackgroundColor(.backgroundSecondary, for: .highlighted)
button.contentEdgeInsets = UIEdgeInsets(
top: Values.mediumSpacing,
leading: 0,
bottom: (UIApplication.shared.keyWindow?.safeAreaInsets.bottom ?? Values.mediumSpacing),
trailing: 0
)
button.addTarget(self, action: action, for: .touchUpInside)
button.autoSetDimension(.width, toSize: buttonWidth)
button.autoSetDimension(.height, toSize: buttonHeight)
return button
}

View File

@ -49,8 +49,8 @@ public class DocumentTileViewController: UIViewController, UITableViewDelegate,
}
lazy var tableView: UITableView = {
let result = UITableView(frame: .zero, style: .grouped)
result.backgroundColor = Colors.navigationBarBackground
let result: UITableView = UITableView()
result.themeBackgroundColor = .backgroundSecondary
result.separatorStyle = .none
result.showsVerticalScrollIndicator = false
result.register(view: DocumentCell.self)
@ -59,6 +59,10 @@ public class DocumentTileViewController: UIViewController, UITableViewDelegate,
// Feels a bit weird to have content smashed all the way to the bottom edge.
result.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 20, right: 0)
if #available(iOS 15.0, *) {
result.sectionHeaderTopPadding = 0
}
return result
}()
@ -69,7 +73,7 @@ public class DocumentTileViewController: UIViewController, UITableViewDelegate,
// Add a custom back button if this is the only view controller
if self.navigationController?.viewControllers.first == self {
let backButton = OWSViewController.createOWSBackButton(withTarget: self, selector: #selector(didPressDismissButton))
let backButton = UIViewController.createOWSBackButton(target: self, selector: #selector(didPressDismissButton))
self.navigationItem.leftBarButtonItem = backButton
}
@ -363,7 +367,8 @@ class DocumentCell: UITableViewCell {
private let iconImageView: UIImageView = {
let result: UIImageView = UIImageView(image: #imageLiteral(resourceName: "File").withRenderingMode(.alwaysTemplate))
result.translatesAutoresizingMaskIntoConstraints = false
result.tintColor = Colors.text
result.themeTintColor = .textPrimary
result.contentMode = .scaleAspectFit
return result
}()
@ -374,7 +379,20 @@ class DocumentCell: UITableViewCell {
result.setContentHuggingPriority(.defaultHigh, for: .horizontal)
result.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
result.font = .boldSystemFont(ofSize: Values.smallFontSize)
result.textColor = Colors.text
result.themeTextColor = .textPrimary
result.lineBreakMode = .byTruncatingTail
result.numberOfLines = 2
return result
}()
private let timeLabel: UILabel = {
let result: UILabel = UILabel()
result.translatesAutoresizingMaskIntoConstraints = false
result.setContentHuggingPriority(.defaultHigh, for: .horizontal)
result.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
result.font = .systemFont(ofSize: Values.smallFontSize)
result.themeTextColor = .textSecondary
result.lineBreakMode = .byTruncatingTail
return result
@ -386,20 +404,26 @@ class DocumentCell: UITableViewCell {
result.setContentHuggingPriority(.defaultHigh, for: .horizontal)
result.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
result.font = .systemFont(ofSize: Values.smallFontSize)
result.textColor = Colors.text
result.themeTextColor = .textSecondary
result.lineBreakMode = .byTruncatingTail
return result
}()
private func setUpViewHierarchy() {
backgroundColor = Colors.cellBackground
selectedBackgroundView = UIView()
selectedBackgroundView?.backgroundColor = Colors.cellSelected
themeBackgroundColor = .clear
backgroundView = UIView()
backgroundView?.themeBackgroundColor = .conversationButton_background
backgroundView?.layer.cornerRadius = 5
selectedBackgroundView = UIView()
selectedBackgroundView?.themeBackgroundColor = .conversationButton_highlight
selectedBackgroundView?.layer.cornerRadius = 5
contentView.addSubview(iconImageView)
contentView.addSubview(titleLabel)
contentView.addSubview(timeLabel)
contentView.addSubview(detailLabel)
}
@ -407,57 +431,110 @@ class DocumentCell: UITableViewCell {
private func setupLayout() {
NSLayoutConstraint.activate([
contentView.heightAnchor.constraint(equalToConstant: 68),
iconImageView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: Values.mediumSpacing),
iconImageView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
iconImageView.widthAnchor.constraint(equalToConstant: Self.iconImageViewSize.width),
iconImageView.heightAnchor.constraint(equalToConstant: Self.iconImageViewSize.height),
iconImageView.topAnchor.constraint(
greaterThanOrEqualTo: contentView.topAnchor,
constant: (Values.verySmallSpacing + Values.verySmallSpacing)
),
iconImageView.leftAnchor.constraint(
equalTo: contentView.leftAnchor,
constant: (Values.largeSpacing + Values.mediumSpacing)
),
iconImageView.bottomAnchor.constraint(
lessThanOrEqualTo: contentView.bottomAnchor,
constant: -(Values.verySmallSpacing + Values.verySmallSpacing)
),
titleLabel.topAnchor.constraint(
equalTo: contentView.topAnchor,
constant: (Values.verySmallSpacing + Values.verySmallSpacing)
),
titleLabel.leftAnchor.constraint(equalTo: iconImageView.rightAnchor, constant: Values.mediumSpacing),
titleLabel.rightAnchor.constraint(lessThanOrEqualTo: contentView.rightAnchor, constant: -Values.mediumSpacing),
titleLabel.topAnchor.constraint(equalTo: iconImageView.topAnchor),
titleLabel.rightAnchor.constraint(
lessThanOrEqualTo: timeLabel.leftAnchor,
constant: -Values.mediumSpacing
),
timeLabel.topAnchor.constraint(equalTo: iconImageView.topAnchor),
timeLabel.rightAnchor.constraint(
equalTo: contentView.rightAnchor,
constant: -(Values.mediumSpacing + Values.largeSpacing)
),
detailLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: Values.smallSpacing),
detailLabel.leftAnchor.constraint(equalTo: iconImageView.rightAnchor, constant: Values.mediumSpacing),
detailLabel.rightAnchor.constraint(lessThanOrEqualTo: contentView.rightAnchor, constant: -Values.mediumSpacing),
detailLabel.bottomAnchor.constraint(equalTo: iconImageView.bottomAnchor),
detailLabel.rightAnchor.constraint(
lessThanOrEqualTo: contentView.rightAnchor,
constant: -(Values.verySmallSpacing + Values.largeSpacing)
),
detailLabel.bottomAnchor.constraint(
lessThanOrEqualTo: contentView.bottomAnchor,
constant: -(Values.verySmallSpacing + Values.smallSpacing)
),
])
}
override func layoutSubviews() {
super.layoutSubviews()
backgroundView?.frame = CGRect(
x: Values.largeSpacing,
y: Values.verySmallSpacing,
width: (contentView.bounds.width - (Values.largeSpacing * 2)),
height: (contentView.bounds.height - (Values.verySmallSpacing * 2))
)
selectedBackgroundView?.frame = (backgroundView?.frame ?? .zero)
}
// MARK: - Content
func update(with item: MediaGalleryViewModel.Item) {
let attachment = item.attachment
titleLabel.text = attachment.sourceFilename ?? "File"
titleLabel.text = (attachment.sourceFilename ?? "File")
detailLabel.text = "\(OWSFormat.formatFileSize(UInt(attachment.byteCount)))"
timeLabel.text = Date(
timeIntervalSince1970: TimeInterval(item.interactionTimestampMs / 1000)
).formattedForDisplay
}
}
class DocumentSectionHeaderView: UIView {
// HACK: scrollbar incorrectly appears *behind* section headers
// in collection view on iOS11 =(
private class AlwaysOnTopLayer: CALayer {
override var zPosition: CGFloat {
get { return 0 }
set {}
}
}
let label: UILabel
override class var layerClass: AnyClass {
get {
// HACK: scrollbar incorrectly appears *behind* section headers
// in collection view on iOS11 =(
return AlwaysOnTopLayer.self
}
}
override init(frame: CGRect) {
label = UILabel()
label.textColor = Colors.text
let blurEffect = UIBlurEffect(style: .dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
label.themeTextColor = .textPrimary
super.init(frame: frame)
self.backgroundColor = isLightMode ? Colors.cellBackground : UIColor.ows_black.withAlphaComponent(OWSNavigationBar.backgroundBlurMutingFactor)
self.themeBackgroundColor = .clear
let backgroundView: UIView = UIView()
backgroundView.themeBackgroundColor = .backgroundSecondary
addSubview(backgroundView)
backgroundView.pin(to: self)
self.addSubview(blurEffectView)
self.addSubview(label)
blurEffectView.autoPinEdgesToSuperviewEdges()
blurEffectView.isHidden = isLightMode
label.autoPinEdge(toSuperviewMargin: .trailing)
label.autoPinEdge(toSuperviewMargin: .leading)
label.autoVCenterInSuperview()
label.pin(.leading, to: .leading, of: self, withInset: Values.largeSpacing)
label.pin(.trailing, to: .trailing, of: self, withInset: -Values.largeSpacing)
label.center(.vertical, in: self)
}
@available(*, unavailable, message: "Unimplemented")
@ -479,7 +556,7 @@ class DocumentStaticHeaderView: UIView {
addSubview(label)
label.textColor = Colors.text
label.themeTextColor = .textPrimary
label.textAlignment = .center
label.numberOfLines = 0
label.autoPinEdgesToSuperviewMargins(with: UIEdgeInsets(top: 0, leading: Values.largeSpacing, bottom: 0, trailing: Values.largeSpacing))

View File

@ -218,7 +218,7 @@ class GifPickerCell: UICollectionViewCell {
return
}
imageView.image = image
self.backgroundColor = nil
self.themeBackgroundColor = nil
if self.isCellSelected {
let activityIndicator = UIActivityIndicatorView(style: .gray)
@ -229,11 +229,12 @@ class GifPickerCell: UICollectionViewCell {
// Render activityIndicator on a white tile to ensure it's visible on
// when overlayed on a variety of potential gifs.
activityIndicator.backgroundColor = UIColor.white.withAlphaComponent(0.3)
activityIndicator.themeBackgroundColor = .white
activityIndicator.alpha = 0.3
activityIndicator.autoSetDimension(.width, toSize: 30)
activityIndicator.autoSetDimension(.height, toSize: 30)
activityIndicator.themeShadowColor = .black
activityIndicator.layer.cornerRadius = 3
activityIndicator.layer.shadowColor = UIColor.black.cgColor
activityIndicator.layer.shadowOffset = CGSize(width: 1, height: 1)
activityIndicator.layer.shadowOpacity = 0.7
activityIndicator.layer.shadowRadius = 1.0
@ -270,9 +271,7 @@ class GifPickerCell: UICollectionViewCell {
private func clearViewState() {
imageView?.image = nil
self.backgroundColor = (isDarkMode
? UIColor(white: 0.25, alpha: 1.0)
: UIColor(white: 0.95, alpha: 1.0))
self.themeBackgroundColor = .backgroundSecondary
}
private func pickBestAsset() -> ProxiedContentAsset? {

View File

@ -99,28 +99,35 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .cancel,
target: self,
action: #selector(donePressed))
self.navigationItem.leftBarButtonItem = UIBarButtonItem(
barButtonSystemItem: .cancel,
target: self,
action: #selector(donePressed)
)
// Loki: Customize title
let titleLabel = UILabel()
titleLabel.text = "accessibility_gif_button".localized().uppercased()
titleLabel.textColor = Colors.text
let titleLabel: UILabel = UILabel()
titleLabel.font = .boldSystemFont(ofSize: Values.veryLargeFontSize)
titleLabel.text = "accessibility_gif_button".localized().uppercased()
titleLabel.themeTextColor = .textPrimary
navigationItem.titleView = titleLabel
createViews()
reachability = Reachability.forInternetConnection()
NotificationCenter.default.addObserver(self,
selector: #selector(reachabilityChanged),
name: NSNotification.Name.reachabilityChanged,
object: nil)
NotificationCenter.default.addObserver(self,
selector: #selector(didBecomeActive),
name: NSNotification.Name.OWSApplicationDidBecomeActive,
object: nil)
NotificationCenter.default.addObserver(
self,
selector: #selector(reachabilityChanged),
name: .reachabilityChanged,
object: nil
)
NotificationCenter.default.addObserver(
self,
selector: #selector(didBecomeActive),
name: .OWSApplicationDidBecomeActive,
object: nil
)
loadTrending()
}
@ -140,14 +147,8 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
// MARK: Views
private func createViews() {
let backgroundColor = Colors.navigationBarBackground
self.view.backgroundColor = backgroundColor
// Block UIKit from adjust insets of collection view which screws up
// min/max scroll positions.
self.automaticallyAdjustsScrollViewInsets = false
self.view.themeBackgroundColor = .backgroundPrimary
// Search
searchBar.delegate = self
@ -157,7 +158,7 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
self.collectionView.delegate = self
self.collectionView.dataSource = self
self.collectionView.backgroundColor = backgroundColor
self.collectionView.themeBackgroundColor = .backgroundPrimary
self.collectionView.register(GifPickerCell.self, forCellWithReuseIdentifier: kCellReuseIdentifier)
// Inserted below searchbar because we later occlude the collectionview
// by inserting a masking layer between the search bar and collectionview
@ -165,10 +166,14 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
self.collectionView.autoPinEdge(toSuperviewSafeArea: .leading)
self.collectionView.autoPinEdge(toSuperviewSafeArea: .trailing)
self.collectionView.autoPinEdge(.top, to: .bottom, of: searchBar)
// Block UIKit from adjust insets of collection view which screws up
// min/max scroll positions
self.collectionView.contentInsetAdjustmentBehavior = .never
// for iPhoneX devices, extends the black background to the bottom edge of the view.
let bottomBannerContainer = UIView()
bottomBannerContainer.backgroundColor = isLightMode ? UIColor.black : Colors.navigationBarBackground
bottomBannerContainer.themeBackgroundColor = .backgroundPrimary
self.view.addSubview(bottomBannerContainer)
bottomBannerContainer.autoPinWidthToSuperview()
bottomBannerContainer.autoPinEdge(.top, to: .bottom, of: self.collectionView)
@ -188,15 +193,13 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
logoImageView.autoPinHeightToSuperview(withMargin: 3)
logoImageView.autoHCenterInSuperview()
let noResultsView = createErrorLabel(text: NSLocalizedString("GIF_VIEW_SEARCH_NO_RESULTS",
comment: "Indicates that the user's search had no results."))
let noResultsView = createErrorLabel(text: "GIF_VIEW_SEARCH_NO_RESULTS".localized())
self.noResultsView = noResultsView
self.view.addSubview(noResultsView)
noResultsView.autoPinWidthToSuperview(withMargin: 20)
noResultsView.autoAlignAxis(.horizontal, toSameAxisOf: self.collectionView)
let searchErrorView = createErrorLabel(text: NSLocalizedString("GIF_VIEW_SEARCH_ERROR",
comment: "Indicates that an error occurred while searching."))
let searchErrorView = createErrorLabel(text: "GIF_VIEW_SEARCH_ERROR".localized())
self.searchErrorView = searchErrorView
self.view.addSubview(searchErrorView)
searchErrorView.autoPinWidthToSuperview(withMargin: 20)
@ -205,29 +208,24 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
searchErrorView.isUserInteractionEnabled = true
searchErrorView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(retryTapped)))
let activityIndicator = UIActivityIndicatorView(style: .whiteLarge)
let activityIndicator = UIActivityIndicatorView(style: .large)
self.activityIndicator = activityIndicator
self.view.addSubview(activityIndicator)
activityIndicator.autoHCenterInSuperview()
activityIndicator.autoAlignAxis(.horizontal, toSameAxisOf: self.collectionView)
let navigationBar = navigationController!.navigationBar
navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
navigationBar.shadowImage = UIImage()
navigationBar.isTranslucent = false
navigationBar.barTintColor = Colors.navigationBarBackground
self.updateContents()
}
private func createErrorLabel(text: String) -> UILabel {
let label = UILabel()
let label: UILabel = UILabel()
label.font = .ows_mediumFont(withSize: 20)
label.text = text
label.textColor = Colors.text
label.font = UIFont.ows_mediumFont(withSize: 20)
label.themeTextColor = .textPrimary
label.textAlignment = .center
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.numberOfLines = 0
return label
}
@ -246,39 +244,43 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
}
switch viewMode {
case .idle:
self.collectionView.isHidden = true
noResultsView.isHidden = true
searchErrorView.isHidden = true
activityIndicator.isHidden = true
activityIndicator.stopAnimating()
case .searching:
self.collectionView.isHidden = true
noResultsView.isHidden = true
searchErrorView.isHidden = true
activityIndicator.isHidden = false
activityIndicator.startAnimating()
case .results:
self.collectionView.isHidden = false
noResultsView.isHidden = true
searchErrorView.isHidden = true
activityIndicator.isHidden = true
activityIndicator.stopAnimating()
case .idle:
self.collectionView.isHidden = true
noResultsView.isHidden = true
searchErrorView.isHidden = true
activityIndicator.isHidden = true
activityIndicator.stopAnimating()
case .searching:
self.collectionView.isHidden = true
noResultsView.isHidden = true
searchErrorView.isHidden = true
activityIndicator.isHidden = false
activityIndicator.startAnimating()
case .results:
self.collectionView.isHidden = false
noResultsView.isHidden = true
searchErrorView.isHidden = true
activityIndicator.isHidden = true
activityIndicator.stopAnimating()
self.collectionView.collectionViewLayout.invalidateLayout()
self.collectionView.reloadData()
case .noResults:
self.collectionView.isHidden = true
noResultsView.isHidden = false
searchErrorView.isHidden = true
activityIndicator.isHidden = true
activityIndicator.stopAnimating()
case .error:
self.collectionView.isHidden = true
noResultsView.isHidden = true
searchErrorView.isHidden = false
activityIndicator.isHidden = true
activityIndicator.stopAnimating()
self.collectionView.collectionViewLayout.invalidateLayout()
self.collectionView.reloadData()
case .noResults:
self.collectionView.isHidden = true
noResultsView.isHidden = false
searchErrorView.isHidden = true
activityIndicator.isHidden = true
activityIndicator.stopAnimating()
case .error:
self.collectionView.isHidden = true
noResultsView.isHidden = true
searchErrorView.isHidden = false
activityIndicator.isHidden = true
activityIndicator.stopAnimating()
}
}
@ -314,7 +316,6 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
// MARK: - UICollectionViewDelegate
public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
guard let cell = collectionView.cellForItem(at: indexPath) as? GifPickerCell else {
owsFailDebug("unexpected cell.")
return
@ -345,7 +346,7 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
layer.path = path.cgPath
layer.fillRule = .evenOdd
layer.fillColor = UIColor.black.cgColor
layer.themeFillColor = .black
layer.opacity = 0.7
}
maskingView.autoPinEdgesToSuperviewEdges()
@ -389,9 +390,11 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
return
}
let alert = UIAlertController(title: NSLocalizedString("GIF_PICKER_FAILURE_ALERT_TITLE", comment: "Shown when selected GIF couldn't be fetched"),
message: error.localizedDescription,
preferredStyle: .alert)
let alert = UIAlertController(
title: "GIF_PICKER_FAILURE_ALERT_TITLE".localized(),
message: error.localizedDescription,
preferredStyle: .alert
)
alert.addAction(UIAlertAction(title: CommonStrings.retryButton, style: .default) { _ in
strongSelf.getFileForCell(cell)
})
@ -439,11 +442,7 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
progressiveSearchTimer = nil
let kProgressiveSearchDelaySeconds = 1.0
progressiveSearchTimer = WeakTimer.scheduledTimer(timeInterval: kProgressiveSearchDelaySeconds, target: self, userInfo: nil, repeats: true) { [weak self] _ in
guard let strongSelf = self else {
return
}
strongSelf.tryToSearch()
self?.tryToSearch()
}
}
@ -457,19 +456,24 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
progressiveSearchTimer?.invalidate()
progressiveSearchTimer = nil
guard let text = searchBar.text else {
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())
return
}
let query = (text as String).trimmingCharacters(in: CharacterSet.whitespacesAndNewlines)
let query: String = text.trimmingCharacters(in: .whitespacesAndNewlines)
if (viewMode == .searching || viewMode == .results) && lastQuery == query {
Logger.info("ignoring duplicate search: \(query)")
return
}
guard !query.isEmpty else {
loadTrending()
return
}
search(query: query)
}
@ -477,20 +481,22 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
assert(progressiveSearchTimer == nil)
assert(searchBar.text == nil || searchBar.text?.count == 0)
GiphyAPI.sharedInstance.trending().done { [weak self] imageInfos in
guard let self = self else { return }
Logger.info("showing trending")
if imageInfos.count > 0 {
self.imageInfos = imageInfos
self.viewMode = .results
} else {
owsFailDebug("trending results was unexpectedly empty")
GiphyAPI.sharedInstance.trending()
.done { [weak self] imageInfos in
Logger.info("showing trending")
if imageInfos.count > 0 {
self?.imageInfos = imageInfos
self?.viewMode = .results
}
else {
owsFailDebug("trending results was unexpectedly empty")
}
}
.catch { error in
// Don't both showing error UI feedback for default "trending" results.
Logger.error("error: \(error)")
}
}.catch { error in
// Don't both showing error UI feedback for default "trending" results.
Logger.error("error: \(error)")
}
}
private func search(query: String) {
@ -503,22 +509,26 @@ class GifPickerViewController: OWSViewController, UISearchBarDelegate, UICollect
lastQuery = query
self.collectionView.contentOffset = CGPoint.zero
GiphyAPI.sharedInstance.search(query: query, success: { [weak self] imageInfos in
guard let strongSelf = self else { return }
Logger.info("search complete")
strongSelf.imageInfos = imageInfos
if imageInfos.count > 0 {
strongSelf.viewMode = .results
} else {
strongSelf.viewMode = .noResults
}
},
failure: { [weak self] _ in
guard let strongSelf = self else { return }
Logger.info("search failed.")
// TODO: Present this error to the user.
strongSelf.viewMode = .error
})
GiphyAPI.sharedInstance
.search(
query: query,
success: { [weak self] imageInfos in
Logger.info("search complete")
self?.imageInfos = imageInfos
if imageInfos.count > 0 {
self?.viewMode = .results
}
else {
self?.viewMode = .noResults
}
},
failure: { [weak self] _ in
Logger.info("search failed.")
// TODO: Present this error to the user.
self?.viewMode = .error
}
)
}
// MARK: - GifPickerLayoutDelegate

View File

@ -6,6 +6,7 @@ import Foundation
import Photos
import PromiseKit
import SessionUIKit
import SignalUtilitiesKit
protocol ImagePickerGridControllerDelegate: AnyObject {
func imagePickerDidCompleteSelection(_ imagePicker: ImagePickerGridController)
@ -48,7 +49,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = Colors.navigationBarBackground
self.view.themeBackgroundColor = .backgroundSecondary
library.add(delegate: self)
@ -71,7 +72,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
let cancelImage = UIImage(imageLiteralResourceName: "X")
let cancelButton = UIBarButtonItem(image: cancelImage, style: .plain, target: self, action: #selector(didPressCancel))
cancelButton.tintColor = Colors.text
cancelButton.themeTintColor = .textPrimary
navigationItem.leftBarButtonItem = cancelButton
let titleView = TitleView()
@ -80,7 +81,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
navigationItem.titleView = titleView
self.titleView = titleView
collectionView.backgroundColor = Colors.navigationBarBackground
collectionView.themeBackgroundColor = .backgroundSecondary
let selectionPanGesture = DirectionalPanGestureRecognizer(direction: [.horizontal], target: self, action: #selector(didPanSelection))
selectionPanGesture.delegate = self
@ -105,7 +106,9 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
enum BatchSelectionGestureMode {
case select, deselect
}
var selectionPanGestureMode: BatchSelectionGestureMode = .select
var hasEverAppeared: Bool = false
@objc
func didPanSelection(_ selectionPanGesture: UIPanGestureRecognizer) {
@ -189,20 +192,9 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
super.viewWillLayoutSubviews()
updateLayout()
}
var hasEverAppeared: Bool = false
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let backgroundImage: UIImage = UIImage(color: Colors.navigationBarBackground)
self.navigationItem.title = nil
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.isTranslucent = false
self.navigationController?.navigationBar.barTintColor = Colors.navigationBarBackground
(self.navigationController?.navigationBar as? OWSNavigationBar)?.respectsTheme = true
self.navigationController?.navigationBar.backgroundColor = Colors.navigationBarBackground
self.navigationController?.navigationBar.setBackgroundImage(backgroundImage, for: .default)
// Determine the size of the thumbnails to request
let scale = UIScreen.main.scale
@ -362,9 +354,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
// MARK: - Batch Selection
func batchSelectModeDidChange() {
guard let delegate = delegate else {
return
}
guard let delegate = delegate else { return }
guard let collectionView = collectionView else {
owsFailDebug("collectionView was unexpectedly nil")
@ -397,7 +387,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
let toastText = String(format: toastFormat, NSNumber(value: SignalAttachment.maxAttachmentsAllowed))
let toastController = ToastController(text: toastText)
let toastController = ToastController(text: toastText, background: .backgroundPrimary)
let kToastInset: CGFloat = 10
let bottomInset = kToastInset + collectionView.contentInset.bottom + view.layoutMargins.bottom
@ -531,8 +521,6 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
}
let cell: PhotoGridViewCell = collectionView.dequeue(type: PhotoGridViewCell.self, for: indexPath)
cell.loadingColor = UIColor(white: 0.2, alpha: 1)
let assetItem = photoCollectionContents.assetItem(at: indexPath.item, photoMediaSize: photoMediaSize)
cell.configure(item: assetItem)
@ -586,12 +574,12 @@ class TitleView: UIView {
addSubview(stackView)
stackView.autoPinEdgesToSuperviewEdges()
label.textColor = Colors.text
label.font = .boldSystemFont(ofSize: Values.mediumFontSize)
label.themeTextColor = .textPrimary
iconView.tintColor = Colors.text
iconView.image = UIImage(named: "navbar_disclosure_down")?.withRenderingMode(.alwaysTemplate)
iconView.themeTintColor = .textPrimary
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(titleTapped)))
}

View File

@ -93,7 +93,7 @@ class MediaDetailViewController: OWSViewController, UIScrollViewDelegate, OWSVid
override func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = Colors.navigationBarBackground
self.view.themeBackgroundColor = .backgroundSecondary
self.view.addSubview(scrollView)
scrollView.pin(to: self.view)
@ -185,13 +185,13 @@ class MediaDetailViewController: OWSViewController, UIScrollViewDelegate, OWSVid
}
else {
self.mediaView = UIView()
self.mediaView.backgroundColor = Colors.unimportant
self.mediaView.themeBackgroundColor = .backgroundSecondary
}
}
else if self.image == nil {
// Still loading thumbnail.
self.mediaView = UIView()
self.mediaView.backgroundColor = Colors.unimportant
self.mediaView.themeBackgroundColor = .backgroundSecondary
}
else if self.galleryItem.attachment.isVideo {
if self.galleryItem.attachment.isValid {
@ -199,7 +199,7 @@ class MediaDetailViewController: OWSViewController, UIScrollViewDelegate, OWSVid
}
else {
self.mediaView = UIView()
self.mediaView.backgroundColor = Colors.unimportant
self.mediaView.themeBackgroundColor = .backgroundSecondary
}
}
else {

View File

@ -16,7 +16,7 @@ class MediaGalleryNavigationController: OWSNavigationController {
private lazy var backgroundView: UIView = {
let result: UIView = UIView()
result.backgroundColor = Colors.navigationBarBackground
result.themeBackgroundColor = .backgroundSecondary
return result
}()
@ -27,18 +27,8 @@ class MediaGalleryNavigationController: OWSNavigationController {
override func viewDidLoad() {
super.viewDidLoad()
guard let navigationBar = self.navigationBar as? OWSNavigationBar else {
owsFailDebug("navigationBar had unexpected class: \(self.navigationBar)")
return
}
view.backgroundColor = Colors.navigationBarBackground
navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
navigationBar.shadowImage = UIImage()
navigationBar.isTranslucent = false
navigationBar.barTintColor = Colors.navigationBarBackground
view.themeBackgroundColor = .backgroundSecondary
// Insert a view to ensure the nav bar colour goes to the top of the screen
relayoutBackgroundView()

View File

@ -402,6 +402,7 @@ public class MediaGalleryViewModel {
.baseQuery(
orderSQL: SQL(interactionAttachment[.albumIndex]),
customFilters: SQL("""
\(attachment[.isVisualMedia]) = true AND
\(attachment[.isValid]) = true AND
\(interaction[.id]) = \(interactionId)
""")
@ -416,6 +417,8 @@ public class MediaGalleryViewModel {
.baseQuery(
orderSQL: Item.galleryReverseOrderSQL,
customFilters: SQL("""
\(attachment[.isVisualMedia]) = true AND
\(attachment[.isValid]) = true AND
\(interaction[.timestampMs]) > \(albumTimestampMs) AND
\(interaction[.threadId]) = \(threadId)
""")
@ -425,6 +428,8 @@ public class MediaGalleryViewModel {
.baseQuery(
orderSQL: Item.galleryOrderSQL,
customFilters: SQL("""
\(attachment[.isVisualMedia]) = true AND
\(attachment[.isValid]) = true AND
\(interaction[.timestampMs]) < \(albumTimestampMs) AND
\(interaction[.threadId]) = \(threadId)
""")

View File

@ -32,6 +32,17 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
owsFailDebug("unexpectedly unable to build new gallery page")
return
}
// Cache and retrieve the new album items
viewModel.loadAndCacheAlbumData(
for: item.interactionId,
in: self.viewModel.threadId
)
// Swap out the database observer
dataChangeObservable?.cancel()
viewModel.replaceAlbumObservation(toObservationFor: item.interactionId)
startObservingChanges()
updateTitle(item: item)
updateCaption(item: item)
@ -93,12 +104,12 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
var footerBar: UIToolbar = {
let result: UIToolbar = UIToolbar()
result.clipsToBounds = true // hide 1px top-border
result.tintColor = Colors.text
result.barTintColor = Colors.navigationBarBackground
result.themeTintColor = .textPrimary
result.themeBarTintColor = .backgroundPrimary
result.themeBackgroundColor = .backgroundPrimary
result.setBackgroundImage(UIImage(), forToolbarPosition: .any, barMetrics: UIBarMetrics.default)
result.setShadowImage(UIImage(), forToolbarPosition: .any)
result.isTranslucent = false
result.backgroundColor = Colors.navigationBarBackground
return result
}()
@ -115,7 +126,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
// Navigation
let backButton = OWSViewController.createOWSBackButton(withTarget: self, selector: #selector(didPressDismissButton))
let backButton = UIViewController.createOWSBackButton(target: self, selector: #selector(didPressDismissButton))
self.navigationItem.leftBarButtonItem = backButton
self.navigationItem.titleView = portraitHeaderView
@ -154,9 +165,9 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
}
// Views
pagerScrollView.backgroundColor = Colors.navigationBarBackground
pagerScrollView.themeBackgroundColor = .backgroundSecondary
view.backgroundColor = Colors.navigationBarBackground
view.themeBackgroundColor = .backgroundSecondary
captionContainerView.delegate = self
updateCaptionContainerVisibility()
@ -169,7 +180,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
let bottomContainer: DynamicallySizedView = DynamicallySizedView()
bottomContainer.clipsToBounds = true
bottomContainer.autoresizingMask = .flexibleHeight
bottomContainer.backgroundColor = Colors.navigationBarBackground
bottomContainer.themeBackgroundColor = .backgroundPrimary
self.bottomContainer = bottomContainer
let bottomStack = UIStackView(arrangedSubviews: [captionContainerView, galleryRailView, footerBar])
@ -179,7 +190,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
bottomStack.autoPinEdgesToSuperviewEdges()
let galleryRailBlockingView: UIView = UIView()
galleryRailBlockingView.backgroundColor = Colors.navigationBarBackground
galleryRailBlockingView.themeBackgroundColor = .backgroundPrimary
bottomStack.addSubview(galleryRailBlockingView)
galleryRailBlockingView.pin(.top, to: .bottom, of: footerBar)
galleryRailBlockingView.pin(.left, to: .left, of: bottomStack)
@ -196,12 +207,6 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
let verticalSwipe = UISwipeGestureRecognizer(target: self, action: #selector(didSwipeView))
verticalSwipe.direction = [.up, .down]
view.addGestureRecognizer(verticalSwipe)
let navigationBar = navigationController!.navigationBar
navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
navigationBar.shadowImage = UIImage()
navigationBar.isTranslucent = false
navigationBar.barTintColor = Colors.navigationBarBackground
// Notifications
NotificationCenter.default.addObserver(
@ -316,7 +321,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
target: self,
action: #selector(didPressShare)
)
shareBarButton.tintColor = Colors.text
shareBarButton.themeTintColor = .textPrimary
return shareBarButton
}()
@ -327,7 +332,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
target: self,
action: #selector(didPressDelete)
)
deleteBarButton.tintColor = Colors.text
deleteBarButton.themeTintColor = .textPrimary
return deleteBarButton
}()
@ -342,7 +347,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
target: self,
action: #selector(didPressPlayBarButton)
)
videoPlayBarButton.tintColor = Colors.text
videoPlayBarButton.themeTintColor = .textPrimary
return videoPlayBarButton
}()
@ -353,7 +358,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
target: self,
action: #selector(didPressPauseBarButton)
)
videoPauseBarButton.tintColor = Colors.text
videoPauseBarButton.themeTintColor = .textPrimary
return videoPauseBarButton
}()
@ -818,9 +823,9 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
}()
lazy private var portraitHeaderNameLabel: UILabel = {
let label = UILabel()
label.textColor = Colors.text
let label: UILabel = UILabel()
label.font = .systemFont(ofSize: Values.mediumFontSize)
label.themeTextColor = .textPrimary
label.textAlignment = .center
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.8
@ -829,9 +834,9 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
}()
lazy private var portraitHeaderDateLabel: UILabel = {
let label = UILabel()
label.textColor = Colors.text
let label: UILabel = UILabel()
label.font = .systemFont(ofSize: Values.verySmallFontSize)
label.themeTextColor = .textPrimary
label.textAlignment = .center
label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.8
@ -840,7 +845,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
}()
private lazy var portraitHeaderView: UIView = {
let stackView = UIStackView()
let stackView: UIStackView = UIStackView()
stackView.axis = .vertical
stackView.alignment = .center
stackView.spacing = 0
@ -915,12 +920,15 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
extension MediaGalleryViewModel.Item: GalleryRailItem {
public func buildRailItemView() -> UIView {
let imageView = UIImageView()
let imageView: UIImageView = UIImageView()
imageView.contentMode = .scaleAspectFill
getRailImage().map { [weak imageView] image in
guard let imageView = imageView else { return }
imageView.image = image
}.retainUntilComplete()
getRailImage()
.map { [weak imageView] image in
guard let imageView = imageView else { return }
imageView.image = image
}
.retainUntilComplete()
return imageView
}

View File

@ -71,7 +71,7 @@ public class MediaTileViewController: UIViewController, UICollectionViewDataSour
lazy var collectionView: UICollectionView = {
let result: UICollectionView = UICollectionView(frame: .zero, collectionViewLayout: mediaTileViewLayout)
result.translatesAutoresizingMaskIntoConstraints = false
result.backgroundColor = Colors.navigationBarBackground
result.themeBackgroundColor = .backgroundSecondary
result.delegate = self
result.dataSource = self
result.register(view: PhotoGridViewCell.self)
@ -95,8 +95,8 @@ public class MediaTileViewController: UIViewController, UICollectionViewDataSour
animated: false
)
result.barTintColor = Colors.navigationBarBackground
result.tintColor = Colors.text
result.themeBarTintColor = .backgroundPrimary
result.themeTintColor = .textPrimary
return result
}()
@ -107,19 +107,21 @@ public class MediaTileViewController: UIViewController, UICollectionViewDataSour
target: self,
action: #selector(didPressDelete)
)
result.tintColor = Colors.text
result.themeTintColor = .textPrimary
return result
}()
// MARK: - Lifecycle
override public func viewDidLoad() {
super.viewDidLoad()
view.themeBackgroundColor = .backgroundSecondary
// Add a custom back button if this is the only view controller
if self.navigationController?.viewControllers.first == self {
let backButton = OWSViewController.createOWSBackButton(withTarget: self, selector: #selector(didPressDismissButton))
let backButton = UIViewController.createOWSBackButton(target: self, selector: #selector(didPressDismissButton))
self.navigationItem.leftBarButtonItem = backButton
}
@ -763,25 +765,21 @@ private class MediaGallerySectionHeader: UICollectionReusableView {
override init(frame: CGRect) {
label = UILabel()
label.textColor = Colors.text
let blurEffect = UIBlurEffect(style: .dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
label.themeTextColor = .textPrimary
super.init(frame: frame)
self.backgroundColor = isLightMode ? Colors.cellBackground : UIColor.ows_black.withAlphaComponent(OWSNavigationBar.backgroundBlurMutingFactor)
self.themeBackgroundColor = .clear
let backgroundView: UIView = UIView()
backgroundView.themeBackgroundColor = .backgroundSecondary
addSubview(backgroundView)
backgroundView.pin(to: self)
self.addSubview(blurEffectView)
self.addSubview(label)
blurEffectView.autoPinEdgesToSuperviewEdges()
blurEffectView.isHidden = isLightMode
label.autoPinEdge(toSuperviewMargin: .trailing)
label.autoPinEdge(toSuperviewMargin: .leading)
label.autoVCenterInSuperview()
label.pin(.leading, to: .leading, of: self, withInset: Values.largeSpacing)
label.pin(.trailing, to: .trailing, of: self, withInset: -Values.largeSpacing)
label.center(.vertical, in: self)
}
@available(*, unavailable, message: "Unimplemented")
@ -811,7 +809,7 @@ private class MediaGalleryStaticHeader: UICollectionViewCell {
addSubview(label)
label.textColor = Colors.text
label.themeTextColor = .textPrimary
label.textAlignment = .center
label.numberOfLines = 0
label.autoPinEdgesToSuperviewMargins(with: UIEdgeInsets(top: 0, leading: Values.largeSpacing, bottom: 0, trailing: Values.largeSpacing))

View File

@ -3,6 +3,7 @@
//
import Foundation
import AVFoundation
import PromiseKit
import CoreServices
@ -54,9 +55,9 @@ class PhotoCapture: NSObject {
self.session.beginConfiguration()
defer { self.session.commitConfiguration() }
let audioDevice = AVCaptureDevice.default(for: .audio)
guard let audioDevice: AVCaptureDevice = AVCaptureDevice.default(for: .audio) else { return }
// verify works without audio permissions
let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice!)
let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice)
if session.canAddInput(audioDeviceInput) {
// self.session.addInputWithNoConnections(audioDeviceInput)
session.addInput(audioDeviceInput)

View File

@ -1,10 +1,10 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
import Foundation
import UIKit
import AVFoundation
import PromiseKit
import SessionUIKit
import SignalUtilitiesKit
protocol PhotoCaptureViewControllerDelegate: AnyObject {
func photoCaptureViewController(_ photoCaptureViewController: PhotoCaptureViewController, didFinishProcessingAttachment attachment: SignalAttachment)
@ -49,7 +49,7 @@ class PhotoCaptureViewController: OWSViewController {
override func loadView() {
self.view = UIView()
self.view.backgroundColor = .black
self.view.themeBackgroundColor = .backgroundSecondary
}
override func viewDidLoad() {
@ -82,7 +82,8 @@ class PhotoCaptureViewController: OWSViewController {
navigationItem.rightBarButtonItems = nil
navigationItem.titleView = recordingTimerView
recordingTimerView.sizeToFit()
} else {
}
else {
navigationItem.titleView = nil
navigationItem.leftBarButtonItem = dismissControl.barButtonItem
let fixedSpace = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
@ -114,8 +115,9 @@ class PhotoCaptureViewController: OWSViewController {
let barButtonItem: UIBarButtonItem
init(imageName: String, block: @escaping () -> Void) {
self.button = OWSButton(imageName: imageName, tintColor: .ows_white, block: block)
self.button = OWSButton(imageName: imageName, tintColor: .white, block: block)
button.autoPinToSquareAspectRatio()
button.themeShadowColor = .black
button.layer.shadowOffset = CGSize.zero
button.layer.shadowOpacity = 0.35
button.layer.shadowRadius = 4
@ -222,10 +224,12 @@ class PhotoCaptureViewController: OWSViewController {
private func setupOrientationMonitoring() {
UIDevice.current.beginGeneratingDeviceOrientationNotifications()
NotificationCenter.default.addObserver(self,
selector: #selector(didChangeDeviceOrientation),
name: UIDevice.orientationDidChangeNotification,
object: UIDevice.current)
NotificationCenter.default.addObserver(
self,
selector: #selector(didChangeDeviceOrientation),
name: UIDevice.orientationDidChangeNotification,
object: UIDevice.current
)
}
var lastKnownCaptureOrientation: AVCaptureVideoOrientation = .portrait
@ -282,15 +286,14 @@ class PhotoCaptureViewController: OWSViewController {
captureButton.delegate = photoCapture
previewView = CapturePreviewView(session: photoCapture.session)
photoCapture.startCapture().done { [weak self] in
guard let self = self else { return }
self.showCaptureUI()
}.catch { [weak self] error in
guard let self = self else { return }
self.showFailureUI(error: error)
}.retainUntilComplete()
photoCapture.startCapture()
.done { [weak self] in
self?.showCaptureUI()
}
.catch { [weak self] error in
self?.showFailureUI(error: error)
}
.retainUntilComplete()
}
private func showCaptureUI() {
@ -309,11 +312,17 @@ class PhotoCaptureViewController: OWSViewController {
private func showFailureUI(error: Error) {
Logger.error("error: \(error)")
OWSAlerts.showAlert(title: nil,
message: error.localizedDescription,
buttonTitle: CommonStrings.dismissButton,
buttonAction: { [weak self] _ in self?.dismiss(animated: true) })
let modal: ConfirmationModal = ConfirmationModal(
info: ConfirmationModal.Info(
title: CommonStrings.errorAlertTitle,
explanation: error.localizedDescription,
cancelTitle: CommonStrings.dismissButton,
cancelStyle: .textPrimary,
afterClosed: { [weak self] in self?.dismiss(animated: true) }
)
)
present(modal, animated: true)
}
private func updateFlashModeControl() {
@ -421,16 +430,17 @@ class CaptureButton: UIView {
addSubview(innerButton)
innerButtonSizeConstraints = autoSetDimensions(to: CGSize(width: defaultDiameter, height: defaultDiameter))
innerButton.backgroundColor = UIColor.ows_white.withAlphaComponent(0.33)
innerButton.themeBackgroundColor = .white
innerButton.layer.shadowOffset = .zero
innerButton.layer.shadowOpacity = 0.33
innerButton.layer.shadowRadius = 2
innerButton.alpha = 0.33
innerButton.autoPinEdgesToSuperviewEdges()
addSubview(zoomIndicator)
zoomIndicatorSizeConstraints = zoomIndicator.autoSetDimensions(to: CGSize(width: defaultDiameter, height: defaultDiameter))
zoomIndicator.isUserInteractionEnabled = false
zoomIndicator.layer.borderColor = UIColor.ows_white.cgColor
zoomIndicator.themeBorderColor = .white
zoomIndicator.layer.borderWidth = 1.5
zoomIndicator.autoAlignAxis(.horizontal, toSameAxisOf: innerButton)
zoomIndicator.autoAlignAxis(.vertical, toSameAxisOf: innerButton)
@ -569,10 +579,10 @@ class RecordingTimerView: UIView {
// MARK: - Subviews
private lazy var label: UILabel = {
let label = UILabel()
label.font = UIFont.ows_monospacedDigitFont(withSize: 20)
let label: UILabel = UILabel()
label.font = .ows_monospacedDigitFont(withSize: 20)
label.themeTextColor = .textPrimary
label.textAlignment = .center
label.textColor = UIColor.white
label.layer.shadowOffset = CGSize.zero
label.layer.shadowOpacity = 0.35
label.layer.shadowRadius = 4
@ -587,8 +597,7 @@ class RecordingTimerView: UIView {
icon.layer.shadowOffset = CGSize.zero
icon.layer.shadowOpacity = 0.35
icon.layer.shadowRadius = 4
icon.backgroundColor = .red
icon.themeBackgroundColor = .danger
icon.autoSetDimensions(to: CGSize(width: iconWidth, height: iconWidth))
icon.alpha = 0
@ -601,10 +610,12 @@ class RecordingTimerView: UIView {
func startCounting() {
recordingStartTime = CACurrentMediaTime()
timer = Timer.weakScheduledTimer(withTimeInterval: 0.1, target: self, selector: #selector(updateView), userInfo: nil, repeats: true)
UIView.animate(withDuration: 0.5,
delay: 0,
options: [.autoreverse, .repeat],
animations: { self.icon.alpha = 1 })
UIView.animate(
withDuration: 0.5,
delay: 0,
options: [.autoreverse, .repeat],
animations: { self.icon.alpha = 1 }
)
}
func stopCounting() {

View File

@ -28,9 +28,9 @@ public class PhotoGridViewCell: UICollectionViewCell {
private static let videoBadgeImage = #imageLiteral(resourceName: "ic_gallery_badge_video")
private static let animatedBadgeImage = #imageLiteral(resourceName: "ic_gallery_badge_gif")
private static let selectedBadgeImage = #imageLiteral(resourceName: "selected_blue_circle")
private static let selectedBadgeImage = UIImage(systemName: "checkmark.circle.fill")
public var loadingColor = Colors.unimportant
public var loadingColor: ThemeValue = .textSecondary
override public var isSelected: Bool {
didSet {
@ -52,18 +52,23 @@ public class PhotoGridViewCell: UICollectionViewCell {
self.contentTypeBadgeView = UIImageView()
contentTypeBadgeView.isHidden = true
let kSelectedBadgeSize = CGSize(width: 32, height: 32)
self.selectedBadgeView = UIImageView()
selectedBadgeView.image = PhotoGridViewCell.selectedBadgeImage
selectedBadgeView.image = PhotoGridViewCell.selectedBadgeImage?.withRenderingMode(.alwaysTemplate)
selectedBadgeView.themeTintColor = .primary
selectedBadgeView.themeBorderColor = .textPrimary
selectedBadgeView.themeBackgroundColor = .textPrimary
selectedBadgeView.isHidden = true
selectedBadgeView.layer.cornerRadius = (kSelectedBadgeSize.width / 2)
self.highlightedView = UIView()
highlightedView.alpha = 0.2
highlightedView.backgroundColor = Colors.cellSelected
highlightedView.themeBackgroundColor = .black
highlightedView.isHidden = true
self.selectedView = UIView()
selectedView.alpha = 0.3
selectedView.backgroundColor = Colors.cellSelected
selectedView.themeBackgroundColor = .black
selectedView.isHidden = true
super.init(frame: frame)
@ -87,9 +92,8 @@ public class PhotoGridViewCell: UICollectionViewCell {
contentTypeBadgeView.autoPinEdge(toSuperviewEdge: .bottom, withInset: 3)
contentTypeBadgeView.autoSetDimensions(to: kContentTypeBadgeSize)
let kSelectedBadgeSize = CGSize(width: 31, height: 31)
selectedBadgeView.autoPinEdge(toSuperviewEdge: .trailing, withInset: 0)
selectedBadgeView.autoPinEdge(toSuperviewEdge: .bottom, withInset: 0)
selectedBadgeView.autoPinEdge(toSuperviewEdge: .trailing, withInset: Values.verySmallSpacing)
selectedBadgeView.autoPinEdge(toSuperviewEdge: .bottom, withInset: Values.verySmallSpacing)
selectedBadgeView.autoSetDimensions(to: kSelectedBadgeSize)
}
@ -102,7 +106,7 @@ public class PhotoGridViewCell: UICollectionViewCell {
get { return imageView.image }
set {
imageView.image = newValue
imageView.backgroundColor = newValue == nil ? loadingColor : .clear
imageView.themeBackgroundColor = (newValue == nil ? loadingColor : .clear)
}
}

View File

@ -81,9 +81,9 @@ class SendMediaNavigationController: OWSNavigationController {
didSet {
if oldValue != isInBatchSelectMode {
mediaLibraryViewController.batchSelectModeDidChange()
guard let topViewController = viewControllers.last else {
return
}
guard let topViewController = viewControllers.last else { return }
updateButtons(topViewController: topViewController)
}
}
@ -91,23 +91,26 @@ class SendMediaNavigationController: OWSNavigationController {
func updateButtons(topViewController: UIViewController) {
switch topViewController {
case is AttachmentApprovalViewController:
batchModeButton.isHidden = true
doneButton.isHidden = true
cameraModeButton.isHidden = true
mediaLibraryModeButton.isHidden = true
case is ImagePickerGridController:
batchModeButton.isHidden = isInBatchSelectMode
doneButton.isHidden = !isInBatchSelectMode || (attachmentDraftCollection.count == 0 && mediaLibrarySelections.count == 0)
cameraModeButton.isHidden = false
mediaLibraryModeButton.isHidden = true
case is PhotoCaptureViewController:
batchModeButton.isHidden = isInBatchSelectMode
doneButton.isHidden = !isInBatchSelectMode || (attachmentDraftCollection.count == 0 && mediaLibrarySelections.count == 0)
cameraModeButton.isHidden = true
mediaLibraryModeButton.isHidden = false
default:
owsFailDebug("unexpected topViewController: \(topViewController)")
case is AttachmentApprovalViewController:
batchModeButton.isHidden = true
doneButton.isHidden = true
cameraModeButton.isHidden = true
mediaLibraryModeButton.isHidden = true
case is ImagePickerGridController:
batchModeButton.isHidden = isInBatchSelectMode
doneButton.isHidden = !isInBatchSelectMode || (attachmentDraftCollection.count == 0 && mediaLibrarySelections.count == 0)
cameraModeButton.isHidden = false
mediaLibraryModeButton.isHidden = true
case is PhotoCaptureViewController:
batchModeButton.isHidden = isInBatchSelectMode
doneButton.isHidden = !isInBatchSelectMode || (attachmentDraftCollection.count == 0 && mediaLibrarySelections.count == 0)
cameraModeButton.isHidden = true
mediaLibraryModeButton.isHidden = false
default:
owsFailDebug("unexpected topViewController: \(topViewController)")
}
doneButton.updateCount()
@ -150,52 +153,60 @@ class SendMediaNavigationController: OWSNavigationController {
private lazy var doneButton: DoneButton = {
let button = DoneButton()
button.delegate = self
button.setShadow()
return button
}()
private lazy var batchModeButton: UIButton = {
let button = OWSButton(imageName: "media_send_batch_mode_disabled",
tintColor: .ows_gray60,
block: { [weak self] in self?.didTapBatchModeButton() })
let width: CGFloat = type(of: self).bottomButtonWidth
button.autoSetDimensions(to: CGSize(width: width, height: width))
button.layer.cornerRadius = width / 2
let button = OWSButton(
imageName: "media_send_batch_mode_disabled",
tintColor: .backgroundPrimary,
block: { [weak self] in self?.didTapBatchModeButton() }
)
button.clipsToBounds = true
button.adjustsImageWhenHighlighted = false
button.setThemeBackgroundColor(.textPrimary, for: .normal)
button.setThemeBackgroundColor(.textSecondary, for: .highlighted)
button.imageEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
button.backgroundColor = .ows_white
button.setShadow()
button.layer.cornerRadius = (SendMediaNavigationController.bottomButtonWidth / 2)
button.set(.width, to: SendMediaNavigationController.bottomButtonWidth)
button.set(.height, to: SendMediaNavigationController.bottomButtonWidth)
return button
}()
private lazy var cameraModeButton: UIButton = {
let button = OWSButton(imageName: "settings-avatar-camera-2",
tintColor: .ows_gray60,
block: { [weak self] in self?.didTapCameraModeButton() })
let width: CGFloat = type(of: self).bottomButtonWidth
button.autoSetDimensions(to: CGSize(width: width, height: width))
button.layer.cornerRadius = width / 2
let button = OWSButton(
imageName: "settings-avatar-camera-2",
tintColor: .backgroundPrimary,
block: { [weak self] in self?.didTapCameraModeButton() }
)
button.clipsToBounds = true
button.adjustsImageWhenHighlighted = false
button.setThemeBackgroundColor(.textPrimary, for: .normal)
button.setThemeBackgroundColor(.textSecondary, for: .highlighted)
button.imageEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
button.backgroundColor = .ows_white
button.setShadow()
button.layer.cornerRadius = (SendMediaNavigationController.bottomButtonWidth / 2)
button.set(.width, to: SendMediaNavigationController.bottomButtonWidth)
button.set(.height, to: SendMediaNavigationController.bottomButtonWidth)
return button
}()
private lazy var mediaLibraryModeButton: UIButton = {
let button = OWSButton(imageName: "actionsheet_camera_roll_black",
tintColor: .ows_gray60,
block: { [weak self] in self?.didTapMediaLibraryModeButton() })
let width: CGFloat = type(of: self).bottomButtonWidth
button.autoSetDimensions(to: CGSize(width: width, height: width))
button.layer.cornerRadius = width / 2
let button = OWSButton(
imageName: "actionsheet_camera_roll_black",
tintColor: .backgroundPrimary,
block: { [weak self] in self?.didTapMediaLibraryModeButton() }
)
button.clipsToBounds = true
button.adjustsImageWhenHighlighted = false
button.setThemeBackgroundColor(.textPrimary, for: .normal)
button.setThemeBackgroundColor(.textSecondary, for: .highlighted)
button.imageEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
button.backgroundColor = .ows_white
button.setShadow()
button.layer.cornerRadius = (SendMediaNavigationController.bottomButtonWidth / 2)
button.set(.width, to: SendMediaNavigationController.bottomButtonWidth)
button.set(.height, to: SendMediaNavigationController.bottomButtonWidth)
return button
}()
@ -243,63 +254,45 @@ class SendMediaNavigationController: OWSNavigationController {
pushViewController(approvalViewController, animated: true)
}
private func didRequestExit(dontAbandonText: String) {
if attachmentDraftCollection.count == 0 {
private func didRequestExit() {
guard attachmentDraftCollection.count > 0 else {
self.sendMediaNavDelegate?.sendMediaNavDidCancel(self)
} else {
let alertTitle = NSLocalizedString("SEND_MEDIA_ABANDON_TITLE", comment: "alert title when user attempts to leave the send media flow when they have an in-progress album")
let alert = UIAlertController(title: alertTitle, message: nil, preferredStyle: .alert)
let confirmAbandonText = NSLocalizedString("SEND_MEDIA_CONFIRM_ABANDON_ALBUM", comment: "alert action, confirming the user wants to exit the media flow and abandon any photos they've taken")
let confirmAbandonAction = UIAlertAction(title: confirmAbandonText,
style: .destructive,
handler: { [weak self] _ in
guard let self = self else { return }
self.sendMediaNavDelegate?.sendMediaNavDidCancel(self)
})
alert.addAction(confirmAbandonAction)
let dontAbandonAction = UIAlertAction(title: dontAbandonText,
style: .default,
handler: { _ in })
alert.addAction(dontAbandonAction)
self.presentAlert(alert)
return
}
let modal: ConfirmationModal = ConfirmationModal(
info: ConfirmationModal.Info(
title: "SEND_MEDIA_ABANDON_TITLE".localized(),
confirmTitle: "SEND_MEDIA_CONFIRM_ABANDON_ALBUM".localized(),
confirmStyle: .danger,
cancelStyle: .textPrimary,
onConfirm: { [weak self] _ in
self?.sendMediaNavDelegate?.sendMediaNavDidCancel(self)
}
)
)
self.present(modal, animated: true)
}
}
extension SendMediaNavigationController: UINavigationControllerDelegate {
private func setNavBarBackgroundColor(to color: UIColor) {
guard let navBar = navigationBar as? OWSNavigationBar else { return }
navBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
navBar.shadowImage = UIImage()
navBar.isTranslucent = false
navBar.barTintColor = color
}
func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
if viewController == captureViewController {
setNavBarBackgroundColor(to: .black)
} else {
setNavBarBackgroundColor(to: Colors.navigationBarBackground)
}
switch viewController {
case is PhotoCaptureViewController:
if attachmentDraftCollection.count == 1 && !isInBatchSelectMode {
// User is navigating "back" to the previous view, indicating
// they want to discard the previously captured item
discardDraft()
}
case is ImagePickerGridController:
if attachmentDraftCollection.count == 1 && !isInBatchSelectMode {
isInBatchSelectMode = true
self.mediaLibraryViewController.batchSelectModeDidChange()
}
default:
break
case is PhotoCaptureViewController:
if attachmentDraftCollection.count == 1 && !isInBatchSelectMode {
// User is navigating "back" to the previous view, indicating
// they want to discard the previously captured item
discardDraft()
}
case is ImagePickerGridController:
if attachmentDraftCollection.count == 1 && !isInBatchSelectMode {
isInBatchSelectMode = true
self.mediaLibraryViewController.batchSelectModeDidChange()
}
default:
break
}
self.updateButtons(topViewController: viewController)
@ -307,30 +300,8 @@ extension SendMediaNavigationController: UINavigationControllerDelegate {
// In case back navigation was canceled, we re-apply whatever is showing.
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
if viewController == captureViewController {
setNavBarBackgroundColor(to: .black)
} else {
setNavBarBackgroundColor(to: Colors.navigationBarBackground)
}
self.updateButtons(topViewController: viewController)
}
// MARK: - Helpers
private func preferredNavbarTheme(viewController: UIViewController) -> OWSNavigationBar.NavigationBarThemeOverride? {
switch viewController {
case is AttachmentApprovalViewController:
return .clear
case is ImagePickerGridController:
return .alwaysDark
case is PhotoCaptureViewController:
return .clear
default:
owsFailDebug("unexpected viewController: \(viewController)")
return nil
}
}
}
extension SendMediaNavigationController: PhotoCaptureViewControllerDelegate {
@ -338,14 +309,14 @@ extension SendMediaNavigationController: PhotoCaptureViewControllerDelegate {
attachmentDraftCollection.append(.camera(attachment: attachment))
if isInBatchSelectMode {
updateButtons(topViewController: photoCaptureViewController)
} else {
}
else {
pushApprovalViewController()
}
}
func photoCaptureViewControllerDidCancel(_ photoCaptureViewController: PhotoCaptureViewController) {
let dontAbandonText = NSLocalizedString("SEND_MEDIA_RETURN_TO_CAMERA", comment: "alert action when the user decides not to cancel the media flow after all.")
didRequestExit(dontAbandonText: dontAbandonText)
didRequestExit()
}
func discardDraft() {
@ -364,8 +335,7 @@ extension SendMediaNavigationController: ImagePickerGridControllerDelegate {
}
func imagePickerDidCancel(_ imagePicker: ImagePickerGridController) {
let dontAbandonText = NSLocalizedString("SEND_MEDIA_RETURN_TO_MEDIA_LIBRARY", comment: "alert action when the user decides not to cancel the media flow after all.")
didRequestExit(dontAbandonText: dontAbandonText)
didRequestExit()
}
func showApprovalAfterProcessingAnyMediaLibrarySelections() {
@ -374,18 +344,21 @@ extension SendMediaNavigationController: ImagePickerGridControllerDelegate {
let backgroundBlock: (ModalActivityIndicatorViewController) -> Void = { modal in
let attachmentPromises: [Promise<MediaLibraryAttachment>] = mediaLibrarySelections.map { $0.promise }
when(fulfilled: attachmentPromises).map { attachments in
Logger.debug("built all attachments")
modal.dismiss {
self.attachmentDraftCollection.selectedFromPicker(attachments: attachments)
self.pushApprovalViewController()
when(fulfilled: attachmentPromises)
.map { attachments in
Logger.debug("built all attachments")
modal.dismiss {
self.attachmentDraftCollection.selectedFromPicker(attachments: attachments)
self.pushApprovalViewController()
}
}
}.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"))
.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"))
}
}
}.retainUntilComplete()
.retainUntilComplete()
}
ModalActivityIndicatorViewController.present(fromViewController: self,
@ -398,22 +371,17 @@ extension SendMediaNavigationController: ImagePickerGridControllerDelegate {
}
func imagePicker(_ imagePicker: ImagePickerGridController, didSelectAsset asset: PHAsset, attachmentPromise: Promise<SignalAttachment>) {
guard !mediaLibrarySelections.hasValue(forKey: asset) else {
return
}
guard !mediaLibrarySelections.hasValue(forKey: asset) else { return }
let libraryMedia = MediaLibrarySelection(asset: asset, signalAttachmentPromise: attachmentPromise)
mediaLibrarySelections.append(key: asset, value: libraryMedia)
updateButtons(topViewController: imagePicker)
}
func imagePicker(_ imagePicker: ImagePickerGridController, didDeselectAsset asset: PHAsset) {
guard mediaLibrarySelections.hasValue(forKey: asset) else {
return
}
guard mediaLibrarySelections.hasValue(forKey: asset) else { return }
mediaLibrarySelections.remove(key: asset)
updateButtons(topViewController: imagePicker)
}
@ -599,19 +567,70 @@ private protocol DoneButtonDelegate: AnyObject {
private class DoneButton: UIView {
weak var delegate: DoneButtonDelegate?
let numberFormatter: NumberFormatter = NumberFormatter()
private var didTouchDownInside: Bool = false
// MARK: - UI
private let container: UIView = {
let result: UIView = UIView()
result.themeBackgroundColor = .textPrimary
result.layer.cornerRadius = 20
return result
}()
private lazy var badge: CircleView = {
let result: CircleView = CircleView()
result.themeBackgroundColor = .primary
return result
}()
private lazy var badgeLabel: UILabel = {
let result: UILabel = UILabel()
result.font = .ows_dynamicTypeSubheadline.ows_monospaced()
result.themeTextColor = .black // Will render on the primary color so should always be black
result.textAlignment = .center
return result
}()
private lazy var chevron: UIView = {
let image: UIImage = {
guard CurrentAppContext().isRTL else { return #imageLiteral(resourceName: "small_chevron_right") }
return #imageLiteral(resourceName: "small_chevron_left")
}()
let result: UIImageView = UIImageView(image: image.withRenderingMode(.alwaysTemplate))
result.contentMode = .scaleAspectFit
result.themeTintColor = .backgroundPrimary
result.set(.width, to: 10)
result.set(.height, to: 18)
return result
}()
// MARK: - Lifecycle
init() {
super.init(frame: .zero)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTap(tapGesture:)))
addGestureRecognizer(tapGesture)
let container = UIView()
container.backgroundColor = .ows_white
container.layer.cornerRadius = 20
container.layoutMargins = UIEdgeInsets(top: 7, leading: 8, bottom: 7, trailing: 8)
addSubview(container)
container.autoPinEdgesToSuperviewMargins()
container.pin(to: self)
badge.addSubview(badgeLabel)
badgeLabel.pin(to: badge, withInset: 4)
// Constrain to be a pill that is at least a circle, and maybe wider.
badgeLabel.autoPin(toAspectRatio: 1.0, relation: .greaterThanOrEqual)
NSLayoutConstraint.autoSetPriority(.defaultLow) {
badgeLabel.autoPinToSquareAspectRatio()
}
let stackView = UIStackView(arrangedSubviews: [badge, chevron])
stackView.axis = .horizontal
@ -619,74 +638,78 @@ private class DoneButton: UIView {
stackView.spacing = 9
container.addSubview(stackView)
stackView.autoPinEdgesToSuperviewMargins()
}
let numberFormatter: NumberFormatter = NumberFormatter()
func updateCount() {
guard let delegate = delegate else {
return
}
badgeLabel.text = numberFormatter.string(for: delegate.doneButtonCount)
stackView.pin(.top, to: .top, of: container, withInset: 7)
stackView.pin(.leading, to: .leading, of: container, withInset: 8)
stackView.pin(.trailing, to: .trailing, of: container, withInset: -8)
stackView.pin(.bottom, to: .bottom, of: container, withInset: -7)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Functions
func updateCount() {
guard let delegate = delegate else { return }
// MARK: - Subviews
badgeLabel.text = numberFormatter.string(for: delegate.doneButtonCount)
}
// MARK: - Interaction
private lazy var badge: UIView = {
let badge = CircleView()
badge.layoutMargins = UIEdgeInsets(top: 4, leading: 4, bottom: 4, trailing: 4)
badge.backgroundColor = .ows_signalBlue
badge.addSubview(badgeLabel)
badgeLabel.autoPinEdgesToSuperviewMargins()
// Constrain to be a pill that is at least a circle, and maybe wider.
badgeLabel.autoPin(toAspectRatio: 1.0, relation: .greaterThanOrEqual)
NSLayoutConstraint.autoSetPriority(.defaultLow) {
badgeLabel.autoPinToSquareAspectRatio()
}
return badge
}()
private lazy var badgeLabel: UILabel = {
let label = UILabel()
label.textColor = .ows_white
label.font = UIFont.ows_dynamicTypeSubheadline.ows_monospaced()
label.textAlignment = .center
return label
}()
private lazy var chevron: UIView = {
let image: UIImage
if CurrentAppContext().isRTL {
image = #imageLiteral(resourceName: "small_chevron_left")
} else {
image = #imageLiteral(resourceName: "small_chevron_right")
}
let chevron = UIImageView(image: image.withRenderingMode(.alwaysTemplate))
chevron.contentMode = .scaleAspectFit
chevron.tintColor = .ows_gray60
chevron.autoSetDimensions(to: CGSize(width: 10, height: 18))
return chevron
}()
@objc
func didTap(tapGesture: UITapGestureRecognizer) {
@objc func didTap(tapGesture: UITapGestureRecognizer) {
delegate?.doneButtonWasTapped(self)
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
guard
isUserInteractionEnabled,
let location: CGPoint = touches.first?.location(in: self),
bounds.contains(location)
else { return }
didTouchDownInside = true
container.themeBackgroundColor = .textSecondary
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
guard
isUserInteractionEnabled,
let location: CGPoint = touches.first?.location(in: self),
bounds.contains(location),
didTouchDownInside
else {
if didTouchDownInside {
container.themeBackgroundColor = .textPrimary
}
return
}
container.themeBackgroundColor = .textSecondary
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
if didTouchDownInside {
container.themeBackgroundColor = .textPrimary
}
didTouchDownInside = false
}
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
if didTouchDownInside {
container.themeBackgroundColor = .textPrimary
}
didTouchDownInside = false
}
}
// MARK: - SendMediaNavDelegate
protocol SendMediaNavDelegate: AnyObject {
func sendMediaNavDidCancel(_ sendMediaNavigationController: SendMediaNavigationController)
func sendMediaNavDidCancel(_ sendMediaNavigationController: SendMediaNavigationController?)
func sendMediaNav(_ sendMediaNavigationController: SendMediaNavigationController, didApproveAttachments attachments: [SignalAttachment], forThreadId threadId: String, messageText: String?)
func sendMediaNavInitialMessageText(_ sendMediaNavigationController: SendMediaNavigationController) -> String?

View File

@ -79,8 +79,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
}
)
SNAppearance.switchToSessionAppearance()
if Environment.shared?.callManager.wrappedValue?.currentCall == nil {
UserDefaults.sharedLokiProject?.set(false, forKey: "isCallOngoing")
}

View File

@ -236,7 +236,7 @@ NSString *const ReportedApplicationStateDidChangeNotification = @"ReportedApplic
- (nullable UIAlertAction *)openSystemSettingsAction
{
return [UIAlertAction actionWithTitle:CommonStrings.openSettingsButton
accessibilityIdentifier:ACCESSIBILITY_IDENTIFIER_WITH_NAME(self, @"system_settings")
accessibilityIdentifier:[NSString stringWithFormat:@"%@.%@", self.class, @"system_settings"]
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *_Nonnull action) {
[UIApplication.sharedApplication openSystemSettings];

View File

@ -13,9 +13,7 @@
#import "OWSBezierPathView.h"
#import "OWSMessageTimerView.h"
#import "OWSNavigationController.h"
#import "OWSProgressView.h"
#import "OWSWindowManager.h"
#import "OWSQRCodeScanningViewController.h"
#import "MainAppContext.h"
#import "UIViewController+Permissions.h"
#import <PureLayout/PureLayout.h>
@ -31,9 +29,7 @@
#import <SignalUtilitiesKit/OWSViewController.h>
#import <SignalUtilitiesKit/UIColor+OWS.h>
#import <SignalUtilitiesKit/UIFont+OWS.h>
#import <SignalUtilitiesKit/UIUtil.h>
#import <SessionUtilitiesKit/UIView+OWS.h>
#import <SignalUtilitiesKit/UIViewController+OWS.h>
#import <SignalUtilitiesKit/AppVersion.h>
#import <SessionUtilitiesKit/DataSource.h>
#import <SessionUtilitiesKit/MIMETypeUtil.h>

View File

@ -3,6 +3,7 @@
import UIKit
import SessionUIKit
import SessionMessagingKit
import SignalUtilitiesKit
final class DisplayNameVC: BaseVC {
private var spacer1HeightConstraint: NSLayoutConstraint!
@ -13,8 +14,8 @@ final class DisplayNameVC: BaseVC {
// MARK: - Components
private lazy var displayNameTextField: TextField = {
let result = TextField(placeholder: NSLocalizedString("vc_display_name_text_field_hint", comment: ""))
result.layer.borderColor = Colors.text.cgColor
let result = TextField(placeholder: "vc_display_name_text_field_hint".localized())
result.themeBorderColor = .textPrimary
result.accessibilityLabel = "Display name text field"
return result
@ -31,7 +32,7 @@ final class DisplayNameVC: BaseVC {
let titleLabel = UILabel()
titleLabel.font = .boldSystemFont(ofSize: isIPhone5OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize)
titleLabel.text = "vc_display_name_title_2".localized()
titleLabel.textColor = Colors.text
titleLabel.themeTextColor = .textPrimary
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.numberOfLines = 0
@ -39,7 +40,7 @@ final class DisplayNameVC: BaseVC {
let explanationLabel = UILabel()
explanationLabel.font = .systemFont(ofSize: Values.smallFontSize)
explanationLabel.text = "vc_display_name_explanation".localized()
explanationLabel.textColor = Colors.text
explanationLabel.themeTextColor = .textPrimary
explanationLabel.lineBreakMode = .byWordWrapping
explanationLabel.numberOfLines = 0

View File

@ -66,8 +66,8 @@ final class FakeChatView: UIView {
let result = UIView()
let bubbleView = UIView()
bubbleView.set(.width, to: FakeChatView.bubbleWidth)
bubbleView.themeShadowColor = .black
bubbleView.layer.cornerRadius = FakeChatView.bubbleCornerRadius
bubbleView.layer.shadowColor = UIColor.black.cgColor
bubbleView.layer.shadowRadius = isLightMode ? 4 : 8
bubbleView.layer.shadowOpacity = isLightMode ? 0.16 : 0.24
bubbleView.layer.shadowOffset = CGSize.zero

View File

@ -1,12 +1,14 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import AVFoundation
import PromiseKit
import SessionUIKit
import SessionUtilitiesKit
import SessionSnodeKit
import SignalUtilitiesKit
final class LinkDeviceVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControllerDelegate, OWSQRScannerDelegate {
final class LinkDeviceVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControllerDelegate, QRScannerDelegate {
private let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
private var pages: [UIViewController] = []
private var targetVCIndex: Int?
@ -42,29 +44,32 @@ final class LinkDeviceVC: BaseVC, UIPageViewControllerDataSource, UIPageViewCont
}()
private lazy var scanQRCodeWrapperVC: ScanQRCodeWrapperVC = {
let message = NSLocalizedString("vc_link_device_scan_qr_code_explanation", comment: "")
let message = "vc_link_device_scan_qr_code_explanation".localized()
let result = ScanQRCodeWrapperVC(message: message)
result.delegate = self
return result
}()
// MARK: Lifecycle
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setNavBarTitle("vc_link_device_title".localized())
let navigationBar = navigationController!.navigationBar
// Page VC
let hasCameraAccess = (AVCaptureDevice.authorizationStatus(for: .video) == .authorized)
pages = [ recoveryPhraseVC, (hasCameraAccess ? scanQRCodeWrapperVC : scanQRCodePlaceholderVC) ]
pageVC.dataSource = self
pageVC.delegate = self
pageVC.setViewControllers([ recoveryPhraseVC ], direction: .forward, animated: false, completion: nil)
// Tab bar
view.addSubview(tabBar)
tabBar.pin(.leading, to: .leading, of: view)
tabBarTopConstraint = tabBar.autoPinEdge(toSuperviewSafeArea: .top)
view.pin(.trailing, to: .trailing, of: tabBar)
// Page VC constraints
let pageVCView = pageVC.view!
view.addSubview(pageVCView)
@ -72,10 +77,11 @@ final class LinkDeviceVC: BaseVC, UIPageViewControllerDataSource, UIPageViewCont
pageVCView.pin(.top, to: .bottom, of: tabBar)
view.pin(.trailing, to: .trailing, of: pageVCView)
view.pin(.bottom, to: .bottom, of: pageVCView)
let screen = UIScreen.main.bounds
pageVCView.set(.width, to: screen.width)
let statusBarHeight = UIApplication.shared.statusBarFrame.height
let height = navigationController!.view.bounds.height - navigationBar.height() - TabBar.snHeight - statusBarHeight
let height = (navigationController?.view.bounds.height ?? 0) - (navigationController?.navigationBar.bounds.height ?? 0) - TabBar.snHeight - statusBarHeight
pageVCView.set(.height, to: height)
recoveryPhraseVC.constrainHeight(to: height)
scanQRCodePlaceholderVC.constrainHeight(to: height)
@ -90,7 +96,8 @@ final class LinkDeviceVC: BaseVC, UIPageViewControllerDataSource, UIPageViewCont
NotificationCenter.default.removeObserver(self)
}
// MARK: General
// MARK: - General
func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? {
guard let index = pages.firstIndex(of: viewController), index != 0 else { return nil }
return pages[index - 1]
@ -106,7 +113,8 @@ final class LinkDeviceVC: BaseVC, UIPageViewControllerDataSource, UIPageViewCont
pageVC.setViewControllers([ scanQRCodeWrapperVC ], direction: .forward, animated: false, completion: nil)
}
// MARK: Updating
// MARK: - Updating
func pageViewController(_ pageViewController: UIPageViewController, willTransitionTo pendingViewControllers: [UIViewController]) {
guard let targetVC = pendingViewControllers.first, let index = pages.firstIndex(of: targetVC) else { return }
targetVCIndex = index
@ -117,27 +125,31 @@ final class LinkDeviceVC: BaseVC, UIPageViewControllerDataSource, UIPageViewCont
tabBar.selectTab(at: index)
}
// MARK: Interaction
// MARK: - Interaction
@objc private func close() {
dismiss(animated: true, completion: nil)
}
func controller(_ controller: OWSQRCodeScanningViewController, didDetectQRCodeWith string: String) {
func controller(_ controller: QRCodeScanningViewController, didDetectQRCodeWith string: String) {
let seed = Data(hex: string)
continueWithSeed(seed)
}
func continueWithSeed(_ seed: Data) {
if (seed.count != 16) {
let alert = UIAlertController(
title: "invalid_recovery_phrase".localized(),
message: "INVALID_RECOVERY_PHRASE_MESSAGE".localized(),
preferredStyle: .alert
let modal: ConfirmationModal = ConfirmationModal(
info: ConfirmationModal.Info(
title: "invalid_recovery_phrase".localized(),
explanation: "INVALID_RECOVERY_PHRASE_MESSAGE".localized(),
cancelTitle: "BUTTON_OK".localized(),
cancelStyle: .textPrimary,
afterClosed: { [weak self] in
self?.scanQRCodeWrapperVC.startCapture()
}
)
)
alert.addAction(UIAlertAction(title: NSLocalizedString("BUTTON_OK", comment: ""), style: .default, handler: { _ in
self.scanQRCodeWrapperVC.startCapture()
}))
presentAlert(alert)
present(modal, animated: true)
return
}
let (ed25519KeyPair, x25519KeyPair) = try! Identity.generate(from: seed)
@ -164,7 +176,7 @@ final class LinkDeviceVC: BaseVC, UIPageViewControllerDataSource, UIPageViewCont
}
}
private final class RecoveryPhraseVC : UIViewController {
private final class RecoveryPhraseVC: UIViewController {
weak var linkDeviceVC: LinkDeviceVC!
private var spacer1HeightConstraint: NSLayoutConstraint!
private var spacer2HeightConstraint: NSLayoutConstraint!
@ -172,21 +184,23 @@ private final class RecoveryPhraseVC : UIViewController {
private var bottomConstraint: NSLayoutConstraint!
private lazy var mnemonicTextView: TextView = {
let result = TextView(placeholder: NSLocalizedString("vc_restore_seed_text_field_hint", comment: ""))
result.layer.borderColor = Colors.text.cgColor
let result = TextView(placeholder: "vc_restore_seed_text_field_hint".localized())
result.themeBorderColor = .textPrimary
result.accessibilityLabel = "Recovery phrase text view"
return result
}()
// MARK: Lifecycle
// MARK: - Lifecycle
override func viewDidLoad() {
view.backgroundColor = .clear
view.themeBackgroundColor = .clear
// Title label
let titleLabel = UILabel()
titleLabel.font = .boldSystemFont(ofSize: isIPhone5OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize)
titleLabel.text = "vc_enter_recovery_phrase_title".localized()
titleLabel.textColor = Colors.text
titleLabel.themeTextColor = .textPrimary
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.numberOfLines = 0
@ -194,7 +208,7 @@ private final class RecoveryPhraseVC : UIViewController {
let explanationLabel = UILabel()
explanationLabel.font = .systemFont(ofSize: Values.smallFontSize)
explanationLabel.text = "vc_enter_recovery_phrase_explanation".localized()
explanationLabel.textColor = Colors.text
explanationLabel.themeTextColor = .textPrimary
explanationLabel.lineBreakMode = .byWordWrapping
explanationLabel.numberOfLines = 0
@ -267,7 +281,8 @@ private final class RecoveryPhraseVC : UIViewController {
mnemonicTextView.resignFirstResponder()
}
// MARK: Updating
// MARK: - Updating
@objc private func handleKeyboardWillChangeFrameNotification(_ notification: Notification) {
guard let newHeight = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size.height else { return }
bottomConstraint.constant = -newHeight // Negative due to how the constraint is set up
@ -289,11 +304,12 @@ private final class RecoveryPhraseVC : UIViewController {
}
}
// MARK: Interaction
// MARK: - Interaction
@objc private func handleContinueButtonTapped() {
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))
alert.addAction(UIAlertAction(title: "BUTTON_OK".localized(), style: .default, handler: nil))
presentAlert(alert)
}
let mnemonic = mnemonicTextView.text!.lowercased()
@ -309,31 +325,35 @@ private final class RecoveryPhraseVC : UIViewController {
}
}
private final class ScanQRCodePlaceholderVC : UIViewController {
private final class ScanQRCodePlaceholderVC: UIViewController {
weak var linkDeviceVC: LinkDeviceVC!
override func viewDidLoad() {
// Remove background color
view.backgroundColor = .clear
view.themeBackgroundColor = .clear
// Set up explanation label
let explanationLabel = UILabel()
explanationLabel.textColor = Colors.text
explanationLabel.font = .systemFont(ofSize: Values.smallFontSize)
explanationLabel.text = NSLocalizedString("vc_scan_qr_code_camera_access_explanation", comment: "")
explanationLabel.numberOfLines = 0
explanationLabel.text = "vc_scan_qr_code_camera_access_explanation".localized()
explanationLabel.themeTextColor = .textPrimary
explanationLabel.textAlignment = .center
explanationLabel.lineBreakMode = .byWordWrapping
explanationLabel.numberOfLines = 0
// Set up call to action button
let callToActionButton = UIButton()
callToActionButton.titleLabel!.font = .boldSystemFont(ofSize: Values.mediumFontSize)
callToActionButton.setTitleColor(Colors.accent, for: UIControl.State.normal)
callToActionButton.setTitle(NSLocalizedString("vc_scan_qr_code_grant_camera_access_button_title", comment: ""), for: UIControl.State.normal)
callToActionButton.addTarget(self, action: #selector(requestCameraAccess), for: UIControl.Event.touchUpInside)
callToActionButton.titleLabel?.font = .boldSystemFont(ofSize: Values.mediumFontSize)
callToActionButton.setTitle("vc_scan_qr_code_grant_camera_access_button_title".localized(), for: .normal)
callToActionButton.setThemeTitleColor(.primary, for: .normal)
callToActionButton.addTarget(self, action: #selector(requestCameraAccess), for: .touchUpInside)
// Set up stack view
let stackView = UIStackView(arrangedSubviews: [ explanationLabel, callToActionButton ])
stackView.axis = .vertical
stackView.spacing = Values.mediumSpacing
stackView.alignment = .center
// Set up constraints
view.set(.width, to: UIScreen.main.bounds.width)
view.addSubview(stackView)

View File

@ -5,8 +5,9 @@ import PromiseKit
import SessionUIKit
import SessionMessagingKit
import SessionSnodeKit
import SignalUtilitiesKit
final class PNModeVC : BaseVC, OptionViewDelegate {
final class PNModeVC: BaseVC, OptionViewDelegate {
private var optionViews: [OptionView] {
[ apnsOptionView, backgroundPollingOptionView ]
@ -16,36 +17,47 @@ final class PNModeVC : BaseVC, OptionViewDelegate {
return optionViews.first { $0.isSelected }
}
// MARK: Components
// MARK: - Components
private lazy var apnsOptionView: OptionView = {
let explanation = NSLocalizedString("fast_mode_explanation", comment: "")
let result = OptionView(title: "Fast Mode", explanation: explanation, delegate: self, isRecommended: true)
let result: OptionView = OptionView(
title: "Fast Mode",
explanation: "fast_mode_explanation".localized(),
delegate: self,
isRecommended: true
)
result.accessibilityLabel = "Fast mode option"
return result
}()
private lazy var backgroundPollingOptionView: OptionView = {
let explanation = NSLocalizedString("slow_mode_explanation", comment: "")
let result = OptionView(title: "Slow Mode", explanation: explanation, delegate: self)
let result: OptionView = OptionView(
title: "Slow Mode",
explanation: "slow_mode_explanation".localized(),
delegate: self
)
result.accessibilityLabel = "Slow mode option"
return result
}()
// MARK: Lifecycle
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setUpNavBarSessionIcon()
let learnMoreButton = UIBarButtonItem(image: #imageLiteral(resourceName: "ic_info"), style: .plain, target: self, action: #selector(learnMore))
learnMoreButton.tintColor = Colors.text
learnMoreButton.themeTintColor = .textPrimary
navigationItem.rightBarButtonItem = learnMoreButton
// Set up title label
let titleLabel = UILabel()
titleLabel.font = .boldSystemFont(ofSize: isIPhone5OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize)
titleLabel.text = "vc_pn_mode_title".localized()
titleLabel.textColor = Colors.text
titleLabel.themeTextColor = .textPrimary
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.numberOfLines = 0

View File

@ -1,10 +1,14 @@
import UIKit
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
final class OptionView : UIView {
import UIKit
import SessionUIKit
final class OptionView: UIView {
private let title: String
private let explanation: String
private let delegate: OptionViewDelegate
private let isRecommended: Bool
var isSelected = false { didSet { handleIsSelectedChanged() } }
private static let cornerRadius: CGFloat = 8
@ -14,7 +18,9 @@ final class OptionView : UIView {
self.explanation = explanation
self.delegate = delegate
self.isRecommended = isRecommended
super.init(frame: CGRect.zero)
setUpViewHierarchy()
}
@ -27,49 +33,68 @@ final class OptionView : UIView {
}
private func setUpViewHierarchy() {
backgroundColor = Colors.pnOptionBackground
themeBackgroundColor = .backgroundSecondary
// Round corners
layer.cornerRadius = OptionView.cornerRadius
// Set up border
themeBorderColor = .borderSeparator
layer.borderWidth = 1
layer.borderColor = Colors.pnOptionBorder.cgColor
// Set up shadow
layer.shadowColor = UIColor.black.cgColor
themeShadowColor = .black
layer.shadowOffset = CGSize(width: 0, height: 0.8)
layer.shadowOpacity = isLightMode ? 0.16 : 1
layer.shadowRadius = isLightMode ? 4 : 6
ThemeManager.onThemeChange(observer: self) { [weak self] theme, _ in
switch theme.interfaceStyle {
case .light:
self?.layer.shadowOpacity = 0.16
self?.layer.shadowRadius = 4
default:
self?.layer.shadowOpacity = 1
self?.layer.shadowRadius = 6
}
}
// Set up title label
let titleLabel = UILabel()
titleLabel.textColor = Colors.text
let titleLabel: UILabel = UILabel()
titleLabel.font = .boldSystemFont(ofSize: Values.mediumFontSize)
titleLabel.text = title
titleLabel.numberOfLines = 0
titleLabel.themeTextColor = .textPrimary
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.numberOfLines = 0
// Set up explanation label
let explanationLabel = UILabel()
explanationLabel.textColor = Colors.text
let explanationLabel: UILabel = UILabel()
explanationLabel.font = .systemFont(ofSize: Values.verySmallFontSize)
explanationLabel.text = explanation
explanationLabel.numberOfLines = 0
explanationLabel.themeTextColor = .textPrimary
explanationLabel.lineBreakMode = .byWordWrapping
explanationLabel.numberOfLines = 0
// Set up stack view
let stackView = UIStackView(arrangedSubviews: [ titleLabel, explanationLabel ])
stackView.axis = .vertical
stackView.spacing = 4
stackView.alignment = .fill
addSubview(stackView)
stackView.pin(.leading, to: .leading, of: self, withInset: 12)
stackView.pin(.top, to: .top, of: self, withInset: 12)
self.pin(.trailing, to: .trailing, of: stackView, withInset: 12)
self.pin(.bottom, to: .bottom, of: stackView, withInset: 12)
// Set up recommended label if needed
if isRecommended {
let recommendedLabel = UILabel()
recommendedLabel.textColor = Colors.accent
let recommendedLabel: UILabel = UILabel()
recommendedLabel.font = .boldSystemFont(ofSize: Values.smallFontSize)
recommendedLabel.text = NSLocalizedString("vc_pn_mode_recommended_option_tag", comment: "")
recommendedLabel.text = "vc_pn_mode_recommended_option_tag".localized()
recommendedLabel.themeTextColor = .primary
stackView.addArrangedSubview(recommendedLabel)
}
// Set up tap gesture recognizer
let tapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleTap))
addGestureRecognizer(tapGestureRecognizer)
@ -80,30 +105,18 @@ final class OptionView : UIView {
}
private func handleIsSelectedChanged() {
let animationDuration: TimeInterval = 0.25
// Animate border color
let newBorderColor = isSelected ? Colors.accent.cgColor : Colors.pnOptionBorder.cgColor
let borderAnimation = CABasicAnimation(keyPath: "borderColor")
borderAnimation.fromValue = layer.shadowColor
borderAnimation.toValue = newBorderColor
borderAnimation.duration = animationDuration
layer.add(borderAnimation, forKey: borderAnimation.keyPath)
layer.borderColor = newBorderColor
// Animate shadow color
let newShadowColor = isSelected ? Colors.expandedButtonGlowColor.cgColor : UIColor.black.cgColor
let shadowAnimation = CABasicAnimation(keyPath: "shadowColor")
shadowAnimation.fromValue = layer.shadowColor
shadowAnimation.toValue = newShadowColor
shadowAnimation.duration = animationDuration
layer.add(shadowAnimation, forKey: shadowAnimation.keyPath)
layer.shadowColor = newShadowColor
UIView.animate(withDuration: 0.3) { [weak self] in
self?.themeBorderColor = (self?.isSelected == true ? .primary : .borderSeparator)
self?.themeShadowColor = (self?.isSelected == true ? .primary : .black)
}
// Notify delegate
if isSelected { delegate.optionViewDidActivate(self) }
}
}
// MARK: Option View Delegate
protocol OptionViewDelegate {
// MARK: - Option View Delegate
protocol OptionViewDelegate {
func optionViewDidActivate(_ optionView: OptionView)
}

View File

@ -4,6 +4,7 @@ import UIKit
import Sodium
import Curve25519Kit
import SessionUIKit
import SignalUtilitiesKit
final class RegisterVC : BaseVC {
private var seed: Data! { didSet { updateKeyPair() } }
@ -14,11 +15,11 @@ final class RegisterVC : BaseVC {
private lazy var publicKeyLabel: UILabel = {
let result = UILabel()
result.textColor = Colors.text
result.font = Fonts.spaceMono(ofSize: isIPhone5OrSmaller ? Values.mediumFontSize : 20)
result.numberOfLines = 0
result.lineBreakMode = .byCharWrapping
result.themeTextColor = .textPrimary
result.accessibilityLabel = "Session ID label"
result.lineBreakMode = .byCharWrapping
result.numberOfLines = 0
return result
}()
@ -33,21 +34,23 @@ final class RegisterVC : BaseVC {
private lazy var legalLabel: UILabel = {
let result = UILabel()
result.textColor = Colors.text
result.font = .systemFont(ofSize: Values.verySmallFontSize)
result.themeTextColor = .textPrimary
let text = "By using this service, you agree to our Terms of Service, End User License Agreement (EULA) and Privacy Policy"
let attributedText = NSMutableAttributedString(string: text, attributes: [ .font : UIFont.systemFont(ofSize: Values.verySmallFontSize) ])
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Terms of Service"))
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "End User License Agreement (EULA)"))
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Privacy Policy"))
result.attributedText = attributedText
result.numberOfLines = 0
result.textAlignment = .center
result.lineBreakMode = .byWordWrapping
result.numberOfLines = 0
return result
}()
// MARK: Lifecycle
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
@ -57,7 +60,7 @@ final class RegisterVC : BaseVC {
let titleLabel = UILabel()
titleLabel.font = .boldSystemFont(ofSize: isIPhone5OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize)
titleLabel.text = "vc_register_title".localized()
titleLabel.textColor = Colors.text
titleLabel.themeTextColor = .textPrimary
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.numberOfLines = 0
@ -65,7 +68,7 @@ final class RegisterVC : BaseVC {
let explanationLabel = UILabel()
explanationLabel.font = .systemFont(ofSize: Values.smallFontSize)
explanationLabel.text = "vc_register_explanation".localized()
explanationLabel.textColor = Colors.text
explanationLabel.themeTextColor = .textPrimary
explanationLabel.lineBreakMode = .byWordWrapping
explanationLabel.numberOfLines = 0
@ -75,7 +78,7 @@ final class RegisterVC : BaseVC {
publicKeyLabel.pin(to: publicKeyLabelContainer, withInset: Values.mediumSpacing)
publicKeyLabelContainer.layer.cornerRadius = TextField.cornerRadius
publicKeyLabelContainer.layer.borderWidth = 1
publicKeyLabelContainer.layer.borderColor = Colors.text.cgColor
publicKeyLabelContainer.themeBorderColor = .textPrimary
// Set up spacers
let topSpacer = UIView.vStretchingSpacer()

View File

@ -3,6 +3,7 @@
import UIKit
import SessionUIKit
import SessionUtilitiesKit
import SignalUtilitiesKit
final class RestoreVC: BaseVC {
private var spacer1HeightConstraint: NSLayoutConstraint!
@ -11,11 +12,12 @@ final class RestoreVC: BaseVC {
private var restoreButtonBottomOffsetConstraint: NSLayoutConstraint!
private var bottomConstraint: NSLayoutConstraint!
// MARK: Components
// MARK: - Components
private lazy var mnemonicTextView: TextView = {
let result = TextView(placeholder: "vc_restore_seed_text_field_hint".localized())
result.autocapitalizationType = .none
result.layer.borderColor = Colors.text.cgColor
result.themeBorderColor = .textPrimary
result.accessibilityLabel = "Recovery phrase text view"
return result
@ -34,7 +36,7 @@ final class RestoreVC: BaseVC {
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Terms of Service"))
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "End User License Agreement (EULA)"))
attributedText.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: Values.verySmallFontSize), range: (text as NSString).range(of: "Privacy Policy"))
result.textColor = Colors.text
result.themeTextColor = .textPrimary
result.attributedText = attributedText
result.textAlignment = .center
result.lineBreakMode = .byWordWrapping
@ -54,7 +56,7 @@ final class RestoreVC: BaseVC {
let titleLabel = UILabel()
titleLabel.font = .boldSystemFont(ofSize: isIPhone5OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize)
titleLabel.text = "vc_restore_title".localized()
titleLabel.textColor = Colors.text
titleLabel.themeTextColor = .textPrimary
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.numberOfLines = 0
@ -62,7 +64,7 @@ final class RestoreVC: BaseVC {
let explanationLabel = UILabel()
explanationLabel.font = .systemFont(ofSize: Values.smallFontSize)
explanationLabel.text = "vc_restore_explanation".localized()
explanationLabel.textColor = Colors.text
explanationLabel.themeTextColor = .textPrimary
explanationLabel.lineBreakMode = .byWordWrapping
explanationLabel.numberOfLines = 0
@ -70,6 +72,7 @@ final class RestoreVC: BaseVC {
legalLabel.isUserInteractionEnabled = true
let legalLabelTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleLegalLabelTapped))
legalLabel.addGestureRecognizer(legalLabelTapGestureRecognizer)
// Set up spacers
let topSpacer = UIView.vStretchingSpacer()
let spacer1 = UIView()
@ -146,12 +149,15 @@ final class RestoreVC: BaseVC {
// MARK: Updating
@objc private func handleKeyboardWillChangeFrameNotification(_ notification: Notification) {
guard let newHeight = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue.size.height else { return }
bottomConstraint.constant = -newHeight // Negative due to how the constraint is set up
restoreButtonBottomOffsetConstraint.constant = isIPhone6OrSmaller ? Values.smallSpacing : Values.largeSpacing
spacer1HeightConstraint.constant = isIPhone6OrSmaller ? Values.smallSpacing : Values.mediumSpacing
spacer2HeightConstraint.constant = isIPhone6OrSmaller ? Values.smallSpacing : Values.mediumSpacing
spacer3HeightConstraint.constant = isIPhone6OrSmaller ? Values.smallSpacing : Values.mediumSpacing
if isIPhone5OrSmaller { legalLabel.isUserInteractionEnabled = false }
UIView.animate(withDuration: 0.25) {
if isIPhone5OrSmaller { self.legalLabel.alpha = 0 }
self.view.layoutIfNeeded()
@ -164,20 +170,30 @@ final class RestoreVC: BaseVC {
spacer1HeightConstraint.constant = isIPhone5OrSmaller ? Values.smallSpacing : Values.veryLargeSpacing
spacer2HeightConstraint.constant = isIPhone5OrSmaller ? Values.smallSpacing : Values.veryLargeSpacing
spacer3HeightConstraint.constant = isIPhone5OrSmaller ? Values.smallSpacing : Values.veryLargeSpacing
if isIPhone5OrSmaller { legalLabel.isUserInteractionEnabled = true }
UIView.animate(withDuration: 0.25) {
if isIPhone5OrSmaller { self.legalLabel.alpha = 1 }
self.view.layoutIfNeeded()
}
}
// MARK: Interaction
// MARK: - Interaction
@objc private func restore() {
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(
info: ConfirmationModal.Info(
title: title,
explanation: message,
cancelTitle: "BUTTON_OK".localized(),
cancelStyle: .textPrimary
)
)
present(modal, animated: true)
}
let mnemonic = mnemonicTextView.text!.lowercased()
do {
let hexEncodedSeed = try Mnemonic.decode(mnemonic: mnemonic)
@ -185,6 +201,7 @@ final class RestoreVC: BaseVC {
let (ed25519KeyPair, x25519KeyPair) = try! Identity.generate(from: seed)
Onboarding.Flow.recover.preregister(with: seed, ed25519KeyPair: ed25519KeyPair, x25519KeyPair: x25519KeyPair)
mnemonicTextView.resignFirstResponder()
Timer.scheduledTimer(withTimeInterval: 0.25, repeats: false) { _ in
let displayNameVC = DisplayNameVC()
self.navigationController!.pushViewController(displayNameVC, animated: true)
@ -202,6 +219,7 @@ final class RestoreVC: BaseVC {
let ppRange = (legalLabel.text! as NSString).range(of: "Privacy Policy")
let touchInLegalLabelCoordinates = tapGestureRecognizer.location(in: legalLabel)
let characterIndex = legalLabel.characterIndex(for: touchInLegalLabelCoordinates)
if tosRange.contains(characterIndex) {
urlAsString = "https://getsession.org/terms-of-service/"
} else if eulaRange.contains(characterIndex) {
@ -211,6 +229,7 @@ final class RestoreVC: BaseVC {
} else {
urlAsString = nil
}
if let urlAsString = urlAsString {
let url = URL(string: urlAsString)!
UIApplication.shared.open(url)

View File

@ -38,8 +38,8 @@ final class SeedReminderView: UIView {
let result = UILabel()
result.font = .systemFont(ofSize: Values.verySmallFontSize)
result.themeTextColor = .textSecondary
result.numberOfLines = 0
result.lineBreakMode = .byWordWrapping
result.numberOfLines = 2
return result
}()
@ -66,8 +66,17 @@ final class SeedReminderView: UIView {
// Set background color
themeBackgroundColor = .conversationButton_background
// Note: We hard-code the height of the subtitle to 2 lines so changing it's content
// doesn't result in the view changing height (which looks buggy)
let subtitleContainerView: UIView = UIView()
subtitleContainerView.set(.height, to: (subtitleLabel.font.lineHeight * 2))
subtitleContainerView.addSubview(subtitleLabel)
subtitleLabel.pin(.top, to: .top, of: subtitleContainerView)
subtitleLabel.pin(.leading, to: .leading, of: subtitleContainerView)
subtitleLabel.pin(.trailing, to: .trailing, of: subtitleContainerView)
// Set up label stack view
let labelStackView = UIStackView(arrangedSubviews: [ titleLabel, subtitleLabel ])
let labelStackView = UIStackView(arrangedSubviews: [ titleLabel, subtitleContainerView ])
labelStackView.axis = .vertical
labelStackView.spacing = 4
@ -103,12 +112,12 @@ final class SeedReminderView: UIView {
stackView.pin(to: self)
}
// MARK: Updating
// MARK: - Updating
func setProgress(_ progress: Float, animated isAnimated: Bool) {
progressIndicatorView.setProgress(progress, animated: isAnimated)
}
// MARK: Updating
@objc private func handleContinueButtonTapped() {
delegate?.handleContinueButtonTapped(from: self)
}

View File

@ -3,6 +3,7 @@
import UIKit
import SessionUIKit
import SessionUtilitiesKit
import SignalUtilitiesKit
final class SeedVC: BaseVC {
private let mnemonic: String = {
@ -26,20 +27,27 @@ final class SeedVC: BaseVC {
private lazy var seedReminderView: SeedReminderView = {
let result = SeedReminderView(hasContinueButton: false)
let title = "You're almost finished! 90%"
let attributedTitle = NSMutableAttributedString(string: title)
attributedTitle.addAttribute(.foregroundColor, value: Colors.accent, range: (title as NSString).range(of: "90%"))
result.title = attributedTitle
result.subtitle = "view_seed_reminder_subtitle_2".localized()
result.setProgress(0.9, animated: false)
ThemeManager.onThemeChange(observer: result) { [weak result] _, primaryColor in
let title = "You're almost finished! 90%"
let attributedTitle = NSMutableAttributedString(string: title)
attributedTitle.addAttribute(
.foregroundColor,
value: primaryColor.color,
range: (title as NSString).range(of: "90%")
)
result?.title = attributedTitle
}
return result
}()
private lazy var mnemonicLabel: UILabel = {
let result = UILabel()
result.font = Fonts.spaceMono(ofSize: Values.mediumFontSize)
result.textColor = Colors.accent
result.themeTextColor = .primary
result.textAlignment = .center
result.lineBreakMode = .byWordWrapping
result.numberOfLines = 0
@ -64,14 +72,14 @@ final class SeedVC: BaseVC {
// Set up navigation bar buttons
let closeButton = UIBarButtonItem(image: #imageLiteral(resourceName: "X"), style: .plain, target: self, action: #selector(close))
closeButton.tintColor = Colors.text
closeButton.themeTintColor = .textPrimary
navigationItem.leftBarButtonItem = closeButton
// Set up title label
let titleLabel = UILabel()
titleLabel.font = .boldSystemFont(ofSize: isIPhone5OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize)
titleLabel.text = "vc_seed_title_2".localized()
titleLabel.textColor = Colors.text
titleLabel.themeTextColor = .textPrimary
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.numberOfLines = 0
@ -79,7 +87,7 @@ final class SeedVC: BaseVC {
let explanationLabel = UILabel()
explanationLabel.font = .systemFont(ofSize: Values.smallFontSize)
explanationLabel.text = "vc_seed_explanation".localized()
explanationLabel.textColor = Colors.text
explanationLabel.themeTextColor = .textPrimary
explanationLabel.lineBreakMode = .byWordWrapping
explanationLabel.numberOfLines = 0
@ -94,15 +102,15 @@ final class SeedVC: BaseVC {
let mnemonicLabelContainer = UIView()
mnemonicLabelContainer.addSubview(mnemonicLabel)
mnemonicLabel.pin(to: mnemonicLabelContainer, withInset: isIPhone6OrSmaller ? Values.smallSpacing : Values.mediumSpacing)
mnemonicLabelContainer.themeBorderColor = .textPrimary
mnemonicLabelContainer.layer.cornerRadius = TextField.cornerRadius
mnemonicLabelContainer.layer.borderWidth = 1
mnemonicLabelContainer.layer.borderColor = Colors.text.cgColor
// Set up call to action label
let callToActionLabel = UILabel()
callToActionLabel.font = .systemFont(ofSize: isIPhone5OrSmaller ? Values.smallFontSize : Values.mediumFontSize)
callToActionLabel.text = "vc_seed_reveal_button_title".localized()
callToActionLabel.textColor = Colors.text.withAlphaComponent(Values.mediumOpacity)
callToActionLabel.themeTextColor = .textSecondary
callToActionLabel.textAlignment = .center
let callToActionLabelGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(revealMnemonic))
@ -179,14 +187,20 @@ final class SeedVC: BaseVC {
@objc private func revealMnemonic() {
UIView.transition(with: mnemonicLabel, duration: 0.25, options: .transitionCrossDissolve, animations: {
self.mnemonicLabel.text = self.mnemonic
self.mnemonicLabel.textColor = Colors.text
self.mnemonicLabel.themeTextColor = .textPrimary
}, completion: nil)
UIView.transition(with: seedReminderView.titleLabel, duration: 0.25, options: .transitionCrossDissolve, animations: {
let title = "Account Secured! 100%"
let attributedTitle = NSMutableAttributedString(string: title)
attributedTitle.addAttribute(.foregroundColor, value: Colors.accent, range: (title as NSString).range(of: "100%"))
self.seedReminderView.title = attributedTitle
ThemeManager.onThemeChange(observer: self.seedReminderView) { [weak self] _, primaryColor in
let title = "Account Secured! 100%"
let attributedTitle = NSMutableAttributedString(string: title)
attributedTitle.addAttribute(
.foregroundColor,
value: primaryColor.color,
range: (title as NSString).range(of: "100%")
)
self?.seedReminderView.title = attributedTitle
}
}, completion: nil)
UIView.transition(with: seedReminderView.subtitleLabel, duration: 1, options: .transitionCrossDissolve, animations: {

View File

@ -1,12 +1,13 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import AVFoundation
import GRDB
import SessionUIKit
import SessionMessagingKit
import SessionUtilitiesKit
final class JoinOpenGroupVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControllerDelegate, OWSQRScannerDelegate {
final class JoinOpenGroupVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControllerDelegate, QRScannerDelegate {
private let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
private var pages: [UIViewController] = []
private var isJoining = false
@ -136,7 +137,7 @@ final class JoinOpenGroupVC: BaseVC, UIPageViewControllerDataSource, UIPageViewC
dismiss(animated: true, completion: nil)
}
func controller(_ controller: OWSQRCodeScanningViewController, didDetectQRCodeWith string: String) {
func controller(_ controller: QRCodeScanningViewController, didDetectQRCodeWith string: String) {
joinOpenGroup(with: string)
}

View File

@ -38,7 +38,7 @@ class BlockedContactsViewController: BaseVC, UITableViewDelegate, UITableViewDat
private lazy var tableView: UITableView = {
let result: UITableView = UITableView()
result.translatesAutoresizingMaskIntoConstraints = false
result.backgroundColor = .clear
result.themeBackgroundColor = .clear
result.separatorStyle = .none
result.register(view: BlockedContactCell.self)
result.dataSource = self
@ -288,7 +288,7 @@ class BlockedContactsViewController: BaseVC, UITableViewDelegate, UITableViewDat
switch section.model {
case .loadMore:
let loadingIndicator: UIActivityIndicatorView = UIActivityIndicatorView(style: .medium)
loadingIndicator.tintColor = Colors.text
loadingIndicator.themeTintColor = .textPrimary
loadingIndicator.alpha = 0.5
loadingIndicator.startAnimating()

View File

@ -1,11 +1,12 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import AVFoundation
import Curve25519Kit
import SessionUIKit
import SessionUtilitiesKit
final class QRCodeVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControllerDelegate, OWSQRScannerDelegate {
final class QRCodeVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControllerDelegate, QRScannerDelegate {
private let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
private var pages: [UIViewController] = []
private var targetVCIndex: Int?
@ -127,7 +128,7 @@ final class QRCodeVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControl
dismiss(animated: true, completion: nil)
}
func controller(_ controller: OWSQRCodeScanningViewController, didDetectQRCodeWith string: String) {
func controller(_ controller: QRCodeScanningViewController, didDetectQRCodeWith string: String) {
let hexEncodedPublicKey = string
startNewPrivateChatIfPossible(with: hexEncodedPublicKey)
}
@ -200,12 +201,12 @@ private final class ViewMyQRCodeVC : UIViewController {
ThemeManager.onThemeChange(observer: qrCodeImageView) { theme, _ in
switch theme.interfaceStyle {
case .light:
qrCodeImageView.tintColor = theme.colors[.textPrimary]
qrCodeImageViewBackgroundView.backgroundColor = nil
qrCodeImageView.themeTintColorForced = .theme(theme, color: .textPrimary)
qrCodeImageViewBackgroundView.themeBackgroundColorForced = nil
default:
qrCodeImageView.tintColor = theme.colors[.backgroundPrimary]
qrCodeImageViewBackgroundView.backgroundColor = .white
qrCodeImageView.themeTintColorForced = .theme(theme, color: .backgroundPrimary)
qrCodeImageViewBackgroundView.themeBackgroundColorForced = .color(.white)
}
}

View File

@ -29,7 +29,7 @@ class SettingsTableViewController<NavItemId: Equatable, Section: SettingSection,
let result: UITableView = UITableView()
result.translatesAutoresizingMaskIntoConstraints = false
result.separatorStyle = .none
result.backgroundColor = .clear
result.themeBackgroundColor = .clear
result.showsVerticalScrollIndicator = false
result.showsHorizontalScrollIndicator = false
result.register(view: SettingsAvatarCell.self)

View File

@ -60,7 +60,7 @@ class PrimaryColorSelectionView: UIView {
private func setupUI(color: Theme.PrimaryColor) {
// Set the appropriate colours
selectionView.backgroundColor = color.color
selectionView.themeBackgroundColorForced = .primary(color)
// Add the UI
addSubview(backgroundButton)

View File

@ -80,10 +80,10 @@ class ThemeSelectionView: UIView {
self.themeBackgroundColor = .appearance_sectionBackground
// Set the appropriate colours
previewView.backgroundColor = theme.colors[.backgroundPrimary]
previewView.layer.borderColor = theme.colors[.borderSeparator]?.cgColor
previewIncomingMessageView.backgroundColor = theme.colors[.messageBubble_incomingBackground]
previewOutgoingMessageView.backgroundColor = theme.colors[.defaultPrimary]
previewView.themeBackgroundColorForced = .theme(theme, color: .backgroundPrimary)
previewView.themeBorderColorForced = .theme(theme, color: .borderSeparator)
previewIncomingMessageView.themeBackgroundColorForced = .theme(theme, color: .messageBubble_incomingBackground)
previewOutgoingMessageView.themeBackgroundColorForced = .theme(theme, color: .defaultPrimary)
selectionView.text = theme.title
// Add the UI

View File

@ -1,6 +1,7 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
import UIKit
import SessionUIKit
public protocol CaptionContainerViewDelegate: AnyObject {
func captionContainerViewDidUpdateText(_ captionContainerView: CaptionContainerView)
@ -100,8 +101,8 @@ private class CaptionView: UIView {
let textView = CaptionTextView()
textView.font = UIFont.ows_dynamicTypeBody
textView.textColor = Colors.text
textView.backgroundColor = .clear
textView.themeTextColor = .textPrimary
textView.themeBackgroundColor = .clear
textView.isEditable = false
textView.isSelectable = false

View File

@ -1,66 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
import Foundation
protocol DismissInputBarDelegate: class {
func dismissInputBarDidTapDismiss(_ dismissInputBar: DismissInputBar)
}
class DismissInputBar: UIToolbar {
weak var dismissDelegate: DismissInputBarDelegate?
override init(frame: CGRect) {
super.init(frame: frame)
let spacer = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
let dismissButton = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(didTapDone))
dismissButton.imageInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 40)
dismissButton.tintColor = UIColor.ows_systemPrimaryButton
self.items = [spacer, dismissButton]
self.isTranslucent = false
self.isOpaque = true
self.barTintColor = UIColor.lokiDarkestGray()
self.autoresizingMask = .flexibleHeight
self.translatesAutoresizingMaskIntoConstraints = false
}
required init?(coder aDecoder: NSCoder) {
notImplemented()
}
@objc
public func didTapDone() {
self.dismissDelegate?.dismissInputBarDidTapDismiss(self)
}
}
@objc
public class DismissableTextField: UITextField, DismissInputBarDelegate {
private let dismissBar: DismissInputBar
override init(frame: CGRect) {
self.dismissBar = DismissInputBar()
super.init(frame: frame)
self.inputAccessoryView = dismissBar
dismissBar.dismissDelegate = self
}
required public init?(coder aDecoder: NSCoder) {
notImplemented()
}
// MARK: DismissInputBarDelegate
func dismissInputBarDidTapDismiss(_ dismissInputBar: DismissInputBar) {
self.resignFirstResponder()
}
}

View File

@ -407,7 +407,7 @@ public final class FullConversationCell: UITableViewCell {
hasAtLeastOneReadReceipt: (cellViewModel.interactionHasAtLeastOneReadReceipt ?? false)
)
statusIndicatorView.image = stateInfo?.image
statusIndicatorView.themeTintColor = stateInfo?.tintColor
statusIndicatorView.themeTintColor = stateInfo?.themeTintColor
statusIndicatorView.isHidden = (
cellViewModel.interactionVariant != .standardOutgoing &&
cellViewModel.interactionState != .skipped
@ -456,7 +456,7 @@ public final class FullConversationCell: UITableViewCell {
}
else if cellViewModel.threadOnlyNotifyForMentions == true {
let imageAttachment = NSTextAttachment()
imageAttachment.image = UIImage(named: "NotifyMentions.png")?.asTintedImage(color: textColor)
imageAttachment.image = UIImage(named: "NotifyMentions.png")?.withTint(textColor)
imageAttachment.bounds = CGRect(x: 0, y: -2, width: Values.smallFontSize, height: Values.smallFontSize)
let imageString = NSAttributedString(attachment: imageAttachment)

View File

@ -25,7 +25,7 @@ public class LoadingViewController: UIViewController {
private var logoView: UIImageView = {
let result: UIImageView = UIImageView(image: #imageLiteral(resourceName: "SessionGreen64"))
result.contentMode = .scaleAspectFit
result.layer.shadowColor = Theme.PrimaryColor.green.color.cgColor
result.themeShadowColorForced = .primary(.green)
result.layer.shadowOffset = .zero
result.layer.shadowRadius = 3
result.layer.shadowOpacity = 0
@ -37,8 +37,8 @@ public class LoadingViewController: UIViewController {
let result: UIProgressView = UIProgressView(progressViewStyle: .bar)
result.clipsToBounds = true
result.progress = 0
result.tintColor = Theme.PrimaryColor.green.color
result.progressTintColor = Theme.classicDark.colors[.textPrimary]?.withAlphaComponent(0.1)
result.themeTintColorForced = .primary(.green)
result.themeProgressTintColorForced = .theme(.classicDark, color: .textPrimary, alpha: 0.1)
result.layer.cornerRadius = 6
return result
@ -48,7 +48,7 @@ public class LoadingViewController: UIViewController {
let result: UILabel = UILabel()
result.font = UIFont.systemFont(ofSize: Values.mediumFontSize)
result.text = "DATABASE_VIEW_OVERLAY_TITLE".localized()
result.textColor = Theme.classicDark.colors[.textPrimary]
result.themeTextColorForced = .theme(.classicDark, color: .textPrimary)
result.textAlignment = .center
result.numberOfLines = 0
result.lineBreakMode = .byWordWrapping
@ -60,7 +60,7 @@ public class LoadingViewController: UIViewController {
let result: UILabel = UILabel()
result.font = UIFont.systemFont(ofSize: Values.verySmallFontSize)
result.text = "DATABASE_VIEW_OVERLAY_SUBTITLE".localized()
result.textColor = Theme.classicDark.colors[.textPrimary]
result.themeTextColorForced = .theme(.classicDark, color: .textPrimary)
result.textAlignment = .center
result.numberOfLines = 0
result.lineBreakMode = .byWordWrapping
@ -84,7 +84,7 @@ public class LoadingViewController: UIViewController {
override public func loadView() {
self.view = UIView()
self.view.backgroundColor = Theme.classicDark.colors[.backgroundPrimary]
self.view.themeBackgroundColorForced = .theme(.classicDark, color: .backgroundPrimary)
self.view.addSubview(self.logoView)
self.view.addSubview(self.labelStack)

File diff suppressed because it is too large Load Diff

View File

@ -1,18 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
// This view can be used to safely fill a region of a table
// or collection view cell. These cells change the background
// colors of their subviews when selected. This can inadvertently
// change the color of filled subviews. This view will
// reject a new background once its background has been set.
@objc class NeverClearView: UIView {
override var backgroundColor: UIColor? {
didSet {
if backgroundColor?.cgColor.alpha == 0 {
backgroundColor = oldValue
}
}
}
}

View File

@ -33,7 +33,6 @@ NS_ASSUME_NONNULL_BEGIN
{
self.opaque = NO;
self.userInteractionEnabled = NO;
self.backgroundColor = [UIColor clearColor];
}
- (void)setFrame:(CGRect)frame

View File

@ -1,18 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSProgressView : UIView
@property (nonatomic) UIColor *color;
@property (nonatomic) CGFloat progress;
+ (CGSize)defaultSize;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,132 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "OWSProgressView.h"
#import <SessionUtilitiesKit/UIView+OWS.h>
#import <SessionUtilitiesKit/OWSMath.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSProgressView ()
@property (nonatomic) CAShapeLayer *borderLayer;
@property (nonatomic) CAShapeLayer *progressLayer;
@end
#pragma mark -
@implementation OWSProgressView
- (id)init
{
self = [super init];
if (self) {
[self initCommon];
}
return self;
}
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
[self initCommon];
}
return self;
}
- (void)initCommon
{
self.opaque = NO;
self.userInteractionEnabled = NO;
self.color = [UIColor whiteColor];
// Prevent the shape layer from animating changes.
[CATransaction begin];
[CATransaction setDisableActions:YES];
self.borderLayer = [CAShapeLayer new];
[self.layer addSublayer:self.borderLayer];
self.progressLayer = [CAShapeLayer new];
[self.layer addSublayer:self.progressLayer];
[CATransaction commit];
[self setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical];
[self setContentHuggingPriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisVertical];
}
- (void)layoutSubviews
{
[super layoutSubviews];
[self update];
}
- (void)setProgress:(CGFloat)progress
{
if (_progress != progress) {
_progress = progress;
[self update];
}
}
- (void)setColor:(UIColor *)color
{
if (![_color isEqual:color]) {
_color = color;
[self update];
}
}
- (void)update
{
// Prevent the shape layer from animating changes.
[CATransaction begin];
[CATransaction setDisableActions:YES];
CGFloat borderThickness = MAX(CGHairlineWidth(), self.bounds.size.height * 0.1f);
CGFloat cornerRadius = MIN(self.bounds.size.width, self.bounds.size.height) * 0.5f;
// Add the outer border.
UIBezierPath *borderPath = [UIBezierPath bezierPathWithRoundedRect:self.bounds cornerRadius:cornerRadius];
self.borderLayer.path = borderPath.CGPath;
self.borderLayer.strokeColor = self.color.CGColor;
self.borderLayer.lineWidth = borderThickness;
self.borderLayer.fillColor = [UIColor clearColor].CGColor;
// Add the inner progress.
CGRect progressRect = self.bounds;
progressRect.size.width = cornerRadius * 2;
CGFloat baseProgress = borderThickness * 2;
CGFloat minProgress = baseProgress;
CGFloat maxProgress = MAX(0, self.bounds.size.width - baseProgress);
progressRect.size.width = CGFloatLerp(minProgress, maxProgress, CGFloatClamp01(self.progress));
UIBezierPath *progressPath = [UIBezierPath bezierPathWithRoundedRect:progressRect cornerRadius:cornerRadius];
self.progressLayer.path = progressPath.CGPath;
self.progressLayer.fillColor = self.color.CGColor;
[CATransaction commit];
}
+ (CGSize)defaultSize
{
return CGSizeMake(150, 16);
}
- (CGSize)sizeThatFits:(CGSize)size
{
return OWSProgressView.defaultSize;
}
- (CGSize)intrinsicContentSize
{
return CGSizeMake(UIViewNoIntrinsicMetric, 16);
}
@end
NS_ASSUME_NONNULL_END

View File

@ -1,34 +0,0 @@
//
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
//
#import <AVFoundation/AVFoundation.h>
#import <SignalUtilitiesKit/OWSViewController.h>
#import <UIKit/UIKit.h>
#import <ZXingObjC/ZXingObjC.h>
NS_ASSUME_NONNULL_BEGIN
@class OWSQRCodeScanningViewController;
@protocol OWSQRScannerDelegate
@optional
- (void)controller:(OWSQRCodeScanningViewController *)controller didDetectQRCodeWithString:(NSString *)string;
- (void)controller:(OWSQRCodeScanningViewController *)controller didDetectQRCodeWithData:(NSData *)data;
@end
#pragma mark -
@interface OWSQRCodeScanningViewController
: OWSViewController <AVCaptureMetadataOutputObjectsDelegate, ZXCaptureDelegate>
@property (nonatomic, weak) UIViewController<OWSQRScannerDelegate> *scanDelegate;
- (void)startCapture;
@end
NS_ASSUME_NONNULL_END

View File

@ -1,162 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "OWSQRCodeScanningViewController.h"
#import "OWSBezierPathView.h"
#import "UIColor+OWS.h"
#import "UIView+OWS.h"
NS_ASSUME_NONNULL_BEGIN
@interface OWSQRCodeScanningViewController ()
@property (atomic) ZXCapture *capture;
@property (nonatomic) BOOL captureEnabled;
@property (nonatomic) UIView *maskingView;
@property (nonatomic) dispatch_queue_t captureQueue;
@end
#pragma mark -
@implementation OWSQRCodeScanningViewController
- (void)dealloc
{
[self.capture.layer removeFromSuperlayer];
}
- (instancetype)init
{
self = [super init];
if (!self) {
return self;
}
_captureEnabled = NO;
_captureQueue = dispatch_get_main_queue();
return self;
}
- (nullable instancetype)initWithCoder:(NSCoder *)aDecoder
{
self = [super initWithCoder:aDecoder];
if (!self) {
return self;
}
_captureEnabled = NO;
_captureQueue = dispatch_get_main_queue();
return self;
}
- (void)loadView
{
[super loadView];
OWSBezierPathView *maskingView = [OWSBezierPathView new];
self.maskingView = maskingView;
[maskingView setConfigureShapeLayerBlock:^(CAShapeLayer *layer, CGRect bounds) {
// Add a circular mask
UIBezierPath *path = [UIBezierPath bezierPathWithRect:bounds];
CGFloat margin = ScaleFromIPhone5To7Plus(24.f, 48.f);
CGFloat radius = MIN(bounds.size.width, bounds.size.height) * 0.5f - margin;
// Center the circle's bounding rectangle
CGRect circleRect = CGRectMake(
bounds.size.width * 0.5f - radius, bounds.size.height * 0.5f - radius, radius * 2.f, radius * 2.f);
UIBezierPath *circlePath = [UIBezierPath bezierPathWithRoundedRect:circleRect cornerRadius:16.f];
[path appendPath:circlePath];
[path setUsesEvenOddFillRule:YES];
layer.path = path.CGPath;
layer.fillRule = kCAFillRuleEvenOdd;
layer.fillColor = UIColor.lokiDarkestGray.CGColor;
layer.opacity = 0.32f;
}];
[self.view addSubview:maskingView];
[maskingView ows_autoPinToSuperviewEdges];
}
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if (self.captureEnabled) {
[self startCapture];
}
}
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
[self stopCapture];
}
- (void)viewWillLayoutSubviews
{
self.capture.layer.frame = self.view.bounds;
}
- (void)startCapture
{
self.captureEnabled = YES;
if (!self.capture) {
dispatch_async(self.captureQueue, ^{
self.capture = [[ZXCapture alloc] init];
self.capture.camera = self.capture.back;
self.capture.focusMode = AVCaptureFocusModeContinuousAutoFocus;
self.capture.delegate = self;
dispatch_async(dispatch_get_main_queue(), ^{
self.capture.layer.frame = self.view.bounds;
[self.view.layer addSublayer:self.capture.layer];
[self.view bringSubviewToFront:self.maskingView];
[self.capture start];
});
});
} else {
[self.capture start];
}
}
- (void)stopCapture
{
self.captureEnabled = NO;
dispatch_async(self.captureQueue, ^{
[self.capture stop];
});
}
- (void)captureResult:(ZXCapture *)capture result:(ZXResult *)result
{
if (!self.captureEnabled) {
return;
}
[self stopCapture];
// Vibrate
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate);
if (self.scanDelegate) {
if ([self.scanDelegate respondsToSelector:@selector(controller:didDetectQRCodeWithData:)]) {
OWSLogInfo(@"Scanned Data Code.");
ZXByteArray *byteArray = result.resultMetadata[@(kResultMetadataTypeByteSegments)][0];
NSData *decodedData = [NSData dataWithBytes:byteArray.array length:byteArray.length];
[self.scanDelegate controller:self didDetectQRCodeWithData:decodedData];
}
if ([self.scanDelegate respondsToSelector:@selector(controller:didDetectQRCodeWithString:)]) {
OWSLogInfo(@"Scanned String Code.");
[self.scanDelegate controller:self didDetectQRCodeWithString:result.text];
}
}
}
@end
NS_ASSUME_NONNULL_END

View File

@ -0,0 +1,150 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import AVFoundation
import ZXingObjC
import SessionUIKit
protocol QRScannerDelegate: AnyObject {
func controller(_ controller: QRCodeScanningViewController, didDetectQRCodeWith string: String)
}
class QRCodeScanningViewController: UIViewController, AVCaptureMetadataOutputObjectsDelegate, ZXCaptureDelegate {
public weak var scanDelegate: QRScannerDelegate?
private let captureQueue: DispatchQueue = DispatchQueue.global(qos: .default)
private var capture: ZXCapture?
private var captureEnabled: Bool = false
// MARK: - Initialization
deinit {
self.capture?.layer.removeFromSuperlayer()
}
// MARK: - Components
private let maskingView: UIView = {
let result: OWSBezierPathView = OWSBezierPathView()
result.configureShapeLayerBlock = { layer, bounds in
// Add a circular mask
let path: UIBezierPath = UIBezierPath(rect: bounds)
let margin: CGFloat = ScaleFromIPhone5To7Plus(24, 48)
let radius: CGFloat = ((min(bounds.size.width, bounds.size.height) * 0.5) - margin)
// Center the circle's bounding rectangle
let circleRect: CGRect = CGRect(
x: ((bounds.size.width * 0.5) - radius),
y: ((bounds.size.height * 0.5) - radius),
width: (radius * 2),
height: (radius * 2)
)
let circlePath: UIBezierPath = UIBezierPath.init(
roundedRect: circleRect,
cornerRadius: 16
)
path.append(circlePath)
path.usesEvenOddFillRule = true
layer.path = path.cgPath
layer.fillRule = .evenOdd
layer.themeFillColor = .black
layer.opacity = 0.32
}
return result
}()
// MARK: - Lifecycle
override func loadView() {
super.loadView()
self.view.addSubview(maskingView)
maskingView.pin(to: self.view)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
if captureEnabled {
self.startCapture()
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
self.stopCapture()
}
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
// Note: When accessing 'capture.layer' if the setup hasn't been completed it
// will result in a layout being triggered which creates an infinite loop, this
// check prevents that case
if let capture: ZXCapture = self.capture {
capture.layer.frame = self.view.bounds
}
}
// MARK: - Functions
public func startCapture() {
self.captureEnabled = true
// Note: The simulator doesn't support video but if we do try to start an
// AVCaptureSession it seems to hang on that particular thread indefinitely
// this will prevent us from trying to start a session on the simulator
#if targetEnvironment(simulator)
#else
if self.capture == nil {
self.captureQueue.async { [weak self] in
let capture: ZXCapture = ZXCapture()
capture.camera = capture.back()
capture.focusMode = .autoFocus
capture.delegate = self
capture.start()
// Note: When accessing the 'layer' for the first time it will create
// an instance of 'AVCaptureVideoPreviewLayer', this can hang a little
// so we do this on the background thread first
if capture.layer != nil {}
DispatchQueue.main.async {
capture.layer.frame = (self?.view.bounds ?? .zero)
self?.view.layer.addSublayer(capture.layer)
if let maskingView: UIView = self?.maskingView {
self?.view.bringSubviewToFront(maskingView)
}
self?.capture = capture
}
}
}
else {
self.capture?.start()
}
#endif
}
private func stopCapture() {
self.captureEnabled = false
self.captureQueue.async { [weak self] in
self?.capture?.stop()
}
}
internal func captureResult(_ capture: ZXCapture, result: ZXResult) {
guard self.captureEnabled else { return }
self.stopCapture()
// Vibrate
AudioServicesPlaySystemSound(kSystemSoundID_Vibrate)
self.scanDelegate?.controller(self, didDetectQRCodeWith: result.text)
}
}

View File

@ -1,121 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
import Foundation
import SessionUIKit
class ReminderView: UIView {
let label = UILabel()
typealias Action = () -> Void
var tapAction: Action?
var text: String? {
get {
return label.text
}
set(newText) {
label.text = newText
}
}
enum ReminderViewMode {
// Nags are urgent interactive prompts, bidding for the user's attention.
case nag
// Explanations are not interactive or urgent.
case explanation
}
let mode: ReminderViewMode
@available(*, unavailable, message:"use other constructor instead.")
required init?(coder aDecoder: NSCoder) {
notImplemented()
}
@available(*, unavailable, message:"use other constructor instead.")
override init(frame: CGRect) {
notImplemented()
}
private init(mode: ReminderViewMode,
text: String, tapAction: Action?) {
self.mode = mode
self.tapAction = tapAction
super.init(frame: .zero)
self.text = text
setupSubviews()
}
@objc public class func nag(text: String, tapAction: Action?) -> ReminderView {
return ReminderView(mode: .nag, text: text, tapAction: tapAction)
}
@objc public class func explanation(text: String) -> ReminderView {
return ReminderView(mode: .explanation, text: text, tapAction: nil)
}
func setupSubviews() {
let textColor: UIColor
let iconColor: UIColor
switch mode {
case .nag:
self.backgroundColor = UIColor.ows_reminderYellow
textColor = UIColor.ows_gray90
iconColor = UIColor.ows_gray60
case .explanation:
// TODO: Theme, review with design.
self.backgroundColor = Colors.unimportant
textColor = Colors.text
iconColor = Colors.separator
}
self.clipsToBounds = true
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap(gestureRecognizer:)))
self.addGestureRecognizer(tapGesture)
let container = UIStackView()
container.axis = .horizontal
container.alignment = .center
container.isLayoutMarginsRelativeArrangement = true
self.addSubview(container)
container.layoutMargins = UIEdgeInsets(top: 12, left: 16, bottom: 12, right: 16)
container.ows_autoPinToSuperviewEdges()
// Label
label.font = UIFont.ows_dynamicTypeSubheadline
container.addArrangedSubview(label)
label.textColor = textColor
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
// Show the disclosure indicator if this reminder has a tap action.
if tapAction != nil {
// Icon
let iconName = (CurrentAppContext().isRTL ? "system_disclosure_indicator_rtl" : "system_disclosure_indicator")
guard let iconImage = UIImage(named: iconName) else {
owsFailDebug("missing icon.")
return
}
let iconView = UIImageView(image: iconImage.withRenderingMode(.alwaysTemplate))
iconView.contentMode = .scaleAspectFit
iconView.tintColor = iconColor
iconView.autoSetDimension(.width, toSize: 13)
container.addArrangedSubview(iconView)
}
}
@objc func handleTap(gestureRecognizer: UIGestureRecognizer) {
guard gestureRecognizer.state == .recognized else {
return
}
tapAction?()
}
}

View File

@ -1,14 +1,18 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
final class ScanQRCodeWrapperVC : BaseVC {
var delegate: (UIViewController & OWSQRScannerDelegate)? = nil
import UIKit
import SessionUIKit
final class ScanQRCodeWrapperVC: BaseVC {
var delegate: (UIViewController & QRScannerDelegate)? = nil
var isPresentedModally = false
private let message: String
private let scanQRCodeVC = OWSQRCodeScanningViewController()
private let scanQRCodeVC = QRCodeScanningViewController()
// MARK: Settings
override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait }
// MARK: Lifecycle
// MARK: - Lifecycle
init(message: String) {
self.message = message
super.init(nibName: nil, bundle: nil)
@ -24,6 +28,9 @@ final class ScanQRCodeWrapperVC : BaseVC {
override func viewDidLoad() {
super.viewDidLoad()
title = "Scan QR Code"
// Set up navigation bar if needed
if isPresentedModally {
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(close))
@ -37,6 +44,7 @@ final class ScanQRCodeWrapperVC : BaseVC {
scanQRCodeVCView.pin(.trailing, to: .trailing, of: view)
scanQRCodeVCView.autoPinEdge(.top, to: .top, of: view)
scanQRCodeVCView.autoPinToSquareAspectRatio()
// Set up bottom view
let bottomView = UIView()
view.addSubview(bottomView)
@ -44,37 +52,35 @@ final class ScanQRCodeWrapperVC : BaseVC {
bottomView.pin(.leading, to: .leading, of: view)
bottomView.pin(.trailing, to: .trailing, of: view)
bottomView.pin(.bottom, to: .bottom, of: view)
// Set up explanation label
let explanationLabel = UILabel()
explanationLabel.text = message
explanationLabel.textColor = Colors.text
explanationLabel.themeTextColor = .textPrimary
explanationLabel.font = .systemFont(ofSize: Values.smallFontSize)
explanationLabel.numberOfLines = 0
explanationLabel.lineBreakMode = .byWordWrapping
explanationLabel.textAlignment = .center
explanationLabel.lineBreakMode = .byWordWrapping
explanationLabel.numberOfLines = 0
bottomView.addSubview(explanationLabel)
explanationLabel.autoPinWidthToSuperview(withMargin: 32)
explanationLabel.autoPinHeightToSuperview(withMargin: 32)
// Title
title = "Scan QR Code"
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
UIDevice.current.ows_setOrientation(.portrait)
DispatchQueue.main.async { [weak self] in
self?.scanQRCodeVC.startCapture()
}
self.scanQRCodeVC.startCapture()
}
// MARK: Interaction
// MARK: - Interaction
@objc private func close() {
presentingViewController?.dismiss(animated: true, completion: nil)
}
public func startCapture() {
DispatchQueue.main.async { [weak self] in
self?.scanQRCodeVC.startCapture()
}
self.scanQRCodeVC.startCapture()
}
}

View File

@ -39,7 +39,7 @@ public class ConfirmationModal: Modal {
attributedExplanation: NSAttributedString? = nil,
stateToShow: State = .always,
confirmTitle: String? = nil,
confirmStyle: ThemeValue = .textPrimary,
confirmStyle: ThemeValue = .alert_text,
cancelTitle: String = "TXT_CANCEL_TITLE".localized(),
cancelStyle: ThemeValue = .danger,
dismissOnConfirm: Bool = true,
@ -115,7 +115,7 @@ public class ConfirmationModal: Modal {
private lazy var titleLabel: UILabel = {
let result: UILabel = UILabel()
result.font = .boldSystemFont(ofSize: Values.mediumFontSize)
result.themeTextColor = .textPrimary
result.themeTextColor = .alert_text
result.textAlignment = .center
result.lineBreakMode = .byWordWrapping
result.numberOfLines = 0
@ -126,7 +126,7 @@ public class ConfirmationModal: Modal {
private lazy var explanationLabel: UILabel = {
let result: UILabel = UILabel()
result.font = .systemFont(ofSize: Values.smallFontSize)
result.themeTextColor = .textPrimary
result.themeTextColor = .alert_text
result.textAlignment = .center
result.lineBreakMode = .byWordWrapping
result.numberOfLines = 0

View File

@ -58,6 +58,13 @@ public class Modal: BaseVC, UIGestureRecognizerDelegate {
self.afterClosed = afterClosed
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 = self.view
self.popoverPresentationController?.sourceRect = self.view.bounds
}
}
required init?(coder: NSCoder) {

View File

@ -1,65 +0,0 @@
class Sheet : BaseVC {
private(set) var bottomConstraint: NSLayoutConstraint!
// MARK: Settings
let overshoot: CGFloat = 40
class var isDismissable: Bool { true }
// MARK: Components
lazy var contentView: UIView = {
let result = UIView()
result.backgroundColor = Colors.modalBackground
result.layer.cornerRadius = 24
result.layer.masksToBounds = false
result.layer.borderColor = isLightMode ? UIColor.white.cgColor : Colors.modalBorder.cgColor
result.layer.borderWidth = 1
result.layer.shadowColor = UIColor.black.cgColor
result.layer.shadowRadius = isLightMode ? 2 : 8
result.layer.shadowOpacity = isLightMode ? 0.1 : 0.64
return result
}()
// MARK: Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
let alpha = isLightMode ? CGFloat(0.1) : Values.highOpacity
view.backgroundColor = UIColor(hex: 0x000000).withAlphaComponent(alpha)
if type(of: self).isDismissable {
let swipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(close))
swipeGestureRecognizer.direction = .down
view.addGestureRecognizer(swipeGestureRecognizer)
}
setUpViewHierarchy()
}
private func setUpViewHierarchy() {
view.addSubview(contentView)
contentView.pin(.leading, to: .leading, of: view, withInset: -1)
contentView.pin(.trailing, to: .trailing, of: view, withInset: 1)
bottomConstraint = contentView.pin(.bottom, to: .bottom, of: view, withInset: overshoot)
populateContentView()
}
/// To be overridden by subclasses.
func populateContentView() {
preconditionFailure("populateContentView() is abstract and must be overridden.")
}
// MARK: Interaction
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
let touch = touches.first!
let location = touch.location(in: view)
if contentView.frame.contains(location) {
super.touchesBegan(touches, with: event)
} else {
if type(of: self).isDismissable {
close()
}
}
}
@objc func close() {
dismiss(animated: true, completion: nil)
}
}

View File

@ -7,8 +7,6 @@
#import "Session-Swift.h"
#import <MobileCoreServices/UTCoreTypes.h>
#import <SignalUtilitiesKit/UIUtil.h>
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
NS_ASSUME_NONNULL_BEGIN

View File

@ -21,7 +21,7 @@ import UIKit
owsFailDebug("Missing root view controller.")
return nil
}
return viewController.findFrontmostViewController(ignoringAlerts)
return viewController.findFrontmostViewController(ignoringAlerts: ignoringAlerts)
}
func openSystemSettings() {

View File

@ -1,6 +1,7 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import SessionUIKit
extension UINavigationBar {
func generateSnapshot(in coordinateSpace: UICoordinateSpace) -> (UIView, CGRect)? {
@ -31,7 +32,7 @@ extension UINavigationBar {
height: frame.maxY
)
)
snapshotView.backgroundColor = backgroundColor
snapshotView.themeBackgroundColorForced = self.themeBackgroundColorForced
let imageView: UIImageView = UIImageView(image: image)
imageView.frame = frame

View File

@ -1,48 +0,0 @@
extension UIView {
struct CircularGlowConfiguration {
let size: CGFloat
let color: UIColor
let isAnimated: Bool
let animationDuration: TimeInterval
let offset: CGSize
let opacity: Float
let radius: CGFloat
init(size: CGFloat, color: UIColor, isAnimated: Bool = false, animationDuration: TimeInterval = 0.25, offset: CGSize = CGSize(width: 0, height: 0.8), opacity: Float = isLightMode ? 0.4 : 1, radius: CGFloat) {
self.size = size
self.color = color
self.isAnimated = isAnimated
self.animationDuration = animationDuration
self.offset = offset
self.opacity = opacity
self.radius = radius
}
}
func setCircularGlow(with configuration: CircularGlowConfiguration) {
let newSize = configuration.size
let newPath = UIBezierPath(ovalIn: CGRect(origin: CGPoint.zero, size: CGSize(width: newSize, height: newSize))).cgPath
if configuration.isAnimated {
let pathAnimation = CABasicAnimation(keyPath: "shadowPath")
pathAnimation.fromValue = layer.shadowPath
pathAnimation.toValue = newPath
pathAnimation.duration = configuration.animationDuration
layer.add(pathAnimation, forKey: pathAnimation.keyPath)
}
layer.shadowPath = newPath
let newColor = configuration.color.cgColor
if configuration.isAnimated {
let colorAnimation = CABasicAnimation(keyPath: "shadowColor")
colorAnimation.fromValue = layer.shadowColor
colorAnimation.toValue = newColor
colorAnimation.duration = configuration.animationDuration
layer.add(colorAnimation, forKey: colorAnimation.keyPath)
}
layer.shadowColor = newColor
layer.shadowOffset = configuration.offset
layer.shadowOpacity = configuration.opacity
layer.shadowRadius = configuration.radius
}
}

View File

@ -7,7 +7,6 @@
#import <AVFoundation/AVFoundation.h>
#import <Photos/Photos.h>
#import <SignalCoreKit/Threading.h>
#import <SignalUtilitiesKit/UIUtil.h>
NS_ASSUME_NONNULL_BEGIN

View File

@ -65,7 +65,7 @@ public struct RecipientState: Codable, Equatable, FetchableRecord, PersistableRe
}
}
public func statusIconInfo(variant: Interaction.Variant, hasAtLeastOneReadReceipt: Bool) -> (image: UIImage?, tintColor: ThemeValue) {
public func statusIconInfo(variant: Interaction.Variant, hasAtLeastOneReadReceipt: Bool) -> (image: UIImage?, themeTintColor: ThemeValue) {
guard variant == .standardOutgoing else { return (nil, .textPrimary) }
switch (self, hasAtLeastOneReadReceipt) {

View File

@ -6,8 +6,6 @@
NS_ASSUME_NONNULL_BEGIN
extern NSString *const OWSWindowManagerCallDidChangeNotification;
extern NSString *const IsScreenBlockActiveDidChangeNotification;
// This VC can become first responder
@ -32,27 +30,10 @@ extern const UIWindowLevel UIWindowLevel_Background;
- (void)setupWithRootWindow:(UIWindow *)rootWindow screenBlockingWindow:(UIWindow *)screenBlockingWindow;
@property (nonatomic, readonly) UIWindow *rootWindow;
@property (nonatomic, readonly) UIWindow *menuActionsWindow;
@property (nonatomic) BOOL isScreenBlockActive;
- (BOOL)isAppWindow:(UIWindow *)window;
#pragma mark - Message Actions
@property (nonatomic, readonly) BOOL isPresentingMenuActions;
- (void)showMenuActionsWindow:(UIViewController *)menuActionsViewController;
- (void)hideMenuActionsWindow;
#pragma mark - Calls
@property (nonatomic, readonly) BOOL shouldShowCallView;
- (void)startCall:(UIViewController *)callViewController;
- (void)endCall:(UIViewController *)callViewController;
- (void)leaveCallView;
- (BOOL)hasCall;
@end
NS_ASSUME_NONNULL_END

View File

@ -8,31 +8,11 @@
NS_ASSUME_NONNULL_BEGIN
NSString *const OWSWindowManagerCallDidChangeNotification = @"OWSWindowManagerCallDidChangeNotification";
NSString *const IsScreenBlockActiveDidChangeNotification = @"IsScreenBlockActiveDidChangeNotification";
const CGFloat OWSWindowManagerCallBannerHeight(void)
{
return CurrentAppContext().statusBarHeight + 20;
}
// Behind everything, especially the root window.
const UIWindowLevel UIWindowLevel_Background = -1.f;
const UIWindowLevel UIWindowLevel_ReturnToCall(void);
const UIWindowLevel UIWindowLevel_ReturnToCall(void)
{
return UIWindowLevelStatusBar - 1;
}
// In front of the root window, behind the screen blocking window.
const UIWindowLevel UIWindowLevel_CallView(void);
const UIWindowLevel UIWindowLevel_CallView(void)
{
return UIWindowLevelNormal + 1.f;
}
// In front of the status bar and CallView
const UIWindowLevel UIWindowLevel_ScreenBlocking(void);
const UIWindowLevel UIWindowLevel_ScreenBlocking(void)
@ -40,36 +20,6 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void)
return UIWindowLevelStatusBar + 2.f;
}
// In front of everything
const UIWindowLevel UIWindowLevel_MessageActions(void);
const UIWindowLevel UIWindowLevel_MessageActions(void)
{
// Note: To cover the keyboard, this is higher than the ScreenBlocking level,
// but this window is hidden when screen protection is shown.
return CGFLOAT_MAX - 100;
}
#pragma mark -
@interface MessageActionsWindow : UIWindow
@end
#pragma mark -
@implementation MessageActionsWindow
- (UIWindowLevel)windowLevel
{
// As of iOS11, setWindowLevel clamps the value below
// the height of the keyboard window.
// Because we want to display above the keyboard, we hardcode
// the `windowLevel` getter.
return UIWindowLevel_MessageActions();
}
@end
#pragma mark -
@implementation OWSWindowRootViewController
@ -114,22 +64,10 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
// UIWindowLevelNormal
@property (nonatomic) UIWindow *rootWindow;
// UIWindowLevel_CallView
@property (nonatomic) UIWindow *callViewWindow;
@property (nonatomic) UINavigationController *callNavigationController;
// UIWindowLevel_MessageActions
@property (nonatomic) UIWindow *menuActionsWindow;
@property (nonatomic, nullable) UIViewController *menuActionsViewController;
// UIWindowLevel_Background if inactive,
// UIWindowLevel_ScreenBlocking() if active.
@property (nonatomic) UIWindow *screenBlockingWindow;
@property (nonatomic) BOOL shouldShowCallView;
@property (nonatomic, nullable) UIViewController *callViewController;
@end
#pragma mark -
@ -156,10 +94,7 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
{
self.rootWindow = rootWindow;
self.screenBlockingWindow = screenBlockingWindow;
self.callViewWindow = [self createCallViewWindow:rootWindow];
self.menuActionsWindow = [self createMenuActionsWindowWithRoowWindow:rootWindow];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didChangeStatusBarFrame:)
name:UIApplicationDidChangeStatusBarFrameNotification
@ -175,47 +110,10 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
- (void)didChangeStatusBarFrame:(NSNotification *)notification
{
}
- (void)applicationWillResignActive:(NSNotification *)notification
{
[self hideMenuActionsWindow];
}
- (UIWindow *)createMenuActionsWindowWithRoowWindow:(UIWindow *)rootWindow
{
UIWindow *window = [[MessageActionsWindow alloc] initWithFrame:rootWindow.bounds];
window.hidden = YES;
window.backgroundColor = UIColor.clearColor;
return window;
}
- (UIWindow *)createCallViewWindow:(UIWindow *)rootWindow
{
UIWindow *window = [[UIWindow alloc] initWithFrame:rootWindow.bounds];
window.hidden = YES;
window.windowLevel = UIWindowLevel_CallView();
window.opaque = YES;
// TODO: What's the right color to use here?
window.backgroundColor = [UIColor blackColor];
UIViewController *viewController = [OWSWindowRootViewController new];
viewController.view.backgroundColor = [UIColor blackColor];
// NOTE: Do not use OWSNavigationController for call window.
// It adjusts the size of the navigation bar to reflect the
// call window. We don't want those adjustments made within
// the call window itself.
OWSWindowRootNavigationViewController *navigationController =
[[OWSWindowRootNavigationViewController alloc] initWithRootViewController:viewController];
navigationController.navigationBarHidden = YES;
self.callNavigationController = navigationController;
window.rootViewController = navigationController;
return window;
}
- (void)setIsScreenBlockActive:(BOOL)isScreenBlockActive
@ -231,92 +129,7 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
- (BOOL)isAppWindow:(UIWindow *)window
{
return (window == self.rootWindow || window == self.callViewWindow
|| window == self.menuActionsWindow || window == self.screenBlockingWindow);
}
#pragma mark - Message Actions
- (BOOL)isPresentingMenuActions
{
return self.menuActionsViewController != nil;
}
- (void)showMenuActionsWindow:(UIViewController *)menuActionsViewController
{
self.menuActionsViewController = menuActionsViewController;
self.menuActionsWindow.rootViewController = menuActionsViewController;
[self ensureWindowState];
}
- (void)hideMenuActionsWindow
{
self.menuActionsWindow.rootViewController = nil;
self.menuActionsViewController = nil;
[self ensureWindowState];
}
#pragma mark - Calls
- (void)setCallViewController:(nullable UIViewController *)callViewController
{
if (callViewController == _callViewController) {
return;
}
_callViewController = callViewController;
[NSNotificationCenter.defaultCenter postNotificationName:OWSWindowManagerCallDidChangeNotification object:nil];
}
- (void)startCall:(UIViewController *)callViewController
{
self.callViewController = callViewController;
// Attach callViewController to window.
[self.callNavigationController popToRootViewControllerAnimated:NO];
[self.callNavigationController pushViewController:callViewController animated:NO];
self.shouldShowCallView = YES;
// CallViewController only supports portrait, but if we're _already_ landscape it won't
// automatically switch.
[UIDevice.currentDevice ows_setOrientation:UIInterfaceOrientationPortrait];
[self ensureWindowState];
}
- (void)endCall:(UIViewController *)callViewController
{
if (self.callViewController != callViewController) {
return;
}
// Dettach callViewController from window.
[self.callNavigationController popToRootViewControllerAnimated:NO];
self.callViewController = nil;
self.shouldShowCallView = NO;
[self ensureWindowState];
}
- (void)leaveCallView
{
self.shouldShowCallView = NO;
[self ensureWindowState];
}
- (void)showCallView
{
self.shouldShowCallView = YES;
[self ensureWindowState];
}
- (BOOL)hasCall
{
return self.callViewController != nil;
return (window == self.rootWindow || window == self.screenBlockingWindow);
}
#pragma mark - Window State
@ -332,30 +145,13 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
// Show Screen Block.
[self ensureRootWindowHidden];
[self ensureCallViewWindowHidden];
[self ensureMessageActionsWindowHidden];
[self ensureScreenBlockWindowShown];
} else if (self.callViewController && self.shouldShowCallView) {
// Show Call View.
[self ensureRootWindowHidden];
[self ensureCallViewWindowShown];
[self ensureMessageActionsWindowHidden];
[self ensureScreenBlockWindowHidden];
} else {
}
else {
// Show Root Window
[self ensureRootWindowShown];
[self ensureCallViewWindowHidden];
[self ensureScreenBlockWindowHidden];
if (self.menuActionsViewController) {
// Add "Message Actions" action sheet
[self ensureMessageActionsWindowShown];
} else {
[self ensureMessageActionsWindowHidden];
}
}
}
@ -374,27 +170,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
self.rootWindow.hidden = YES;
}
- (void)ensureCallViewWindowShown
{
[self.callViewWindow makeKeyAndVisible];
}
- (void)ensureCallViewWindowHidden
{
self.callViewWindow.hidden = YES;
}
- (void)ensureMessageActionsWindowShown
{
// Do not make key, we want the keyboard to stay popped.
self.menuActionsWindow.hidden = NO;
}
- (void)ensureMessageActionsWindowHidden
{
self.menuActionsWindow.hidden = YES;
}
- (void)ensureScreenBlockWindowShown
{
self.screenBlockingWindow.windowLevel = UIWindowLevel_ScreenBlocking();

View File

@ -62,20 +62,20 @@ final class SAEScreenLockViewController: ScreenLockViewController {
ThemeManager.onThemeChange(observer: self.unlockButton) { [weak self] theme, _ in
switch theme.interfaceStyle {
case .light:
self?.unlockButton.setTitleColor(theme.colors[.textPrimary], for: .normal)
self?.unlockButton.setBackgroundImage(
theme.colors[.textPrimary]?.withAlphaComponent(0.3).toImage(),
self?.unlockButton.setThemeTitleColorForced(.theme(theme, color: .textPrimary), for: .normal)
self?.unlockButton.setThemeBackgroundColorForced(
.theme(theme, color: .textPrimary),
for: .highlighted
)
self?.unlockButton.layer.borderColor = theme.colors[.textPrimary]?.cgColor
self?.unlockButton.themeBorderColorForced = .theme(theme, color: .textPrimary)
default:
self?.unlockButton.setTitleColor(Theme.PrimaryColor.green.color, for: .normal)
self?.unlockButton.setBackgroundImage(
Theme.PrimaryColor.green.color.withAlphaComponent(0.3).toImage(),
self?.unlockButton.setThemeTitleColorForced(.primary(.green), for: .normal)
self?.unlockButton.setThemeBackgroundColorForced(
.primary(.green, alpha: 0.3),
for: .highlighted
)
self?.unlockButton.layer.borderColor = Theme.PrimaryColor.green.color.cgColor
self?.unlockButton.themeBorderColorForced = .primary(.green)
}
}
}

View File

@ -139,7 +139,7 @@ final class ShareAppExtensionContext: NSObject, AppContext {
}
func frontmostViewController() -> UIViewController? {
return rootViewController.findFrontmostViewController(true)
return rootViewController.findFrontmostViewController(ignoringAlerts: true)
}
func appDocumentDirectoryPath() -> String {

View File

@ -25,7 +25,7 @@ class NotificationContentViewModelSpec: QuickSpec {
SNUtilitiesKit.migrations(),
SNSnodeKit.migrations(),
SNMessagingKit.migrations(),
SUIKit.migrations()
SNUIKit.migrations()
]
)
viewModel = NotificationContentViewModel(storage: mockStorage)

View File

@ -3,13 +3,13 @@
import Foundation
import SessionUtilitiesKit
public enum SUIKit {
public enum SNUIKit {
public static func migrations() -> TargetMigrations {
return TargetMigrations(
identifier: .uiKit,
migrations: [
// Want to ensure the initial DB stuff has been completed before doing any
// SUIKit migrations
// SNUIKit migrations
[], // Initial DB Creation
[], // YDB to GRDB Migration
[], // YDB Removal

View File

@ -82,7 +82,10 @@ public enum ThemeManager {
// Note: We have to trigger this directly or the 'TraitObservingWindow' won't actually
// trigger the trait change if the app launched with this setting switched off
applyWindowStyling()
// Note: We need to set this to 'unspecified' to force the UI to properly update as the
// 'TraitObservingWindow' won't actually trigger the trait change otherwise
mainWindow?.overrideUserInterfaceStyle = .unspecified
}
}
@ -203,8 +206,6 @@ public enum ThemeManager {
public static func applyWindowStyling() {
mainWindow?.overrideUserInterfaceStyle = {
guard !ThemeManager.matchSystemNightModeSetting else { return .unspecified }
switch ThemeManager.currentTheme.interfaceStyle {
case .light: return .light
case .dark, .unspecified: return .dark

View File

@ -74,6 +74,7 @@ internal enum Theme_ClassicDark: ThemeColors {
.appearance_buttonHighlight: .classicDark3,
// Alert
.alert_text: .classicDark6,
.alert_background: .classicDark1,
.alert_buttonBackground: .classicDark1,
.alert_buttonHighlight: .classicDark3,
@ -96,6 +97,7 @@ internal enum Theme_ClassicDark: ThemeColors {
// ContextMenu
.contextMenu_background: .classicDark1,
.contextMenu_highlight: .primary,
.contextMenu_text: .classicDark6,
.contextMenu_textHighlight: .classicDark0,
// Call
@ -104,6 +106,6 @@ internal enum Theme_ClassicDark: ThemeColors {
// Reactions
.reactions_contextBackground: .classicDark2,
.reactions_contextMoreBackground: .classicDark3
.reactions_contextMoreBackground: .classicDark1
]
}

View File

@ -74,6 +74,7 @@ internal enum Theme_ClassicLight: ThemeColors {
.appearance_buttonHighlight: .classicLight4,
// Alert
.alert_text: .classicLight0,
.alert_background: .classicLight6,
.alert_buttonBackground: .classicLight6,
.alert_buttonHighlight: .classicLight4,
@ -96,6 +97,7 @@ internal enum Theme_ClassicLight: ThemeColors {
// ContextMenu
.contextMenu_background: .classicLight6,
.contextMenu_highlight: .primary,
.contextMenu_text: .classicLight0,
.contextMenu_textHighlight: .classicLight0,
// Call

View File

@ -75,13 +75,14 @@ internal extension UIColor {
static let oceanDark5: UIColor = #colorLiteral(red: 0.6509803922, green: 0.662745098, blue: 0.8078431373, alpha: 1) // #A6A9CE
static let oceanDark6: UIColor = #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1) // #FFFFFF
static let oceanLight0: UIColor = #colorLiteral(red: 0.09803921569, green: 0.2039215686, blue: 0.3647058824, alpha: 1) // #19345D
static let oceanLight1: UIColor = #colorLiteral(red: 0.4156862745, green: 0.431372549, blue: 0.5647058824, alpha: 1) // #6A6E90
static let oceanLight2: UIColor = #colorLiteral(red: 0.3607843137, green: 0.6666666667, blue: 0.8, alpha: 1) // #5CAACC
static let oceanLight3: UIColor = #colorLiteral(red: 0.7019607843, green: 0.9294117647, blue: 0.9490196078, alpha: 1) // #B3EDF2
static let oceanLight4: UIColor = #colorLiteral(red: 0.9058823529, green: 0.9529411765, blue: 0.9568627451, alpha: 1) // #E7F3F4
static let oceanLight5: UIColor = #colorLiteral(red: 0.9254901961, green: 0.9803921569, blue: 0.9843137255, alpha: 1) // #ECFAFB
static let oceanLight6: UIColor = #colorLiteral(red: 0.9882352941, green: 1, blue: 1, alpha: 1) // #FCFFFF
static let oceanLight0: UIColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) // #000000
static let oceanLight1: UIColor = #colorLiteral(red: 0.09803921569, green: 0.2039215686, blue: 0.3647058824, alpha: 1) // #19345D
static let oceanLight2: UIColor = #colorLiteral(red: 0.4156862745, green: 0.431372549, blue: 0.5647058824, alpha: 1) // #6A6E90
static let oceanLight3: UIColor = #colorLiteral(red: 0.3607843137, green: 0.6666666667, blue: 0.8, alpha: 1) // #5CAACC
static let oceanLight4: UIColor = #colorLiteral(red: 0.7019607843, green: 0.9294117647, blue: 0.9490196078, alpha: 1) // #B3EDF2
static let oceanLight5: UIColor = #colorLiteral(red: 0.9058823529, green: 0.9529411765, blue: 0.9568627451, alpha: 1) // #E7F3F4
static let oceanLight6: UIColor = #colorLiteral(red: 0.9254901961, green: 0.9803921569, blue: 0.9843137255, alpha: 1) // #ECFAFB
static let oceanLight7: UIColor = #colorLiteral(red: 0.9882352941, green: 1, blue: 1, alpha: 1) // #FCFFFF
}
public extension UIColor {

View File

@ -74,6 +74,7 @@ internal enum Theme_OceanDark: ThemeColors {
.appearance_buttonHighlight: .oceanDark4,
// Alert
.alert_text: .oceanDark6,
.alert_background: .oceanDark3,
.alert_buttonBackground: .oceanDark3,
.alert_buttonHighlight: .oceanDark4,
@ -96,6 +97,7 @@ internal enum Theme_OceanDark: ThemeColors {
// ContextMenu
.contextMenu_background: .oceanDark2,
.contextMenu_highlight: .primary,
.contextMenu_text: .oceanDark6,
.contextMenu_textHighlight: .oceanDark0,
// Call

View File

@ -12,27 +12,27 @@ internal enum Theme_OceanLight: ThemeColors {
.defaultPrimary: Theme.PrimaryColor.blue.color,
.danger: .dangerLight,
.disabled: .disabledLight,
.backgroundPrimary: .oceanLight6,
.backgroundSecondary: .oceanLight5,
.textPrimary: .oceanLight0,
.textSecondary: .oceanLight1,
.borderSeparator: .oceanLight2,
.backgroundPrimary: .oceanLight7,
.backgroundSecondary: .oceanLight6,
.textPrimary: .oceanLight1,
.textSecondary: .oceanLight2,
.borderSeparator: .oceanLight3,
// Path
.path_connected: .pathConnected,
.path_connecting: .pathConnecting,
.path_error: .pathError,
.path_unknown: .oceanLight4,
.path_unknown: .oceanLight5,
// TextBox
.textBox_background: .oceanLight6,
.textBox_border: .oceanLight2,
.textBox_background: .oceanLight7,
.textBox_border: .oceanLight3,
// MessageBubble
.messageBubble_outgoingBackground: .primary,
.messageBubble_incomingBackground: .oceanLight3,
.messageBubble_outgoingText: .oceanLight0,
.messageBubble_incomingText: .oceanLight0,
.messageBubble_incomingBackground: .oceanLight4,
.messageBubble_outgoingText: .oceanLight1,
.messageBubble_incomingText: .oceanLight1,
.messageBubble_overlay: .black_06,
// MenuButton
@ -44,58 +44,60 @@ internal enum Theme_OceanLight: ThemeColors {
// RadioButton
.radioButton_selectedBackground: .primary,
.radioButton_unselectedBackground: .clear,
.radioButton_selectedBorder: .oceanLight0,
.radioButton_unselectedBorder: .oceanLight2,
.radioButton_selectedBorder: .oceanLight1,
.radioButton_unselectedBorder: .oceanLight3,
// OutlineButton
.outlineButton_text: .oceanLight0,
.outlineButton_text: .oceanLight1,
.outlineButton_background: .clear,
.outlineButton_highlight: .oceanLight0.withAlphaComponent(0.1),
.outlineButton_border: .oceanLight0,
.outlineButton_filledText: .oceanLight6,
.outlineButton_filledBackground: .oceanLight0,
.outlineButton_filledHighlight: .oceanLight1,
.outlineButton_highlight: .oceanLight1.withAlphaComponent(0.1),
.outlineButton_border: .oceanLight1,
.outlineButton_filledText: .oceanLight7,
.outlineButton_filledBackground: .oceanLight1,
.outlineButton_filledHighlight: .oceanLight2,
.outlineButton_destructiveText: .dangerLight,
.outlineButton_destructiveBackground: .clear,
.outlineButton_destructiveHighlight: .dangerLight.withAlphaComponent(0.3),
.outlineButton_destructiveBorder: .dangerLight,
// SolidButton
.solidButton_background: .oceanLight4,
.solidButton_highlight: .oceanLight5,
.solidButton_background: .oceanLight5,
.solidButton_highlight: .oceanLight6,
// Settings
.settings_tabBackground: .oceanLight6,
.settings_tabHighlight: .oceanLight4,
.settings_tabBackground: .oceanLight7,
.settings_tabHighlight: .oceanLight5,
// Appearance
.appearance_sectionBackground: .oceanLight6,
.appearance_buttonBackground: .oceanLight6,
.appearance_buttonHighlight: .oceanLight4,
.appearance_sectionBackground: .oceanLight7,
.appearance_buttonBackground: .oceanLight7,
.appearance_buttonHighlight: .oceanLight5,
// Alert
.alert_background: .oceanLight6,
.alert_buttonBackground: .oceanLight6,
.alert_buttonHighlight: .oceanLight4,
.alert_text: .oceanLight0,
.alert_background: .oceanLight7,
.alert_buttonBackground: .oceanLight7,
.alert_buttonHighlight: .oceanLight5,
// ConversationButton
.conversationButton_background: .oceanLight6,
.conversationButton_highlight: .oceanLight4,
.conversationButton_unreadBackground: .oceanLight5,
.conversationButton_unreadHighlight: .oceanLight4,
.conversationButton_background: .oceanLight7,
.conversationButton_highlight: .oceanLight5,
.conversationButton_unreadBackground: .oceanLight6,
.conversationButton_unreadHighlight: .oceanLight5,
.conversationButton_unreadStripBackground: .primary,
.conversationButton_unreadBubbleBackground: .primary,
.conversationButton_unreadBubbleText: .oceanLight0,
.conversationButton_unreadBubbleText: .oceanLight1,
.conversationButton_swipeDestructive: .dangerLight,
.conversationButton_swipeSecondary: .oceanLight1,
.conversationButton_swipeSecondary: .oceanLight2,
.conversationButton_swipeTertiary: Theme.PrimaryColor.orange.color,
// InputButton
.inputButton_background: .oceanLight6,
.inputButton_background: .oceanLight7,
// ContextMenu
.contextMenu_background: .oceanLight6,
.contextMenu_background: .oceanLight7,
.contextMenu_highlight: .primary,
.contextMenu_text: .oceanLight0,
.contextMenu_textHighlight: .oceanLight0,
// Call
@ -103,7 +105,7 @@ internal enum Theme_OceanLight: ThemeColors {
.callDecline_background: .dangerLight,
// Reactions
.reactions_contextBackground: .oceanLight6,
.reactions_contextMoreBackground: .oceanLight5
.reactions_contextBackground: .oceanLight7,
.reactions_contextMoreBackground: .oceanLight6
]
}

View File

@ -125,6 +125,7 @@ public enum ThemeValue {
case appearance_buttonHighlight
// Alert
case alert_text
case alert_background
case alert_buttonBackground
case alert_buttonHighlight
@ -147,6 +148,7 @@ public enum ThemeValue {
// ContextMenu
case contextMenu_background
case contextMenu_highlight
case contextMenu_text
case contextMenu_textHighlight
// Call
@ -157,3 +159,40 @@ public enum ThemeValue {
case reactions_contextBackground
case reactions_contextMoreBackground
}
// MARK: - ForcedThemeValue
public enum ForcedThemeValue {
case color(UIColor)
case primary(Theme.PrimaryColor, alpha: CGFloat?)
case theme(Theme, color: ThemeValue, alpha: CGFloat?)
public static func primary(_ primary: Theme.PrimaryColor) -> ForcedThemeValue {
return .primary(primary, alpha: nil)
}
public static func theme(_ theme: Theme, color: ThemeValue) -> ForcedThemeValue {
return .theme(theme, color: color, alpha: nil)
}
}
// MARK: - ForcedThemeAttribute
public enum ForcedThemeAttribute {
case background(UIColor)
case foreground(UIColor)
public var key: NSAttributedString.Key {
switch self {
case .background: return NSAttributedString.Key.backgroundColor
case .foreground: return NSAttributedString.Key.foregroundColor
}
}
public var value: Any {
switch self {
case .background(let value): return value
case .foreground(let value): return value
}
}
}

View File

@ -8,20 +8,124 @@ public extension UIView {
get { return nil }
}
var themeBackgroundColorForced: ForcedThemeValue? {
set {
switch newValue {
case .color(let color): backgroundColor = color
case .primary(let value, let alpha):
guard let alpha: CGFloat = alpha else {
backgroundColor = value.color
return
}
backgroundColor = value.color.withAlphaComponent(alpha)
case .theme(let theme, let value, let alpha):
guard let alpha: CGFloat = alpha else {
backgroundColor = theme.colors[value]
return
}
backgroundColor = theme.colors[value]?.withAlphaComponent(alpha)
case .none: backgroundColor = nil
}
}
get { return self.backgroundColor.map { .color($0) } }
}
var themeTintColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.tintColor, to: newValue) }
get { return nil }
}
var themeTintColorForced: ForcedThemeValue? {
set {
switch newValue {
case .color(let color): tintColor = color
case .primary(let value, let alpha):
guard let alpha: CGFloat = alpha else {
tintColor = value.color
return
}
tintColor = value.color.withAlphaComponent(alpha)
case .theme(let theme, let value, let alpha):
guard let alpha: CGFloat = alpha else {
tintColor = theme.colors[value]
return
}
tintColor = theme.colors[value]?.withAlphaComponent(alpha)
case .none: tintColor = nil
}
}
get { return self.tintColor.map { .color($0) } }
}
var themeBorderColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.layer.borderColor, to: newValue) }
get { return nil }
}
var themeBorderColorForced: ForcedThemeValue? {
set {
switch newValue {
case .color(let color): layer.borderColor = color.cgColor
case .primary(let value, let alpha):
guard let alpha: CGFloat = alpha else {
layer.borderColor = value.color.cgColor
return
}
layer.borderColor = value.color.withAlphaComponent(alpha).cgColor
case .theme(let theme, let value, let alpha):
guard let alpha: CGFloat = alpha else {
layer.borderColor = theme.colors[value]?.cgColor
return
}
layer.borderColor = theme.colors[value]?.withAlphaComponent(alpha).cgColor
case .none: layer.borderColor = nil
}
}
get { return nil }
}
var themeShadowColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.layer.shadowColor, to: newValue) }
get { return nil }
}
var themeShadowColorForced: ForcedThemeValue? {
set {
switch newValue {
case .color(let color): layer.shadowColor = color.cgColor
case .primary(let value, let alpha):
guard let alpha: CGFloat = alpha else {
layer.shadowColor = value.color.cgColor
return
}
layer.shadowColor = value.color.withAlphaComponent(alpha).cgColor
case .theme(let theme, let value, let alpha):
guard let alpha: CGFloat = alpha else {
layer.shadowColor = theme.colors[value]?.cgColor
return
}
layer.shadowColor = theme.colors[value]?.withAlphaComponent(alpha).cgColor
case .none: layer.shadowColor = nil
}
}
get { return self.layer.shadowColor.map { .color(UIColor(cgColor: $0)) } }
}
}
public extension UILabel {
@ -29,6 +133,32 @@ public extension UILabel {
set { ThemeManager.set(self, keyPath: \.textColor, to: newValue) }
get { return nil }
}
var themeTextColorForced: ForcedThemeValue? {
set {
switch newValue {
case .color(let color): textColor = color
case .primary(let value, let alpha):
guard let alpha: CGFloat = alpha else {
textColor = value.color
return
}
textColor = value.color.withAlphaComponent(alpha)
case .theme(let theme, let value, let alpha):
guard let alpha: CGFloat = alpha else {
textColor = theme.colors[value]
return
}
textColor = theme.colors[value]?.withAlphaComponent(alpha)
case .none: textColor = nil
}
}
get { return self.textColor.map { .color($0) } }
}
}
public extension UITextView {
@ -36,6 +166,32 @@ public extension UITextView {
set { ThemeManager.set(self, keyPath: \.textColor, to: newValue) }
get { return nil }
}
var themeTextColorForced: ForcedThemeValue? {
set {
switch newValue {
case .color(let color): textColor = color
case .primary(let value, let alpha):
guard let alpha: CGFloat = alpha else {
textColor = value.color
return
}
textColor = value.color.withAlphaComponent(alpha)
case .theme(let theme, let value, let alpha):
guard let alpha: CGFloat = alpha else {
textColor = theme.colors[value]
return
}
textColor = theme.colors[value]?.withAlphaComponent(alpha)
case .none: textColor = nil
}
}
get { return self.textColor.map { .color($0) } }
}
}
public extension UITextField {
@ -43,6 +199,32 @@ public extension UITextField {
set { ThemeManager.set(self, keyPath: \.textColor, to: newValue) }
get { return nil }
}
var themeTextColorForced: ForcedThemeValue? {
set {
switch newValue {
case .color(let color): textColor = color
case .primary(let value, let alpha):
guard let alpha: CGFloat = alpha else {
textColor = value.color
return
}
textColor = value.color.withAlphaComponent(alpha)
case .theme(let theme, let value, let alpha):
guard let alpha: CGFloat = alpha else {
textColor = theme.colors[value]
return
}
textColor = theme.colors[value]?.withAlphaComponent(alpha)
case .none: textColor = nil
}
}
get { return self.textColor.map { .color($0) } }
}
}
public extension UIButton {
@ -71,6 +253,29 @@ public extension UIButton {
)
}
func setThemeBackgroundColorForced(_ newValue: ForcedThemeValue?, for state: UIControl.State) {
switch newValue {
case .color(let color): self.setBackgroundImage(color.toImage(), for: state)
case .primary(let value, let alpha):
guard let alpha: CGFloat = alpha else {
self.setBackgroundImage(value.color.toImage(), for: state)
return
}
self.setBackgroundImage(value.color.withAlphaComponent(alpha).toImage(), for: state)
case .theme(let theme, let value, let alpha):
guard let alpha: CGFloat = alpha else {
self.setBackgroundImage(theme.colors[value]?.toImage(), for: state)
return
}
self.setBackgroundImage(theme.colors[value]?.withAlphaComponent(alpha).toImage(), for: state)
case .none: self.setBackgroundImage(nil, for: state)
}
}
func setThemeTitleColor(_ value: ThemeValue?, for state: UIControl.State) {
let keyPath: KeyPath<UIButton, UIColor?> = \.titleLabel?.textColor
@ -95,6 +300,29 @@ public extension UIButton {
}
)
}
func setThemeTitleColorForced(_ newValue: ForcedThemeValue?, for state: UIControl.State) {
switch newValue {
case .color(let color): self.setTitleColor(color, for: state)
case .primary(let value, let alpha):
guard let alpha: CGFloat = alpha else {
self.setTitleColor(value.color, for: state)
return
}
self.setTitleColor(value.color.withAlphaComponent(alpha), for: state)
case .theme(let theme, let value, let alpha):
guard let alpha: CGFloat = alpha else {
self.setTitleColor(theme.colors[value], for: state)
return
}
self.setTitleColor(theme.colors[value]?.withAlphaComponent(alpha), for: state)
case .none: self.setTitleColor(nil, for: state)
}
}
}
public extension UISwitch {
@ -117,12 +345,57 @@ public extension UIProgressView {
get { return nil }
}
var themeProgressTintColorForced: ForcedThemeValue? {
set {
switch newValue {
case .color(let color): progressTintColor = color
case .primary(let value, let alpha):
guard let alpha: CGFloat = alpha else {
progressTintColor = value.color
return
}
progressTintColor = value.color.withAlphaComponent(alpha)
case .theme(let theme, let value, let alpha):
guard let alpha: CGFloat = alpha else {
progressTintColor = theme.colors[value]
return
}
progressTintColor = theme.colors[value]?.withAlphaComponent(alpha)
case .none: progressTintColor = nil
}
}
get { return self.progressTintColor.map { .color($0) } }
}
var themeTrackTintColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.trackTintColor, to: newValue) }
get { return nil }
}
}
public extension UISlider {
var themeMinimumTrackTintColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.minimumTrackTintColor, to: newValue) }
get { return nil }
}
var themeMaximumTrackTintColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.maximumTrackTintColor, to: newValue) }
get { return nil }
}
}
public extension UIToolbar {
var themeBarTintColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.barTintColor, to: newValue) }
get { return nil }
}
}
public extension UIContextualAction {
var themeBackgroundColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.backgroundColor, to: newValue) }
@ -136,13 +409,96 @@ public extension CAShapeLayer {
get { return nil }
}
var themeStrokeColorForced: ForcedThemeValue? {
set {
switch newValue {
case .color(let color): strokeColor = color.cgColor
case .primary(let value, let alpha):
guard let alpha: CGFloat = alpha else {
strokeColor = value.color.cgColor
return
}
strokeColor = value.color.withAlphaComponent(alpha).cgColor
case .theme(let theme, let value, let alpha):
guard let alpha: CGFloat = alpha else {
strokeColor = theme.colors[value]?.cgColor
return
}
strokeColor = theme.colors[value]?.withAlphaComponent(alpha).cgColor
case .none: strokeColor = nil
}
}
get { return self.strokeColor.map { .color(UIColor(cgColor: $0)) } }
}
var themeFillColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.fillColor, to: newValue) }
get { return nil }
}
var themeFillColorForced: ForcedThemeValue? {
set {
switch newValue {
case .color(let color): fillColor = color.cgColor
case .primary(let value, let alpha):
guard let alpha: CGFloat = alpha else {
fillColor = value.color.cgColor
return
}
fillColor = value.color.withAlphaComponent(alpha).cgColor
case .theme(let theme, let value, let alpha):
guard let alpha: CGFloat = alpha else {
fillColor = theme.colors[value]?.cgColor
return
}
fillColor = theme.colors[value]?.withAlphaComponent(alpha).cgColor
case .none: fillColor = nil
}
}
get { return self.fillColor.map { .color(UIColor(cgColor: $0)) } }
}
}
public extension CALayer {
var themeBackgroundColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.backgroundColor, to: newValue) }
get { return nil }
}
var themeBackgroundColorForced: ForcedThemeValue? {
set {
switch newValue {
case .color(let color): backgroundColor = color.cgColor
case .primary(let value, let alpha):
guard let alpha: CGFloat = alpha else {
backgroundColor = value.color.cgColor
return
}
backgroundColor = value.color.withAlphaComponent(alpha).cgColor
case .theme(let theme, let value, let alpha):
guard let alpha: CGFloat = alpha else {
backgroundColor = theme.colors[value]?.cgColor
return
}
backgroundColor = theme.colors[value]?.withAlphaComponent(alpha).cgColor
case .none: backgroundColor = nil
}
}
get { return self.backgroundColor.map { .color(UIColor(cgColor: $0)) } }
}
var themeBorderColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.borderColor, to: newValue) }
get { return nil }
@ -153,3 +509,42 @@ public extension CALayer {
get { return nil }
}
}
public extension CATextLayer {
var themeForegroundColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.foregroundColor, to: newValue) }
get { return nil }
}
var themeForegroundColorForced: ForcedThemeValue? {
set {
switch newValue {
case .color(let color): foregroundColor = color.cgColor
case .primary(let value, let alpha):
guard let alpha: CGFloat = alpha else {
foregroundColor = value.color.cgColor
return
}
foregroundColor = value.color.withAlphaComponent(alpha).cgColor
case .theme(let theme, let value, let alpha):
guard let alpha: CGFloat = alpha else {
foregroundColor = theme.colors[value]?.cgColor
return
}
foregroundColor = theme.colors[value]?.withAlphaComponent(alpha).cgColor
case .none: foregroundColor = nil
}
}
get { return self.foregroundColor.map { .color(UIColor(cgColor: $0)) } }
}
}
public extension NSMutableAttributedString {
func addThemeAttribute(_ attribute: ForcedThemeAttribute, range: NSRange) {
self.addAttribute(attribute.key, value: attribute.value, range: range)
}
}

View File

@ -1,11 +1,13 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
public extension UIImage {
func withTint(_ color: UIColor) -> UIImage? {
let template = self.withRenderingMode(.alwaysTemplate)
let imageView = UIImageView(image: template)
imageView.tintColor = color
imageView.themeTintColorForced = .color(color)
return imageView.toImage(isOpaque: imageView.isOpaque, scale: UIScreen.main.scale)
}
}

View File

@ -111,22 +111,12 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value);
- (NSArray<NSLayoutConstraint *> *)autoPinToEdgesOfView:(UIView *)view;
- (void)traverseViewHierarchyWithVisitor:(UIViewVisitorBlock)visitor;
#pragma mark - Containers
+ (UIView *)containerView;
+ (UIView *)verticalStackWithSubviews:(NSArray<UIView *> *)subviews spacing:(int)spacing;
#pragma mark - Debugging
- (void)addBorderWithColor:(UIColor *)color;
- (void)addRedBorder;
// Add red border to self, and all subviews recursively.
- (void)addRedBorderRecursively;
@end
#pragma mark -

View File

@ -439,36 +439,6 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value)
return container;
}
#pragma mark - Debugging
- (void)addBorderWithColor:(UIColor *)color
{
self.layer.borderColor = color.CGColor;
self.layer.borderWidth = 1;
}
- (void)addRedBorder
{
[self addBorderWithColor:[UIColor redColor]];
}
- (void)addRedBorderRecursively
{
[self addRedBorder];
for (UIView *subview in self.subviews) {
[subview addRedBorderRecursively];
}
}
- (void)traverseViewHierarchyWithVisitor:(UIViewVisitorBlock)visitor
{
visitor(self);
for (UIView *subview in self.subviews) {
[subview traverseViewHierarchyWithVisitor:visitor];
}
}
@end
#pragma mark -

View File

@ -14,6 +14,6 @@ public enum Configuration {
SNMessagingKit.configure()
SNSnodeKit.configure()
SUIKit.configure()
SNUIKit.configure()
}
}

View File

@ -1,6 +1,4 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import UIKit
@ -55,17 +53,17 @@ class AttachmentApprovalInputAccessoryView: UIView {
// sizing when used as an input accessory view.
self.autoresizingMask = .flexibleHeight
self.translatesAutoresizingMaskIntoConstraints = false
self.backgroundColor = .clear
self.themeBackgroundColor = .clear
preservesSuperviewLayoutMargins = true
// Use a background view that extends below the keyboard to avoid animation glitches.
let backgroundView = UIView()
backgroundView.backgroundColor = UIColor.black.withAlphaComponent(0.6)
backgroundView.themeBackgroundColor = .backgroundPrimary
addSubview(backgroundView)
backgroundView.autoPinEdgesToSuperviewEdges()
currentCaptionLabel.textColor = .white
currentCaptionLabel.themeTextColor = .white
currentCaptionLabel.font = .systemFont(ofSize: Values.mediumFontSize)
currentCaptionLabel.numberOfLines = 5
currentCaptionLabel.lineBreakMode = .byWordWrapping
@ -90,7 +88,7 @@ class AttachmentApprovalInputAccessoryView: UIView {
stackView.autoPinEdge(toSuperviewMargin: .bottom)
let galleryRailBlockingView: UIView = UIView()
galleryRailBlockingView.backgroundColor = backgroundView.backgroundColor
galleryRailBlockingView.themeBackgroundColor = .backgroundPrimary
stackView.addSubview(galleryRailBlockingView)
galleryRailBlockingView.pin(.top, to: .bottom, of: attachmentTextToolbar)
galleryRailBlockingView.pin(.left, to: .left, of: stackView)
@ -101,9 +99,8 @@ class AttachmentApprovalInputAccessoryView: UIView {
// MARK: - Events
@objc func captionTapped(sender: UIGestureRecognizer) {
guard sender.state == .recognized else {
return
}
guard sender.state == .recognized else { return }
delegate?.attachmentApprovalInputStartEditingCaptions()
}

View File

@ -213,18 +213,8 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
override public func viewDidLoad() {
super.viewDidLoad()
self.view.backgroundColor = Colors.navigationBarBackground
self.view.themeBackgroundColor = .backgroundSecondary
let backgroundImage: UIImage = UIImage(color: Colors.navigationBarBackground)
self.navigationItem.title = nil
self.navigationController?.navigationBar.setBackgroundImage(UIImage(), for: .default)
self.navigationController?.navigationBar.shadowImage = UIImage()
self.navigationController?.navigationBar.isTranslucent = false
self.navigationController?.navigationBar.barTintColor = Colors.navigationBarBackground
(self.navigationController?.navigationBar as? OWSNavigationBar)?.respectsTheme = true
self.navigationController?.navigationBar.backgroundColor = Colors.navigationBarBackground
self.navigationController?.navigationBar.setBackgroundImage(backgroundImage, for: .default)
// Avoid an unpleasant "bounce" which doesn't make sense in the context of a single item.
pagerScrollView?.isScrollEnabled = (attachmentItems.count > 1)
@ -369,12 +359,9 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
let cancelButton = OWSButton(title: CommonStrings.cancelButton) { [weak self] in
self?.cancelPressed()
}
cancelButton.setTitleColor(Colors.text, for: .normal)
if let titleLabel = cancelButton.titleLabel {
titleLabel.font = UIFont.systemFont(ofSize: 17.0)
} else {
owsFailDebug("Missing titleLabel.")
}
cancelButton.titleLabel?.font = .systemFont(ofSize: 17.0)
cancelButton.setThemeTitleColor(.textPrimary, for: .normal)
cancelButton.setThemeTitleColor(.textSecondary, for: .highlighted)
cancelButton.sizeToFit()
navigationItem.leftBarButtonItem = UIBarButtonItem(customView: cancelButton)
}
@ -382,7 +369,7 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
// Mimic a conventional back button, but with a shadow.
let isRTL = CurrentAppContext().isRTL
let imageName = (isRTL ? "NavBarBackRTL" : "NavBarBack")
let backButton = OWSButton(imageName: imageName, tintColor: Colors.text) { [weak self] in
let backButton = OWSButton(imageName: imageName, tintColor: .textPrimary) { [weak self] in
self?.navigationController?.popViewController(animated: true)
}
@ -727,13 +714,9 @@ public class AttachmentApprovalViewController: UIPageViewController, UIPageViewC
// MARK: -
extension AttachmentApprovalViewController: AttachmentTextToolbarDelegate {
func attachmentTextToolbarDidBeginEditing(_ attachmentTextToolbar: AttachmentTextToolbar) {
currentPageViewController?.setAttachmentViewScale(.compact, animated: true)
}
func attachmentTextToolbarDidBeginEditing(_ attachmentTextToolbar: AttachmentTextToolbar) {}
func attachmentTextToolbarDidEndEditing(_ attachmentTextToolbar: AttachmentTextToolbar) {
currentPageViewController?.setAttachmentViewScale(.fullsize, animated: true)
}
func attachmentTextToolbarDidEndEditing(_ attachmentTextToolbar: AttachmentTextToolbar) {}
func attachmentTextToolbarDidTapSend(_ attachmentTextToolbar: AttachmentTextToolbar) {
// Toolbar flickers in and out if there are errors
@ -768,9 +751,9 @@ extension AttachmentApprovalViewController: AttachmentPrepViewControllerDelegate
extension SignalAttachmentItem: GalleryRailItem {
func buildRailItemView() -> UIView {
let imageView = UIImageView()
imageView.contentMode = .scaleAspectFill
imageView.backgroundColor = UIColor.black.withAlphaComponent(0.33)
imageView.image = getThumbnailImage()
imageView.themeBackgroundColor = .backgroundSecondary
imageView.contentMode = .scaleAspectFill
return imageView
}

View File

@ -6,7 +6,7 @@ import Foundation
import UIKit
import SessionUIKit
protocol AttachmentCaptionToolbarDelegate: class {
protocol AttachmentCaptionToolbarDelegate: AnyObject {
func attachmentCaptionToolbarDidEdit(_ attachmentCaptionToolbar: AttachmentCaptionToolbar)
func attachmentCaptionToolbarDidComplete()
}
@ -49,7 +49,7 @@ class AttachmentCaptionToolbar: UIView, UITextViewDelegate {
// sizing when used as an input accessory view.
self.autoresizingMask = .flexibleHeight
self.translatesAutoresizingMaskIntoConstraints = false
self.backgroundColor = UIColor.clear
self.themeBackgroundColor = .clear
textView.delegate = self
@ -92,12 +92,12 @@ class AttachmentCaptionToolbar: UIView, UITextViewDelegate {
let lengthLimitLabel = UILabel()
// Length Limit Label shown when the user inputs too long of a message
lengthLimitLabel.textColor = .white
lengthLimitLabel.themeTextColor = .textPrimary
lengthLimitLabel.text = NSLocalizedString("ATTACHMENT_APPROVAL_MESSAGE_LENGTH_LIMIT_REACHED", comment: "One-line label indicating the user can add no more text to the media message field.")
lengthLimitLabel.textAlignment = .center
// Add shadow in case overlayed on white content
lengthLimitLabel.layer.shadowColor = UIColor.black.cgColor
lengthLimitLabel.themeShadowColor = .black
lengthLimitLabel.layer.shadowOffset = .zero
lengthLimitLabel.layer.shadowOpacity = 0.8
lengthLimitLabel.layer.shadowRadius = 2.0
@ -127,11 +127,11 @@ class AttachmentCaptionToolbar: UIView, UITextViewDelegate {
let textView = AttachmentTextView()
textView.keyboardAppearance = isLightMode ? .default : .dark
textView.backgroundColor = .clear
textView.tintColor = .white
textView.themeBackgroundColor = .clear
textView.themeTintColor = .textPrimary
textView.font = UIFont.ows_dynamicTypeBody
textView.textColor = .white
textView.themeTextColor = .textPrimary
textView.textContainerInset = UIEdgeInsets(top: 7, left: 7, bottom: 7, right: 7)
return textView

View File

@ -1,316 +0,0 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
import UIKit
import SessionUIKit
protocol AttachmentCaptionDelegate: class {
func captionView(_ captionView: AttachmentCaptionViewController, didChangeCaptionText captionText: String?, attachmentItem: SignalAttachmentItem)
func captionViewDidCancel()
}
// MARK: -
class AttachmentCaptionViewController: OWSViewController {
weak var delegate: AttachmentCaptionDelegate?
private let attachmentItem: SignalAttachmentItem
private let originalCaptionText: String?
private let textView = UITextView()
private var textViewHeightConstraint: NSLayoutConstraint?
private let kMaxCaptionCharacterCount = 240
init(delegate: AttachmentCaptionDelegate,
attachmentItem: SignalAttachmentItem) {
self.delegate = delegate
self.attachmentItem = attachmentItem
self.originalCaptionText = attachmentItem.captionText
super.init(nibName: nil, bundle: nil)
self.addObserver(textView, forKeyPath: "contentSize", options: .new, context: nil)
}
@available(*, unavailable, message: "use other init() instead.")
required public init?(coder aDecoder: NSCoder) {
notImplemented()
}
deinit {
self.removeObserver(textView, forKeyPath: "contentSize")
}
open override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey: Any]?, context: UnsafeMutableRawPointer?) {
updateTextView()
}
// MARK: - View Lifecycle
public override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
textView.becomeFirstResponder()
updateTextView()
}
public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
textView.becomeFirstResponder()
updateTextView()
}
public override func loadView() {
self.view = UIView()
self.view.backgroundColor = UIColor(white: 0, alpha: 0.25)
self.view.isOpaque = false
self.view.isUserInteractionEnabled = true
self.view.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(backgroundTapped)))
configureTextView()
let doneIcon = UIImage(named: "image_editor_checkmark_full")?.withRenderingMode(.alwaysTemplate)
let doneButton = UIBarButtonItem(image: doneIcon, style: .plain,
target: self,
action: #selector(didTapDone))
doneButton.tintColor = .white
navigationItem.rightBarButtonItem = doneButton
self.view.layoutMargins = .zero
lengthLimitLabel.setContentHuggingHigh()
lengthLimitLabel.setCompressionResistanceHigh()
let stackView = UIStackView(arrangedSubviews: [lengthLimitLabel, textView])
stackView.axis = .vertical
stackView.spacing = 20
stackView.alignment = .fill
stackView.layoutMargins = UIEdgeInsets(top: 16, left: 20, bottom: 16, right: 20)
stackView.isLayoutMarginsRelativeArrangement = true
self.view.addSubview(stackView)
stackView.autoPinEdge(toSuperviewEdge: .leading)
stackView.autoPinEdge(toSuperviewEdge: .trailing)
self.autoPinView(toBottomOfViewControllerOrKeyboard: stackView, avoidNotch: true)
let backgroundView = UIView()
backgroundView.backgroundColor = UIColor(white: 0, alpha: 0.5)
view.addSubview(backgroundView)
view.sendSubviewToBack(backgroundView)
backgroundView.autoPinEdge(toSuperviewEdge: .leading)
backgroundView.autoPinEdge(toSuperviewEdge: .trailing)
backgroundView.autoPinEdge(toSuperviewEdge: .bottom)
backgroundView.autoPinEdge(.top, to: .top, of: stackView)
let minTextHeight: CGFloat = textView.font?.lineHeight ?? 0
textViewHeightConstraint = textView.autoSetDimension(.height, toSize: minTextHeight)
view.addSubview(placeholderTextView)
placeholderTextView.autoAlignAxis(.horizontal, toSameAxisOf: textView)
placeholderTextView.autoPinEdge(.leading, to: .leading, of: textView)
placeholderTextView.autoPinEdge(.trailing, to: .trailing, of: textView)
}
private func configureTextView() {
textView.delegate = self
textView.text = attachmentItem.captionText
textView.font = UIFont.ows_dynamicTypeBody
textView.textColor = .white
textView.isEditable = true
textView.backgroundColor = .clear
textView.isOpaque = false
// We use a white cursor since we use a dark background.
textView.tintColor = .white
textView.isScrollEnabled = true
textView.scrollsToTop = false
textView.isUserInteractionEnabled = true
textView.textAlignment = .left
textView.textContainerInset = .zero
textView.textContainer.lineFragmentPadding = 0
textView.contentInset = .zero
}
// MARK: - Events
@objc func backgroundTapped(sender: UIGestureRecognizer) {
AssertIsOnMainThread()
completeAndDismiss(didCancel: false)
}
@objc public func didTapCancel() {
completeAndDismiss(didCancel: true)
}
@objc public func didTapDone() {
completeAndDismiss(didCancel: false)
}
private func completeAndDismiss(didCancel: Bool) {
if didCancel {
self.delegate?.captionViewDidCancel()
} else {
self.delegate?.captionView(self, didChangeCaptionText: self.textView.text, attachmentItem: attachmentItem)
}
self.dismiss(animated: true) {
// Do nothing.
}
}
// MARK: - Length Limit
private lazy var lengthLimitLabel: UILabel = {
let lengthLimitLabel = UILabel()
// Length Limit Label shown when the user inputs too long of a message
lengthLimitLabel.textColor = UIColor.ows_destructiveRed
lengthLimitLabel.text = NSLocalizedString("ATTACHMENT_APPROVAL_CAPTION_LENGTH_LIMIT_REACHED", comment: "One-line label indicating the user can add no more text to the attachment caption.")
lengthLimitLabel.textAlignment = .center
// Add shadow in case overlayed on white content
lengthLimitLabel.layer.shadowColor = UIColor.black.cgColor
lengthLimitLabel.layer.shadowOffset = .zero
lengthLimitLabel.layer.shadowOpacity = 0.8
lengthLimitLabel.isHidden = true
return lengthLimitLabel
}()
// MARK: - Text Height
// TODO: We need to revisit this with Myles.
func updatePlaceholderTextViewVisibility() {
let isHidden: Bool = {
guard !self.textView.isFirstResponder else {
return true
}
guard let captionText = self.textView.text else {
return false
}
guard captionText.count > 0 else {
return false
}
return true
}()
placeholderTextView.isHidden = isHidden
}
private lazy var placeholderTextView: UIView = {
let placeholderTextView = UITextView()
placeholderTextView.text = NSLocalizedString("ATTACHMENT_APPROVAL_CAPTION_PLACEHOLDER", comment: "placeholder text for an empty captioning field")
placeholderTextView.isEditable = false
placeholderTextView.backgroundColor = .clear
placeholderTextView.font = UIFont.ows_dynamicTypeBody
placeholderTextView.textColor = Colors.text
placeholderTextView.tintColor = Colors.text
placeholderTextView.returnKeyType = .done
return placeholderTextView
}()
// MARK: - Text Height
private func updateTextView() {
guard let textViewHeightConstraint = textViewHeightConstraint else {
owsFailDebug("Missing textViewHeightConstraint.")
return
}
let contentSize = textView.sizeThatFits(CGSize(width: textView.width(), height: CGFloat.greatestFiniteMagnitude))
// `textView.contentSize` isn't accurate when restoring a multiline draft, so we compute it here.
textView.contentSize = contentSize
let minHeight: CGFloat = textView.font?.lineHeight ?? 0
let maxHeight: CGFloat = 300
let newHeight = contentSize.height.clamp(minHeight, maxHeight)
textViewHeightConstraint.constant = newHeight
textView.invalidateIntrinsicContentSize()
textView.superview?.invalidateIntrinsicContentSize()
textView.isScrollEnabled = contentSize.height > maxHeight
updatePlaceholderTextViewVisibility()
}
}
extension AttachmentCaptionViewController: UITextViewDelegate {
public func textViewDidChange(_ textView: UITextView) {
updateTextView()
}
public func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
let existingText: String = textView.text ?? ""
let proposedText: String = (existingText as NSString).replacingCharacters(in: range, with: text)
let kMaxCaptionByteCount = kOversizeTextMessageSizeThreshold / 4
guard proposedText.utf8.count <= kMaxCaptionByteCount else {
Logger.debug("hit caption byte count limit")
self.lengthLimitLabel.isHidden = false
// `range` represents the section of the existing text we will replace. We can re-use that space.
// Range is in units of NSStrings's standard UTF-16 characters. Since some of those chars could be
// represented as single bytes in utf-8, while others may be 8 or more, the only way to be sure is
// to just measure the utf8 encoded bytes of the replaced substring.
let bytesAfterDelete: Int = (existingText as NSString).replacingCharacters(in: range, with: "").utf8.count
// Accept as much of the input as we can
let byteBudget: Int = Int(kOversizeTextMessageSizeThreshold) - bytesAfterDelete
if byteBudget >= 0, let acceptableNewText = text.truncated(toByteCount: UInt(byteBudget)) {
textView.text = (existingText as NSString).replacingCharacters(in: range, with: acceptableNewText)
}
return false
}
// After verifying the byte-length is sufficiently small, verify the character count is within bounds.
// Normally this character count should entail *much* less byte count.
guard proposedText.count <= kMaxCaptionCharacterCount else {
Logger.debug("hit caption character count limit")
self.lengthLimitLabel.isHidden = false
// `range` represents the section of the existing text we will replace. We can re-use that space.
let charsAfterDelete: Int = (existingText as NSString).replacingCharacters(in: range, with: "").count
// Accept as much of the input as we can
let charBudget: Int = Int(kMaxCaptionCharacterCount) - charsAfterDelete
if charBudget >= 0 {
let acceptableNewText = String(text.prefix(charBudget))
textView.text = (existingText as NSString).replacingCharacters(in: range, with: acceptableNewText)
}
return false
}
self.lengthLimitLabel.isHidden = true
return true
}
public func textViewDidBeginEditing(_ textView: UITextView) {
updatePlaceholderTextViewVisibility()
}
public func textViewDidEndEditing(_ textView: UITextView) {
updatePlaceholderTextViewVisibility()
}
}

View File

@ -9,10 +9,10 @@ import SessionMessagingKit
class AddMoreRailItem: GalleryRailItem {
func buildRailItemView() -> UIView {
let view = UIView()
view.backgroundColor = UIColor.black.withAlphaComponent(0.33)
view.themeBackgroundColor = .backgroundSecondary
let iconView = UIImageView(image: #imageLiteral(resourceName: "ic_plus_24").withRenderingMode(.alwaysTemplate))
iconView.tintColor = .ows_white
iconView.themeTintColor = .textPrimary
view.addSubview(iconView)
iconView.setCompressionResistanceHigh()
iconView.setContentHuggingHigh()
@ -66,9 +66,9 @@ class SignalAttachmentItem: Hashable {
}
// MARK: Hashable
public var hashValue: Int {
return attachment.hashValue
func hash(into hasher: inout Hasher) {
attachment.hash(into: &hasher)
}
// MARK: Equatable

View File

@ -1,6 +1,4 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import Foundation
import UIKit
@ -49,7 +47,7 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
AttachmentTextToolbar.kMinTextViewHeight + (AttachmentTextToolbar.kToolbarMargin * 2)
)
private lazy var scrollView: UIScrollView = {
public lazy var scrollView: UIScrollView = {
// Scroll View - used to zoom/pan on images and video
let scrollView: UIScrollView = UIScrollView()
scrollView.translatesAutoresizingMaskIntoConstraints = false
@ -124,9 +122,8 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
}()
public var shouldHideControls: Bool {
guard let imageEditorView = imageEditorView else {
return false
}
guard let imageEditorView = imageEditorView else { return false }
return imageEditorView.shouldHideControls
}
@ -134,7 +131,9 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
init(attachmentItem: SignalAttachmentItem) {
self.attachmentItem = attachmentItem
super.init(nibName: nil, bundle: nil)
if attachment.hasError {
owsFailDebug(attachment.error.debugDescription)
}
@ -149,13 +148,16 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
public override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = Colors.navigationBarBackground
view.themeBackgroundColor = .backgroundSecondary
view.addSubview(contentContainerView)
contentContainerView.addSubview(scrollView)
scrollView.addSubview(mediaMessageView)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(screenTapped))
mediaMessageView.addGestureRecognizer(tapGesture)
if attachment.isImage, let editorView: ImageEditorView = imageEditorView {
view.addSubview(editorView)
@ -292,9 +294,13 @@ public class AttachmentPrepViewController: OWSViewController, PlayerProgressBarD
}
// MARK: - Event Handlers
@objc func screenTapped() {
self.view.window?.endEditing(true)
}
@objc public func didTapPlayerView(_ gestureRecognizer: UIGestureRecognizer) {
assert(self.videoPlayer != nil)
self.view.window?.endEditing(true)
self.pauseVideo()
}
@ -527,25 +533,15 @@ extension AttachmentPrepViewController: UIScrollViewDelegate {
// MARK: -
extension AttachmentPrepViewController: ImageEditorViewDelegate {
public func imageEditor(presentFullScreenView viewController: UIViewController,
isTransparent: Bool) {
public func imageEditor(presentFullScreenView viewController: UIViewController, isTransparent: Bool) {
let navigationController = OWSNavigationController(rootViewController: viewController)
navigationController.modalPresentationStyle = (isTransparent
? .overFullScreen
: .fullScreen)
navigationController.modalPresentationStyle = (isTransparent ?
.overFullScreen :
.fullScreen
)
navigationController.ows_prefersStatusBarHidden = true
navigationController.view.backgroundColor = Colors.navigationBarBackground
if let navigationBar = navigationController.navigationBar as? OWSNavigationBar {
navigationBar.overrideTheme(type: .clear)
} else {
owsFailDebug("navigationBar was nil or unexpected class")
}
self.present(navigationController, animated: false) {
// Do nothing.
}
self.present(navigationController, animated: false, completion: nil)
}
public func imageEditorUpdateNavigationBar() {

View File

@ -9,7 +9,7 @@ import SessionUIKit
// Coincides with Android's max text message length
let kMaxMessageBodyCharacterCount = 2000
protocol AttachmentTextToolbarDelegate: class {
protocol AttachmentTextToolbarDelegate: AnyObject {
func attachmentTextToolbarDidTapSend(_ attachmentTextToolbar: AttachmentTextToolbar)
func attachmentTextToolbarDidBeginEditing(_ attachmentTextToolbar: AttachmentTextToolbar)
func attachmentTextToolbarDidEndEditing(_ attachmentTextToolbar: AttachmentTextToolbar)
@ -55,7 +55,7 @@ class AttachmentTextToolbar: UIView, UITextViewDelegate {
// sizing when used as an input accessory view.
self.autoresizingMask = .flexibleHeight
self.translatesAutoresizingMaskIntoConstraints = false
self.backgroundColor = UIColor.clear
self.themeBackgroundColor = .clear
textView.delegate = self
@ -65,7 +65,7 @@ class AttachmentTextToolbar: UIView, UITextViewDelegate {
sendButton.titleLabel?.font = .boldSystemFont(ofSize: Values.mediumFontSize)
sendButton.titleLabel?.textAlignment = .center
sendButton.tintColor = Colors.accent
sendButton.themeTintColor = .primary
// Increase hit area of send button
sendButton.contentEdgeInsets = UIEdgeInsets(top: 6, left: 8, bottom: 6, right: 8)
@ -138,12 +138,12 @@ class AttachmentTextToolbar: UIView, UITextViewDelegate {
let lengthLimitLabel = UILabel()
// Length Limit Label shown when the user inputs too long of a message
lengthLimitLabel.textColor = .white
lengthLimitLabel.text = NSLocalizedString("ATTACHMENT_APPROVAL_MESSAGE_LENGTH_LIMIT_REACHED", comment: "One-line label indicating the user can add no more text to the media message field.")
lengthLimitLabel.text = "ATTACHMENT_APPROVAL_MESSAGE_LENGTH_LIMIT_REACHED".localized()
lengthLimitLabel.themeTextColor = .textPrimary
lengthLimitLabel.textAlignment = .center
// Add shadow in case overlayed on white content
lengthLimitLabel.layer.shadowColor = UIColor.black.cgColor
lengthLimitLabel.themeShadowColor = .black
lengthLimitLabel.layer.shadowOffset = .zero
lengthLimitLabel.layer.shadowOpacity = 0.8
lengthLimitLabel.layer.shadowRadius = 2.0
@ -173,7 +173,7 @@ class AttachmentTextToolbar: UIView, UITextViewDelegate {
private lazy var textContainer: UIView = {
let textContainer = UIView()
textContainer.layer.borderColor = UIColor.white.cgColor
textContainer.themeBorderColor = .borderSeparator
textContainer.layer.borderWidth = Values.separatorThickness
textContainer.layer.cornerRadius = (AttachmentTextToolbar.kMinTextViewHeight / 2)
textContainer.clipsToBounds = true
@ -191,11 +191,11 @@ class AttachmentTextToolbar: UIView, UITextViewDelegate {
let textView = AttachmentTextView()
textView.keyboardAppearance = isLightMode ? .default : .dark
textView.backgroundColor = .clear
textView.tintColor = .white
textView.themeBackgroundColor = .clear
textView.themeTintColor = .textPrimary
textView.font = .systemFont(ofSize: Values.mediumFontSize)
textView.textColor = .white
textView.themeTextColor = .textPrimary
textView.showsVerticalScrollIndicator = false
textView.textContainerInset = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)

View File

@ -1,12 +1,10 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import SessionUIKit
@objc
public protocol ImageEditorBrushViewControllerDelegate: class {
public protocol ImageEditorBrushViewControllerDelegate: AnyObject {
func brushDidComplete(currentColor: ImageEditorColor)
}
@ -17,24 +15,27 @@ public class ImageEditorBrushViewController: OWSViewController {
private weak var delegate: ImageEditorBrushViewControllerDelegate?
private let model: ImageEditorModel
private let canvasView: ImageEditorCanvasView
private let paletteView: ImageEditorPaletteView
private let bottomInset: CGFloat
// We only want to let users undo changes made in this view.
// So we snapshot any older "operation id" and prevent
// users from undoing it.
private let firstUndoOperationId: String?
init(delegate: ImageEditorBrushViewControllerDelegate,
model: ImageEditorModel,
currentColor: ImageEditorColor) {
init(
delegate: ImageEditorBrushViewControllerDelegate,
model: ImageEditorModel,
currentColor: ImageEditorColor,
bottomInset: CGFloat
) {
self.delegate = delegate
self.model = model
self.canvasView = ImageEditorCanvasView(model: model)
self.paletteView = ImageEditorPaletteView(currentColor: currentColor)
self.firstUndoOperationId = model.currentUndoOperationId()
self.bottomInset = bottomInset
super.init(nibName: nil, bundle: nil)
@ -50,16 +51,19 @@ public class ImageEditorBrushViewController: OWSViewController {
public override func loadView() {
self.view = UIView()
self.view.backgroundColor = Colors.navigationBarBackground
self.view.themeBackgroundColor = .backgroundSecondary
self.view.isOpaque = true
canvasView.configureSubviews()
self.view.addSubview(canvasView)
canvasView.autoPinEdgesToSuperviewEdges()
canvasView.pin(.top, to: .top, of: self.view)
canvasView.pin(.leading, to: .leading, of: self.view)
canvasView.pin(.trailing, to: .trailing, of: self.view)
canvasView.pin(.bottom, to: .bottom, of: self.view, withInset: -bottomInset)
paletteView.delegate = self
self.view.addSubview(paletteView)
paletteView.autoVCenterInSuperview()
paletteView.center(.vertical, in: self.view, withInset: -(bottomInset / 2))
paletteView.autoPinEdge(toSuperviewEdge: .trailing, withInset: 0)
self.view.isUserInteractionEnabled = true

View File

@ -1,8 +1,7 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import SessionUIKit
public class EditorTextLayer: CATextLayer {
let itemId: String
@ -71,13 +70,13 @@ public class ImageEditorCanvasView: UIView {
@objc
public func configureSubviews() {
self.backgroundColor = .clear
self.themeBackgroundColor = .clear
self.isOpaque = false
self.srcImage = loadSrcImage()
clipView.clipsToBounds = true
clipView.backgroundColor = .clear
clipView.themeBackgroundColor = .clear
clipView.isOpaque = false
clipView.layoutCallback = { [weak self] (_) in
guard let strongSelf = self else {
@ -92,7 +91,7 @@ public class ImageEditorCanvasView: UIView {
imageLayer.contentsScale = srcImage.scale
}
contentView.backgroundColor = .clear
contentView.themeBackgroundColor = .clear
contentView.isOpaque = false
contentView.layer.addSublayer(imageLayer)
contentView.layoutCallback = { [weak self] (_) in
@ -396,7 +395,7 @@ public class ImageEditorCanvasView: UIView {
let shapeLayer = CAShapeLayer()
shapeLayer.lineWidth = strokeWidth
shapeLayer.strokeColor = item.color.cgColor
shapeLayer.themeStrokeColorForced = .color(item.color)
shapeLayer.frame = CGRect(origin: .zero, size: viewSize)
// Stroke samples are specified in "image unit" coordinates, but
@ -469,7 +468,7 @@ public class ImageEditorCanvasView: UIView {
}
shapeLayer.path = bezierPath.cgPath
shapeLayer.fillColor = nil
shapeLayer.themeFillColor = nil
shapeLayer.lineCap = CAShapeLayerLineCap.round
shapeLayer.lineJoin = CAShapeLayerLineJoin.round
shapeLayer.zPosition = zPositionForItem(item: item, model: model, zPositionBase: brushLayerZ)
@ -501,14 +500,17 @@ public class ImageEditorCanvasView: UIView {
let fontSize = item.font.pointSize * imageFrame.size.width / item.fontReferenceImageWidth
let text = item.text.filterForDisplay ?? ""
let attributedString = NSAttributedString(string: text,
attributes: [
NSAttributedString.Key.font: item.font.withSize(fontSize),
NSAttributedString.Key.foregroundColor: item.color.color
])
let attributedString: NSMutableAttributedString = NSMutableAttributedString(
string: text,
attributes: [ .font: item.font.withSize(fontSize) ]
)
attributedString.addThemeAttribute(
.foreground(item.color.color),
range: NSRange(location: 0, length: text.count)
)
let layer = EditorTextLayer(itemId: item.itemId)
layer.string = attributedString
layer.foregroundColor = item.color.cgColor
layer.themeForegroundColorForced = .color(item.color.color)
layer.font = CGFont(item.font.fontName as CFString)
layer.fontSize = fontSize
layer.isWrapped = true
@ -608,14 +610,14 @@ public class ImageEditorCanvasView: UIView {
// Because CALayer.renderInContext() doesn't honor CALayer properties like frame,
// transform, etc.
let view = UIView()
view.backgroundColor = UIColor.clear
view.themeBackgroundColor = .clear
view.isOpaque = false
view.frame = CGRect(origin: .zero, size: viewSize)
// Rendering a UIView to an image will not honor the root image's layer transform.
// We therefore use a subview.
let contentView = UIView()
contentView.backgroundColor = UIColor.clear
contentView.themeBackgroundColor = .clear
contentView.isOpaque = false
contentView.frame = CGRect(origin: .zero, size: viewSize)
view.addSubview(contentView)

Some files were not shown because too many files have changed in this diff Show More