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 */ /* Begin PBXBuildFile section */
1FFD68A448D5A1439F2F02FD /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionShareExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DBA125424EDD2417B515C63A /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionShareExtension.framework */; }; 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 */; }; 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 */; }; 3427C64320F500E000EEC730 /* OWSMessageTimerView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3427C64220F500DF00EEC730 /* OWSMessageTimerView.m */; };
3430FE181F7751D4000EC51B /* GiphyAPI.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3430FE171F7751D4000EC51B /* GiphyAPI.swift */; }; 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 */; }; 34661FB820C1C0D60056EDD6 /* message_sent.aiff in Resources */ = {isa = PBXBuildFile; fileRef = 34661FB720C1C0D60056EDD6 /* message_sent.aiff */; };
346B66311F4E29B200E5122F /* CropScaleImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346B66301F4E29B200E5122F /* CropScaleImageViewController.swift */; }; 346B66311F4E29B200E5122F /* CropScaleImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 346B66301F4E29B200E5122F /* CropScaleImageViewController.swift */; };
3478504C1FD7496D007B8332 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B66DBF4919D5BBC8006EA940 /* Images.xcassets */; }; 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 */; }; 34D1F0521F7E8EA30066283D /* GiphyDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D1F0511F7E8EA30066283D /* GiphyDownloader.swift */; };
34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */; }; 34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 34D5CCA81EAE3D30005515DB /* AvatarViewHelper.m */; };
34D99CE4217509C2000AFB39 /* AppEnvironment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 34D99CE3217509C1000AFB39 /* AppEnvironment.swift */; }; 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 */; }; 34F308A21ECB469700BB7697 /* OWSBezierPathView.m in Sources */ = {isa = PBXBuildFile; fileRef = 34F308A11ECB469700BB7697 /* OWSBezierPathView.m */; };
4503F1BE20470A5B00CEE724 /* classic-quiet.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 4503F1BB20470A5B00CEE724 /* classic-quiet.aifc */; }; 4503F1BE20470A5B00CEE724 /* classic-quiet.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 4503F1BB20470A5B00CEE724 /* classic-quiet.aifc */; };
4503F1BF20470A5B00CEE724 /* classic.aifc in Resources */ = {isa = PBXBuildFile; fileRef = 4503F1BC20470A5B00CEE724 /* classic.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, ); }; }; 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, ); }; }; 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 */; }; 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 */; }; 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 */; }; 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 */; }; 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 */; }; 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 */; }; 45CB2FA81CB7146C00E1B343 /* Launch Screen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 45CB2FA71CB7146C00E1B343 /* Launch Screen.storyboard */; };
45CD81EF1DC030E7004C9430 /* SyncPushTokensJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45CD81EE1DC030E7004C9430 /* SyncPushTokensJob.swift */; }; 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 */; }; 45F32C232057297A00A300D5 /* MediaPageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45F32C1D205718B000A300D5 /* MediaPageViewController.swift */; };
4C090A1B210FD9C7001FD7F9 /* HapticFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */; }; 4C090A1B210FD9C7001FD7F9 /* HapticFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C090A1A210FD9C7001FD7F9 /* HapticFeedback.swift */; };
4C1885D2218F8E1C00B67051 /* PhotoGridViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1885D1218F8E1C00B67051 /* PhotoGridViewCell.swift */; }; 4C1885D2218F8E1C00B67051 /* PhotoGridViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C1885D1218F8E1C00B67051 /* PhotoGridViewCell.swift */; };
4C21D5D8223AC60F00EF8A77 /* PhotoCapture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C21D5D7223AC60F00EF8A77 /* PhotoCapture.swift */; }; 4C21D5D8223AC60F00EF8A77 /* PhotoCapture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C21D5D7223AC60F00EF8A77 /* PhotoCapture.swift */; };
4C4AE6A1224AF35700D4AF6F /* SendMediaNavigationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4C4AE69F224AF21900D4AF6F /* SendMediaNavigationController.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 */; }; 4C586926224FAB83003FD070 /* AVAudioSession+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = 4C586925224FAB83003FD070 /* AVAudioSession+OWS.m */; };
4C63CC00210A620B003AE45C /* SignalTSan.supp in Resources */ = {isa = PBXBuildFile; fileRef = 4C63CBFF210A620B003AE45C /* SignalTSan.supp */; }; 4C63CC00210A620B003AE45C /* SignalTSan.supp in Resources */ = {isa = PBXBuildFile; fileRef = 4C63CBFF210A620B003AE45C /* SignalTSan.supp */; };
4C6F527C20FFE8400097DEEE /* SignalUBSan.supp in Resources */ = {isa = PBXBuildFile; fileRef = 4C6F527B20FFE8400097DEEE /* SignalUBSan.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 */; }; 7BAF54D427ACCF01003D12F8 /* SAEScreenLockViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BAF54D227ACCF01003D12F8 /* SAEScreenLockViewController.swift */; };
7BAF54D827ACD0E3003D12F8 /* ReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BAF54D527ACD0E2003D12F8 /* ReusableView.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 */; }; 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 */; }; 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 */; }; 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, ); }; }; 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 */; }; 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 */; }; C300A5F22554B09800555489 /* MessageSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = C300A5F12554B09800555489 /* MessageSender.swift */; };
C300A60D2554B31900555489 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5CE2553860700C340D1 /* Logging.swift */; }; C300A60D2554B31900555489 /* Logging.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3C2A5CE2553860700C340D1 /* Logging.swift */; };
C302093E25DCBF08001F572D /* MentionSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C302093D25DCBF07001F572D /* MentionSelectionView.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 */; }; C31A6C5C247F2CF3001123EF /* CGRect+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31A6C5B247F2CF3001123EF /* CGRect+Utilities.swift */; };
C31D1DE32521718E005D4DA8 /* UserSelectionVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DE22521718E005D4DA8 /* UserSelectionVC.swift */; }; C31D1DE32521718E005D4DA8 /* UserSelectionVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DE22521718E005D4DA8 /* UserSelectionVC.swift */; };
C32824D325C9F9790062D0A7 /* SessionSnodeKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A59F255385C100C340D1 /* SessionSnodeKit.framework */; }; 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, ); }; }; 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 */; }; C33100082558FF6D00070591 /* NewConversationButtonSet.swift in Sources */ = {isa = PBXBuildFile; fileRef = B83F2B85240C7B8F000A54AB /* NewConversationButtonSet.swift */; };
C33100092558FF6D00070591 /* UserCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = C31D1DDC25217014005D4DA8 /* UserCell.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 */; }; 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 */; }; 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, ); }; }; 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 */; }; C38EF00C255B61CC007E1867 /* SignalUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C33FD9AB255A548A00E217F9 /* SignalUtilitiesKit.framework */; };
C38EF22B255B6D5D007E1867 /* ShareViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF226255B6D5D007E1867 /* ShareViewDelegate.swift */; }; C38EF22B255B6D5D007E1867 /* ShareViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF226255B6D5D007E1867 /* ShareViewDelegate.swift */; };
C38EF22C255B6D5D007E1867 /* OWSVideoPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF227255B6D5D007E1867 /* OWSVideoPlayer.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 */; }; 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, ); }; }; 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 */; }; 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, ); }; }; 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, ); }; }; 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 */; }; 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 */; }; C38EF2B4255B6D9C007E1867 /* UIView+Utilities.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */; };
C38EF30C255B6DBF007E1867 /* ScreenLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2E2255B6DB9007E1867 /* ScreenLock.swift */; }; C38EF30C255B6DBF007E1867 /* ScreenLock.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2E2255B6DB9007E1867 /* ScreenLock.swift */; };
C38EF31C255B6DBF007E1867 /* Searcher.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF2F2255B6DBC007E1867 /* Searcher.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 */; }; 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, ); }; }; 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 */; }; C38EF32E255B6DBF007E1867 /* ImageCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF304255B6DBE007E1867 /* ImageCache.swift */; };
C38EF32F255B6DBF007E1867 /* OWSFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF305255B6DBE007E1867 /* OWSFormat.m */; }; C38EF32F255B6DBF007E1867 /* OWSFormat.m in Sources */ = {isa = PBXBuildFile; fileRef = C38EF305255B6DBE007E1867 /* OWSFormat.m */; };
C38EF331255B6DBF007E1867 /* UIGestureRecognizer+OWS.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */; }; 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, ); }; }; 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, ); }; }; 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 */; }; 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 */; }; C38EF38A255B6DD2007E1867 /* AttachmentCaptionToolbar.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF381255B6DD1007E1867 /* AttachmentCaptionToolbar.swift */; };
C38EF38B255B6DD2007E1867 /* AttachmentPrepViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF382255B6DD1007E1867 /* AttachmentPrepViewController.swift */; }; C38EF38B255B6DD2007E1867 /* AttachmentPrepViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF382255B6DD1007E1867 /* AttachmentPrepViewController.swift */; };
C38EF38C255B6DD2007E1867 /* ApprovalRailCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF383255B6DD1007E1867 /* ApprovalRailCellView.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 */; }; C38EF3B8255B6DE7007E1867 /* ImageEditorTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3A8255B6DE4007E1867 /* ImageEditorTextViewController.swift */; };
C38EF3B9255B6DE7007E1867 /* ImageEditorPinchGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */; }; C38EF3B9255B6DE7007E1867 /* ImageEditorPinchGestureRecognizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3A9255B6DE4007E1867 /* ImageEditorPinchGestureRecognizer.swift */; };
C38EF3BA255B6DE7007E1867 /* ImageEditorItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3AA255B6DE4007E1867 /* ImageEditorItem.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 */; }; C38EF402255B6DF7007E1867 /* CommonStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3E4255B6DF4007E1867 /* CommonStrings.swift */; };
C38EF405255B6DF7007E1867 /* OWSButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3E7255B6DF5007E1867 /* OWSButton.swift */; }; C38EF405255B6DF7007E1867 /* OWSButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3E7255B6DF5007E1867 /* OWSButton.swift */; };
C38EF407255B6DF7007E1867 /* Toast.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3E9255B6DF6007E1867 /* Toast.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 */; }; C38EF40B255B6DF7007E1867 /* TappableStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3ED255B6DF6007E1867 /* TappableStackView.swift */; };
C38EF40C255B6DF7007E1867 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3EE255B6DF6007E1867 /* GradientView.swift */; }; C38EF40C255B6DF7007E1867 /* GradientView.swift in Sources */ = {isa = PBXBuildFile; fileRef = C38EF3EE255B6DF6007E1867 /* GradientView.swift */; };
C38EF48A255B7E3F007E1867 /* SessionUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C331FF1B2558F9D300070591 /* SessionUIKit.framework */; }; 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, ); }; }; 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 */; }; C3DAB3242480CB2B00725F25 /* SRCopyableLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DAB3232480CB2A00725F25 /* SRCopyableLabel.swift */; };
C3DB66C3260ACCE6001EFC55 /* OpenGroupPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3DB66C2260ACCE6001EFC55 /* OpenGroupPoller.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 */; }; C3E5C2FA251DBABB0040DFFC /* EditClosedGroupVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3E5C2F9251DBABB0040DFFC /* EditClosedGroupVC.swift */; };
C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A52F255C80BC007BE2A3 /* NoopNotificationsManager.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 */; }; 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 */; }; FD71161728D00DA400B47552 /* ThreadSettingsViewModelSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD71161628D00DA400B47552 /* ThreadSettingsViewModelSpec.swift */; };
FD71161A28D00E1100B47552 /* NotificationContentViewModelSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD71161928D00E1100B47552 /* NotificationContentViewModelSpec.swift */; }; FD71161A28D00E1100B47552 /* NotificationContentViewModelSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD71161928D00E1100B47552 /* NotificationContentViewModelSpec.swift */; };
FD71161C28D194FB00B47552 /* MentionInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD71161B28D194FB00B47552 /* MentionInfo.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 */; }; FD7162DB281B6C440060647B /* TypedTableAlias.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD7162DA281B6C440060647B /* TypedTableAlias.swift */; };
FD716E6428502DDD00C96BF4 /* CallManagerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD716E6328502DDD00C96BF4 /* CallManagerProtocol.swift */; }; FD716E6428502DDD00C96BF4 /* CallManagerProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD716E6328502DDD00C96BF4 /* CallManagerProtocol.swift */; };
FD716E6628502EE200C96BF4 /* CurrentCallProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD716E6528502EE200C96BF4 /* CurrentCallProtocol.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>"; }; 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; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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; }; 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; }; 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; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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; }; 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>"; }; 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; }; 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; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; 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>"; }; FD716E6528502EE200C96BF4 /* CurrentCallProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CurrentCallProtocol.swift; sourceTree = "<group>"; };
@ -2247,7 +2215,6 @@
B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */, B83F2B87240CB75A000A54AB /* UIImage+Scaling.swift */,
FD1C98E3282E3C5B00B76F9E /* UINavigationBar+Utilities.swift */, FD1C98E3282E3C5B00B76F9E /* UINavigationBar+Utilities.swift */,
FD848B8E283EF2A8000E298B /* UIScrollView+Utilities.swift */, FD848B8E283EF2A8000E298B /* UIScrollView+Utilities.swift */,
C31A6C59247F214E001123EF /* UIView+Glow.swift */,
C3548F0724456AB6009433A8 /* UIView+Wrapping.swift */, C3548F0724456AB6009433A8 /* UIView+Wrapping.swift */,
7BAADFCD27B215FE007BCF92 /* UIView+Draggable.swift */, 7BAADFCD27B215FE007BCF92 /* UIView+Draggable.swift */,
7BFD1A892745C4F000FB91B9 /* Permissions.swift */, 7BFD1A892745C4F000FB91B9 /* Permissions.swift */,
@ -2589,19 +2556,12 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
4CA46F4B219CCC630038ABDE /* CaptionView.swift */, 4CA46F4B219CCC630038ABDE /* CaptionView.swift */,
4C4AEC4420EC343B0020E72B /* DismissableTextField.swift */,
45E5A6981F61E6DD001E4A8A /* MarqueeLabel.swift */,
34386A53207D271C009F5D9C /* NeverClearView.swift */,
34F308A01ECB469700BB7697 /* OWSBezierPathView.h */, 34F308A01ECB469700BB7697 /* OWSBezierPathView.h */,
34F308A11ECB469700BB7697 /* OWSBezierPathView.m */, 34F308A11ECB469700BB7697 /* OWSBezierPathView.m */,
34330AA11E79686200DF2FB9 /* OWSProgressView.h */,
34330AA21E79686200DF2FB9 /* OWSProgressView.m */,
45A6DAD51EBBF85500893231 /* ReminderView.swift */,
C354E75923FE2A7600CE22E3 /* BaseVC.swift */, C354E75923FE2A7600CE22E3 /* BaseVC.swift */,
B8BB82AA238F669C00BA5194 /* FullConversationCell.swift */, B8BB82AA238F669C00BA5194 /* FullConversationCell.swift */,
4542DF53208D40AC007B4E76 /* LoadingViewController.swift */, 4542DF53208D40AC007B4E76 /* LoadingViewController.swift */,
340FC888204DAC8C007AEB0F /* OWSQRCodeScanningViewController.h */, FD71162128D983ED00B47552 /* QRCodeScanningViewController.swift */,
340FC896204DAC8C007AEB0F /* OWSQRCodeScanningViewController.m */,
B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */, B893063E2383961A005EAA8E /* ScanQRCodeWrapperVC.swift */,
C31D1DDC25217014005D4DA8 /* UserCell.swift */, C31D1DDC25217014005D4DA8 /* UserCell.swift */,
C31D1DE22521718E005D4DA8 /* UserSelectionVC.swift */, C31D1DE22521718E005D4DA8 /* UserSelectionVC.swift */,
@ -2841,9 +2801,9 @@
children = ( children = (
B8544E3023D16CA500299F14 /* DeviceUtilities.swift */, B8544E3023D16CA500299F14 /* DeviceUtilities.swift */,
FD37E9D628A20B5D003AE748 /* UIColor+Utilities.swift */, FD37E9D628A20B5D003AE748 /* UIColor+Utilities.swift */,
C33100132558FFC200070591 /* UIImage+Tinting.swift */,
B885D5F52334A32100EE0D8E /* UIView+Constraints.swift */, B885D5F52334A32100EE0D8E /* UIView+Constraints.swift */,
C33100272559000A00070591 /* UIView+Rendering.swift */, C33100272559000A00070591 /* UIView+Rendering.swift */,
FD71161F28D97ABC00B47552 /* UIImage+Tinting.swift */,
); );
path = Utilities; path = Utilities;
sourceTree = "<group>"; sourceTree = "<group>";
@ -2990,7 +2950,6 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
B86BD08323399ACF000F5AE3 /* Modal.swift */, B86BD08323399ACF000F5AE3 /* Modal.swift */,
C3DFFAC523E96F0D0058DAF8 /* Sheet.swift */,
FD52090628B49738006098F6 /* ConfirmationModal.swift */, FD52090628B49738006098F6 /* ConfirmationModal.swift */,
); );
path = "Sheets & Modals"; path = "Sheets & Modals";
@ -3019,7 +2978,6 @@
45F32C1D205718B000A300D5 /* MediaPageViewController.swift */, 45F32C1D205718B000A300D5 /* MediaPageViewController.swift */,
454A84032059C787008B8C75 /* MediaTileViewController.swift */, 454A84032059C787008B8C75 /* MediaTileViewController.swift */,
7BBBDC452875600700747E59 /* DocumentTitleViewController.swift */, 7BBBDC452875600700747E59 /* DocumentTitleViewController.swift */,
34E3E5671EC4B19400495BAC /* AudioProgressView.swift */,
346B66301F4E29B200E5122F /* CropScaleImageViewController.swift */, 346B66301F4E29B200E5122F /* CropScaleImageViewController.swift */,
34969559219B605E00DCFE74 /* ImagePickerController.swift */, 34969559219B605E00DCFE74 /* ImagePickerController.swift */,
34A6C27F21E503E600B5B12E /* OWSImagePickerController.swift */, 34A6C27F21E503E600B5B12E /* OWSImagePickerController.swift */,
@ -3085,7 +3043,6 @@
C38EF356255B6DCB007E1867 /* OWSNavigationController.m */, C38EF356255B6DCB007E1867 /* OWSNavigationController.m */,
C38EF344255B6DC5007E1867 /* OWSViewController.h */, C38EF344255B6DC5007E1867 /* OWSViewController.h */,
C38EF355255B6DCB007E1867 /* OWSViewController.m */, C38EF355255B6DCB007E1867 /* OWSViewController.m */,
C38EF33F255B6DC5007E1867 /* SheetViewController.swift */,
); );
path = "Shared View Controllers"; path = "Shared View Controllers";
sourceTree = "<group>"; sourceTree = "<group>";
@ -3127,7 +3084,6 @@
C38EF37D255B6DCF007E1867 /* AttachmentApprovalInputAccessoryView.swift */, C38EF37D255B6DCF007E1867 /* AttachmentApprovalInputAccessoryView.swift */,
C38EF37F255B6DD0007E1867 /* AttachmentApprovalViewController.swift */, C38EF37F255B6DD0007E1867 /* AttachmentApprovalViewController.swift */,
C38EF381255B6DD1007E1867 /* AttachmentCaptionToolbar.swift */, C38EF381255B6DD1007E1867 /* AttachmentCaptionToolbar.swift */,
C38EF384255B6DD2007E1867 /* AttachmentCaptionViewController.swift */,
C38EF37E255B6DD0007E1867 /* AttachmentItemCollection.swift */, C38EF37E255B6DD0007E1867 /* AttachmentItemCollection.swift */,
C38EF382255B6DD1007E1867 /* AttachmentPrepViewController.swift */, C38EF382255B6DD1007E1867 /* AttachmentPrepViewController.swift */,
C38EF37C255B6DCF007E1867 /* AttachmentTextToolbar.swift */, C38EF37C255B6DCF007E1867 /* AttachmentTextToolbar.swift */,
@ -3142,7 +3098,6 @@
B8C2B2C72563685C00551B4D /* CircleView.swift */, B8C2B2C72563685C00551B4D /* CircleView.swift */,
C38EF383255B6DD1007E1867 /* ApprovalRailCellView.swift */, C38EF383255B6DD1007E1867 /* ApprovalRailCellView.swift */,
C38EF3E7255B6DF5007E1867 /* OWSButton.swift */, C38EF3E7255B6DF5007E1867 /* OWSButton.swift */,
C38EF3EC255B6DF6007E1867 /* OWSFlatButton.swift */,
C38EF3DB255B6DF1007E1867 /* OWSLayerView.swift */, C38EF3DB255B6DF1007E1867 /* OWSLayerView.swift */,
C38EF3D9255B6DF1007E1867 /* OWSNavigationBar.swift */, C38EF3D9255B6DF1007E1867 /* OWSNavigationBar.swift */,
C38EF3D7255B6DF0007E1867 /* OWSTextField.h */, C38EF3D7255B6DF0007E1867 /* OWSTextField.h */,
@ -3358,16 +3313,12 @@
7BAF54DB27ACD12B003D12F8 /* UIColor+Extensions.swift */, 7BAF54DB27ACD12B003D12F8 /* UIColor+Extensions.swift */,
C38EF3DC255B6DF1007E1867 /* DirectionalPanGestureRecognizer.swift */, C38EF3DC255B6DF1007E1867 /* DirectionalPanGestureRecognizer.swift */,
C38EF240255B6D67007E1867 /* UIView+OWS.swift */, C38EF240255B6D67007E1867 /* UIView+OWS.swift */,
C38EF236255B6D65007E1867 /* UIViewController+OWS.h */, FD71161D28D9772700B47552 /* UIViewController+OWS.swift */,
C38EF23B255B6D66007E1867 /* UIViewController+OWS.m */,
C38EF23C255B6D66007E1867 /* UIColor+OWS.h */, C38EF23C255B6D66007E1867 /* UIColor+OWS.h */,
C38EF242255B6D67007E1867 /* UIColor+OWS.m */, C38EF242255B6D67007E1867 /* UIColor+OWS.m */,
C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */, C38EF2B2255B6D9C007E1867 /* UIView+Utilities.swift */,
C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */, C38EF2B1255B6D9C007E1867 /* UIViewController+Utilities.swift */,
C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */, C38EF307255B6DBE007E1867 /* UIGestureRecognizer+OWS.swift */,
C38EF2F3255B6DBC007E1867 /* UIImage+OWS.swift */,
C38EF30A255B6DBE007E1867 /* UIUtil.h */,
C38EF300255B6DBD007E1867 /* UIUtil.m */,
C38EF239255B6D66007E1867 /* UIFont+OWS.h */, C38EF239255B6D66007E1867 /* UIFont+OWS.h */,
C38EF238255B6D66007E1867 /* UIFont+OWS.m */, C38EF238255B6D66007E1867 /* UIFont+OWS.m */,
C33FDA96255A57FE00E217F9 /* OWSDispatch.h */, C33FDA96255A57FE00E217F9 /* OWSDispatch.h */,
@ -4213,7 +4164,6 @@
files = ( files = (
C33FDDB0255A582000E217F9 /* NSURLSessionDataTask+StatusCode.h in Headers */, C33FDDB0255A582000E217F9 /* NSURLSessionDataTask+StatusCode.h in Headers */,
C33FDDD0255A582000E217F9 /* FunctionalUtil.h in Headers */, C33FDDD0255A582000E217F9 /* FunctionalUtil.h in Headers */,
C38EF334255B6DBF007E1867 /* UIUtil.h in Headers */,
C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */, C33FDD5B255A582000E217F9 /* OWSOperation.h in Headers */,
C33FDD7C255A582000E217F9 /* SSKAsserts.h in Headers */, C33FDD7C255A582000E217F9 /* SSKAsserts.h in Headers */,
C38EF3F6255B6DF7007E1867 /* OWSTextView.h in Headers */, C38EF3F6255B6DF7007E1867 /* OWSTextView.h in Headers */,
@ -4221,7 +4171,6 @@
C38EF32B255B6DBF007E1867 /* OWSFormat.h in Headers */, C38EF32B255B6DBF007E1867 /* OWSFormat.h in Headers */,
C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */, C33FDDCC255A582000E217F9 /* TSConstants.h in Headers */,
C33FDDBD255A582000E217F9 /* ByteParser.h in Headers */, C33FDDBD255A582000E217F9 /* ByteParser.h in Headers */,
C38EF243255B6D67007E1867 /* UIViewController+OWS.h in Headers */,
C38EF35D255B6DCC007E1867 /* OWSNavigationController.h in Headers */, C38EF35D255B6DCC007E1867 /* OWSNavigationController.h in Headers */,
C38EF249255B6D67007E1867 /* UIColor+OWS.h in Headers */, C38EF249255B6D67007E1867 /* UIColor+OWS.h in Headers */,
C38EF3F5255B6DF7007E1867 /* OWSTextField.h in Headers */, C38EF3F5255B6DF7007E1867 /* OWSTextField.h in Headers */,
@ -5192,13 +5141,13 @@
C331FF982558FA6B00070591 /* AppMode.swift in Sources */, C331FF982558FA6B00070591 /* AppMode.swift in Sources */,
FD52090328B4680F006098F6 /* RadioButton.swift in Sources */, FD52090328B4680F006098F6 /* RadioButton.swift in Sources */,
C331FFE82558FB0000070591 /* TextView.swift in Sources */, C331FFE82558FB0000070591 /* TextView.swift in Sources */,
FD71162028D97ABC00B47552 /* UIImage+Tinting.swift in Sources */,
FD37E9D728A20B5D003AE748 /* UIColor+Utilities.swift in Sources */, FD37E9D728A20B5D003AE748 /* UIColor+Utilities.swift in Sources */,
FD37E9F928A5F14A003AE748 /* _001_ThemePreferences.swift in Sources */, FD37E9F928A5F14A003AE748 /* _001_ThemePreferences.swift in Sources */,
FD37E9C328A1C6F3003AE748 /* ThemeManager.swift in Sources */, FD37E9C328A1C6F3003AE748 /* ThemeManager.swift in Sources */,
C331FF9A2558FA6B00070591 /* Values.swift in Sources */, C331FF9A2558FA6B00070591 /* Values.swift in Sources */,
FD37E9C628A1D4EC003AE748 /* Theme+ClassicDark.swift in Sources */, FD37E9C628A1D4EC003AE748 /* Theme+ClassicDark.swift in Sources */,
C331FFE42558FB0000070591 /* OutlineButton.swift in Sources */, C331FFE42558FB0000070591 /* OutlineButton.swift in Sources */,
C33100142558FFC200070591 /* UIImage+Tinting.swift in Sources */,
C3310033255900A400070591 /* Notification+AppMode.swift in Sources */, C3310033255900A400070591 /* Notification+AppMode.swift in Sources */,
C331FFE92558FB0000070591 /* Separator.swift in Sources */, C331FFE92558FB0000070591 /* Separator.swift in Sources */,
C33100282559000A00070591 /* UIView+Rendering.swift in Sources */, C33100282559000A00070591 /* UIView+Rendering.swift in Sources */,
@ -5220,6 +5169,7 @@
C38EF2A5255B6D93007E1867 /* Identicon+ObjC.swift in Sources */, C38EF2A5255B6D93007E1867 /* Identicon+ObjC.swift in Sources */,
C38EF385255B6DD2007E1867 /* AttachmentTextToolbar.swift in Sources */, C38EF385255B6DD2007E1867 /* AttachmentTextToolbar.swift in Sources */,
C33FDD23255A582000E217F9 /* FeatureFlags.swift in Sources */, C33FDD23255A582000E217F9 /* FeatureFlags.swift in Sources */,
FD71161E28D9772700B47552 /* UIViewController+OWS.swift in Sources */,
C38EF389255B6DD2007E1867 /* AttachmentTextView.swift in Sources */, C38EF389255B6DD2007E1867 /* AttachmentTextView.swift in Sources */,
C38EF3FF255B6DF7007E1867 /* TappableView.swift in Sources */, C38EF3FF255B6DF7007E1867 /* TappableView.swift in Sources */,
C38EF3C2255B6DE7007E1867 /* ImageEditorPaletteView.swift in Sources */, C38EF3C2255B6DE7007E1867 /* ImageEditorPaletteView.swift in Sources */,
@ -5230,7 +5180,6 @@
C38EF30C255B6DBF007E1867 /* ScreenLock.swift in Sources */, C38EF30C255B6DBF007E1867 /* ScreenLock.swift in Sources */,
C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */, C38EF363255B6DCC007E1867 /* ModalActivityIndicatorViewController.swift in Sources */,
C38EF38A255B6DD2007E1867 /* AttachmentCaptionToolbar.swift in Sources */, C38EF38A255B6DD2007E1867 /* AttachmentCaptionToolbar.swift in Sources */,
C38EF40A255B6DF7007E1867 /* OWSFlatButton.swift in Sources */,
C33FDCD1255A582000E217F9 /* FunctionalUtil.m in Sources */, C33FDCD1255A582000E217F9 /* FunctionalUtil.m in Sources */,
C38EF402255B6DF7007E1867 /* CommonStrings.swift in Sources */, C38EF402255B6DF7007E1867 /* CommonStrings.swift in Sources */,
C38EF3C1255B6DE7007E1867 /* ImageEditorBrushViewController.swift in Sources */, C38EF3C1255B6DE7007E1867 /* ImageEditorBrushViewController.swift in Sources */,
@ -5243,7 +5192,6 @@
C33FDC29255A581F00E217F9 /* ReachabilityManager.swift in Sources */, C33FDC29255A581F00E217F9 /* ReachabilityManager.swift in Sources */,
C38EF407255B6DF7007E1867 /* Toast.swift in Sources */, C38EF407255B6DF7007E1867 /* Toast.swift in Sources */,
C38EF38C255B6DD2007E1867 /* ApprovalRailCellView.swift in Sources */, C38EF38C255B6DD2007E1867 /* ApprovalRailCellView.swift in Sources */,
C38EF32A255B6DBF007E1867 /* UIUtil.m in Sources */,
C38EF2A6255B6D93007E1867 /* PlaceholderIcon.swift in Sources */, C38EF2A6255B6D93007E1867 /* PlaceholderIcon.swift in Sources */,
C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */, C33FDD92255A582000E217F9 /* SignalIOS.pb.swift in Sources */,
C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */, C33FDC45255A581F00E217F9 /* AppVersion.m in Sources */,
@ -5254,7 +5202,6 @@
FD87DD0428B8727D00AF0F98 /* Configuration.swift in Sources */, FD87DD0428B8727D00AF0F98 /* Configuration.swift in Sources */,
C38EF3BA255B6DE7007E1867 /* ImageEditorItem.swift in Sources */, C38EF3BA255B6DE7007E1867 /* ImageEditorItem.swift in Sources */,
C38EF3F7255B6DF7007E1867 /* OWSNavigationBar.swift in Sources */, C38EF3F7255B6DF7007E1867 /* OWSNavigationBar.swift in Sources */,
C38EF248255B6D67007E1867 /* UIViewController+OWS.m in Sources */,
C33FDD3A255A582000E217F9 /* Notification+Loki.swift in Sources */, C33FDD3A255A582000E217F9 /* Notification+Loki.swift in Sources */,
7BAF54DC27ACD12B003D12F8 /* UIColor+Extensions.swift in Sources */, 7BAF54DC27ACD12B003D12F8 /* UIColor+Extensions.swift in Sources */,
C38EF370255B6DCC007E1867 /* OWSNavigationController.m in Sources */, C38EF370255B6DCC007E1867 /* OWSNavigationController.m in Sources */,
@ -5291,14 +5238,11 @@
C33FDC98255A582000E217F9 /* SwiftSingletons.swift in Sources */, C33FDC98255A582000E217F9 /* SwiftSingletons.swift in Sources */,
C38EF3B8255B6DE7007E1867 /* ImageEditorTextViewController.swift in Sources */, C38EF3B8255B6DE7007E1867 /* ImageEditorTextViewController.swift in Sources */,
C38EF40B255B6DF7007E1867 /* TappableStackView.swift in Sources */, C38EF40B255B6DF7007E1867 /* TappableStackView.swift in Sources */,
C38EF31D255B6DBF007E1867 /* UIImage+OWS.swift in Sources */,
C38EF359255B6DCC007E1867 /* SheetViewController.swift in Sources */,
C38EF386255B6DD2007E1867 /* AttachmentApprovalInputAccessoryView.swift in Sources */, C38EF386255B6DD2007E1867 /* AttachmentApprovalInputAccessoryView.swift in Sources */,
B8C2B2C82563685C00551B4D /* CircleView.swift in Sources */, B8C2B2C82563685C00551B4D /* CircleView.swift in Sources */,
C38EF331255B6DBF007E1867 /* UIGestureRecognizer+OWS.swift in Sources */, C38EF331255B6DBF007E1867 /* UIGestureRecognizer+OWS.swift in Sources */,
C33FDDC5255A582000E217F9 /* OWSError.m in Sources */, C33FDDC5255A582000E217F9 /* OWSError.m in Sources */,
FD848B9C284435D7000E298B /* AppSetup.swift in Sources */, FD848B9C284435D7000E298B /* AppSetup.swift in Sources */,
C38EF38D255B6DD2007E1867 /* AttachmentCaptionViewController.swift in Sources */,
C38EF31C255B6DBF007E1867 /* Searcher.swift in Sources */, C38EF31C255B6DBF007E1867 /* Searcher.swift in Sources */,
C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */, C38EF2B3255B6D9C007E1867 /* UIViewController+Utilities.swift in Sources */,
C38EF3BE255B6DE7007E1867 /* OrderedDictionary.swift in Sources */, C38EF3BE255B6DE7007E1867 /* OrderedDictionary.swift in Sources */,
@ -5668,7 +5612,6 @@
B83524A525C3BA4B0089A44F /* InfoMessageCell.swift in Sources */, B83524A525C3BA4B0089A44F /* InfoMessageCell.swift in Sources */,
7B9F71D82853100A006DFE7B /* EmojiWithSkinTones.swift in Sources */, 7B9F71D82853100A006DFE7B /* EmojiWithSkinTones.swift in Sources */,
B84A89BC25DE328A0040017D /* ProfilePictureVC.swift in Sources */, B84A89BC25DE328A0040017D /* ProfilePictureVC.swift in Sources */,
34386A54207D271D009F5D9C /* NeverClearView.swift in Sources */,
FDCDB8E02811007F00352A0C /* HomeViewModel.swift in Sources */, FDCDB8E02811007F00352A0C /* HomeViewModel.swift in Sources */,
7B0EFDF62755CC5400FFAAE7 /* CallMissedTipsModal.swift in Sources */, 7B0EFDF62755CC5400FFAAE7 /* CallMissedTipsModal.swift in Sources */,
C374EEF425DB31D40073A857 /* VoiceMessageRecordingView.swift in Sources */, C374EEF425DB31D40073A857 /* VoiceMessageRecordingView.swift in Sources */,
@ -5682,7 +5625,6 @@
34B0796D1FCF46B100E248C2 /* MainAppContext.m in Sources */, 34B0796D1FCF46B100E248C2 /* MainAppContext.m in Sources */,
34A8B3512190A40E00218A25 /* MediaAlbumView.swift in Sources */, 34A8B3512190A40E00218A25 /* MediaAlbumView.swift in Sources */,
FD09C5E828264937000CE219 /* MediaDetailViewController.swift in Sources */, FD09C5E828264937000CE219 /* MediaDetailViewController.swift in Sources */,
4C4AEC4520EC343B0020E72B /* DismissableTextField.swift in Sources */,
3496955E219B605E00DCFE74 /* PhotoLibrary.swift in Sources */, 3496955E219B605E00DCFE74 /* PhotoLibrary.swift in Sources */,
7B1B52E028580D51006069F2 /* EmojiSkinTonePicker.swift in Sources */, 7B1B52E028580D51006069F2 /* EmojiSkinTonePicker.swift in Sources */,
B849789625D4A2F500D0D0B3 /* LinkPreviewView.swift in Sources */, B849789625D4A2F500D0D0B3 /* LinkPreviewView.swift in Sources */,
@ -5693,7 +5635,6 @@
7BA68909272A27BE00EFC32F /* SessionCall.swift in Sources */, 7BA68909272A27BE00EFC32F /* SessionCall.swift in Sources */,
B835247925C38D880089A44F /* MessageCell.swift in Sources */, B835247925C38D880089A44F /* MessageCell.swift in Sources */,
B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */, B86BD08623399CEF000F5AE3 /* SeedModal.swift in Sources */,
34E3E5681EC4B19400495BAC /* AudioProgressView.swift in Sources */,
B8D0A26925E4A2C200C1835E /* Onboarding.swift in Sources */, B8D0A26925E4A2C200C1835E /* Onboarding.swift in Sources */,
34D1F0521F7E8EA30066283D /* GiphyDownloader.swift in Sources */, 34D1F0521F7E8EA30066283D /* GiphyDownloader.swift in Sources */,
4CC613362227A00400E21A3A /* ConversationSearch.swift in Sources */, 4CC613362227A00400E21A3A /* ConversationSearch.swift in Sources */,
@ -5709,17 +5650,14 @@
7BA6890F27325CE300EFC32F /* SessionCallManager+CXProvider.swift in Sources */, 7BA6890F27325CE300EFC32F /* SessionCallManager+CXProvider.swift in Sources */,
34BECE301F7ABCF800D7438D /* GifPickerLayout.swift in Sources */, 34BECE301F7ABCF800D7438D /* GifPickerLayout.swift in Sources */,
7B46AAAF28766DF4001AF2DC /* AllMediaViewController.swift in Sources */, 7B46AAAF28766DF4001AF2DC /* AllMediaViewController.swift in Sources */,
FD71162228D983ED00B47552 /* QRCodeScanningViewController.swift in Sources */,
C331FFFE2558FF3B00070591 /* FullConversationCell.swift in Sources */, C331FFFE2558FF3B00070591 /* FullConversationCell.swift in Sources */,
FD52090728B49738006098F6 /* ConfirmationModal.swift in Sources */, FD52090728B49738006098F6 /* ConfirmationModal.swift in Sources */,
C3DFFAC623E96F0D0058DAF8 /* Sheet.swift in Sources */,
B8D84EA325DF745A005A043E /* LinkPreviewState.swift in Sources */, B8D84EA325DF745A005A043E /* LinkPreviewState.swift in Sources */,
45C0DC1E1E69011F00E04C47 /* UIStoryboard+OWS.swift in Sources */, 45C0DC1E1E69011F00E04C47 /* UIStoryboard+OWS.swift in Sources */,
45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */,
B82B408E239DC00D00A248E7 /* DisplayNameVC.swift in Sources */, B82B408E239DC00D00A248E7 /* DisplayNameVC.swift in Sources */,
B835246E25C38ABF0089A44F /* ConversationVC.swift in Sources */, B835246E25C38ABF0089A44F /* ConversationVC.swift in Sources */,
7B7037432834B81F000DCF35 /* ReactionContainerView.swift in Sources */, 7B7037432834B81F000DCF35 /* ReactionContainerView.swift in Sources */,
B8AF4BB426A5204600583500 /* SendSeedModal.swift in Sources */,
B821494625D4D6FF009C0F2A /* URLModal.swift in Sources */,
7BBBDC462875600700747E59 /* DocumentTitleViewController.swift in Sources */, 7BBBDC462875600700747E59 /* DocumentTitleViewController.swift in Sources */,
B877E24226CA12910007970A /* CallVC.swift in Sources */, B877E24226CA12910007970A /* CallVC.swift in Sources */,
7BA6890D27325CCC00EFC32F /* SessionCallManager+CXCallController.swift in Sources */, 7BA6890D27325CCC00EFC32F /* SessionCallManager+CXCallController.swift in Sources */,
@ -5730,7 +5668,6 @@
FD37EA1928AC5CCA003AE748 /* NotificationSoundViewModel.swift in Sources */, FD37EA1928AC5CCA003AE748 /* NotificationSoundViewModel.swift in Sources */,
FD7115EE28C5D79B00B47552 /* SettingsAvatarCell.swift in Sources */, FD7115EE28C5D79B00B47552 /* SettingsAvatarCell.swift in Sources */,
4CA485BB2232339F004B9E7D /* PhotoCaptureViewController.swift in Sources */, 4CA485BB2232339F004B9E7D /* PhotoCaptureViewController.swift in Sources */,
34330AA31E79686200DF2FB9 /* OWSProgressView.m in Sources */,
C328254925CA60E60062D0A7 /* ContextMenuVC+Action.swift in Sources */, C328254925CA60E60062D0A7 /* ContextMenuVC+Action.swift in Sources */,
4542DF54208D40AC007B4E76 /* LoadingViewController.swift in Sources */, 4542DF54208D40AC007B4E76 /* LoadingViewController.swift in Sources */,
34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */, 34D5CCA91EAE3D30005515DB /* AvatarViewHelper.m in Sources */,
@ -5794,14 +5731,12 @@
FD4B200E283492210034334B /* InsetLockableTableView.swift in Sources */, FD4B200E283492210034334B /* InsetLockableTableView.swift in Sources */,
B8269D3325C7A8C600488AB4 /* InputViewButton.swift in Sources */, B8269D3325C7A8C600488AB4 /* InputViewButton.swift in Sources */,
B8269D3D25C7B34D00488AB4 /* InputTextView.swift in Sources */, B8269D3D25C7B34D00488AB4 /* InputTextView.swift in Sources */,
340FC8B6204DAC8D007AEB0F /* OWSQRCodeScanningViewController.m in Sources */,
7B0EFDF0275084AA00FFAAE7 /* CallMessageCell.swift in Sources */, 7B0EFDF0275084AA00FFAAE7 /* CallMessageCell.swift in Sources */,
FD37EA0B28AB12E2003AE748 /* SettingsCell.swift in Sources */, FD37EA0B28AB12E2003AE748 /* SettingsCell.swift in Sources */,
7B93D06A27CF173D00811CB6 /* MessageRequestsViewController.swift in Sources */, 7B93D06A27CF173D00811CB6 /* MessageRequestsViewController.swift in Sources */,
C33100082558FF6D00070591 /* NewConversationButtonSet.swift in Sources */, C33100082558FF6D00070591 /* NewConversationButtonSet.swift in Sources */,
C3AAFFF225AE99710089E6DD /* AppDelegate.swift in Sources */, C3AAFFF225AE99710089E6DD /* AppDelegate.swift in Sources */,
B8BB82A5238F627000BA5194 /* HomeVC.swift in Sources */, B8BB82A5238F627000BA5194 /* HomeVC.swift in Sources */,
C31A6C5A247F214E001123EF /* UIView+Glow.swift in Sources */,
4521C3C01F59F3BA00B4C582 /* TextFieldHelper.swift in Sources */, 4521C3C01F59F3BA00B4C582 /* TextFieldHelper.swift in Sources */,
FD37E9D128A1F2EB003AE748 /* ThemeSelectionView.swift in Sources */, FD37E9D128A1F2EB003AE748 /* ThemeSelectionView.swift in Sources */,
7B9F71D22852EEE2006DFE7B /* Emoji+SkinTones.swift in Sources */, 7B9F71D22852EEE2006DFE7B /* Emoji+SkinTones.swift in Sources */,
@ -5821,7 +5756,6 @@
FDD2506E283711D600198BDA /* DifferenceKit+Utilities.swift in Sources */, FDD2506E283711D600198BDA /* DifferenceKit+Utilities.swift in Sources */,
B897621C25D201F7004F83B2 /* ScrollToBottomButton.swift in Sources */, B897621C25D201F7004F83B2 /* ScrollToBottomButton.swift in Sources */,
346B66311F4E29B200E5122F /* CropScaleImageViewController.swift in Sources */, 346B66311F4E29B200E5122F /* CropScaleImageViewController.swift in Sources */,
45E5A6991F61E6DE001E4A8A /* MarqueeLabel.swift in Sources */,
FD1C98E4282E3C5B00B76F9E /* UINavigationBar+Utilities.swift in Sources */, FD1C98E4282E3C5B00B76F9E /* UINavigationBar+Utilities.swift in Sources */,
C302093E25DCBF08001F572D /* MentionSelectionView.swift in Sources */, C302093E25DCBF08001F572D /* MentionSelectionView.swift in Sources */,
C328251F25CA3A900062D0A7 /* QuoteView.swift in Sources */, C328251F25CA3A900062D0A7 /* QuoteView.swift in Sources */,

View File

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

View File

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

View File

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

View File

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

View File

@ -148,7 +148,7 @@ extension ConversationVC:
// MARK: - SendMediaNavDelegate // MARK: - SendMediaNavDelegate
func sendMediaNavDidCancel(_ sendMediaNavigationController: SendMediaNavigationController) { func sendMediaNavDidCancel(_ sendMediaNavigationController: SendMediaNavigationController?) {
dismiss(animated: true, completion: nil) 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?.rootViewController = self.contextMenuVC
self.contextMenuWindow?.overrideUserInterfaceStyle = (isDarkMode ? .dark : .light) self.contextMenuWindow?.overrideUserInterfaceStyle = (isDarkMode ? .dark : .light)
self.contextMenuWindow?.makeKeyAndVisible() self.contextMenuWindow?.makeKeyAndVisible()

View File

@ -137,7 +137,7 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
lazy var tableView: InsetLockableTableView = { lazy var tableView: InsetLockableTableView = {
let result: InsetLockableTableView = InsetLockableTableView() let result: InsetLockableTableView = InsetLockableTableView()
result.separatorStyle = .none result.separatorStyle = .none
result.backgroundColor = .clear result.themeBackgroundColor = .clear
result.showsVerticalScrollIndicator = false result.showsVerticalScrollIndicator = false
result.contentInsetAdjustmentBehavior = .never result.contentInsetAdjustmentBehavior = .never
result.keyboardDismissMode = .interactive result.keyboardDismissMode = .interactive
@ -257,7 +257,7 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
result.clipsToBounds = true result.clipsToBounds = true
result.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16) result.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
result.setTitle("TXT_BLOCK_USER_TITLE".localized(), for: .normal) 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) result.addTarget(self, action: #selector(block), for: .touchUpInside)
return result return result
@ -1210,7 +1210,7 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
switch section.model { switch section.model {
case .loadOlder, .loadNewer: case .loadOlder, .loadNewer:
let loadingIndicator: UIActivityIndicatorView = UIActivityIndicatorView(style: .medium) let loadingIndicator: UIActivityIndicatorView = UIActivityIndicatorView(style: .medium)
loadingIndicator.tintColor = Colors.text loadingIndicator.themeTintColor = .textPrimary
loadingIndicator.alpha = 0.5 loadingIndicator.alpha = 0.5
loadingIndicator.startAnimating() loadingIndicator.startAnimating()
@ -1386,7 +1386,7 @@ final class ConversationVC: BaseVC, ConversationSearchControllerDelegate, UITabl
let ipadCancelButton = UIButton() let ipadCancelButton = UIButton()
ipadCancelButton.setTitle("cancel".localized(), for: .normal) ipadCancelButton.setTitle("cancel".localized(), for: .normal)
ipadCancelButton.addTarget(self, action: #selector(hideSearchUI), for: .touchUpInside) ipadCancelButton.addTarget(self, action: #selector(hideSearchUI), for: .touchUpInside)
ipadCancelButton.setTitleColor(Colors.text, for: .normal) ipadCancelButton.setThemeTitleColor(.textPrimary, for: .normal)
searchBarContainer.addSubview(ipadCancelButton) searchBarContainer.addSubview(ipadCancelButton)
ipadCancelButton.pin(.trailing, to: .trailing, of: searchBarContainer) ipadCancelButton.pin(.trailing, to: .trailing, of: searchBarContainer)
ipadCancelButton.autoVCenterInSuperview() 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 { class EmojiSkinTonePicker: UIView {
let emoji: Emoji let emoji: Emoji
@ -116,12 +118,12 @@ class EmojiSkinTonePicker: UIView {
layer.shadowOpacity = 0.25 layer.shadowOpacity = 0.25
layer.shadowRadius = 4 layer.shadowRadius = 4
referenceOverlay.backgroundColor = Colors.modalBackground referenceOverlay.themeBackgroundColor = .backgroundSecondary
referenceOverlay.layer.cornerRadius = 9 referenceOverlay.layer.cornerRadius = 9
addSubview(referenceOverlay) addSubview(referenceOverlay)
containerView.layoutMargins = UIEdgeInsets(top: 9, leading: 16, bottom: 9, trailing: 16) containerView.layoutMargins = UIEdgeInsets(top: 9, leading: 16, bottom: 9, trailing: 16)
containerView.backgroundColor = Colors.modalBackground containerView.themeBackgroundColor = .backgroundSecondary
containerView.layer.cornerRadius = 11 containerView.layer.cornerRadius = 11
addSubview(containerView) addSubview(containerView)
containerView.autoPinWidthToSuperview() containerView.autoPinWidthToSuperview()
@ -129,7 +131,8 @@ class EmojiSkinTonePicker: UIView {
if emoji.baseEmoji!.allowsMultipleSkinTones { if emoji.baseEmoji!.allowsMultipleSkinTones {
prepareForMultipleSkinTones() prepareForMultipleSkinTones()
} else { }
else {
prepareForSingleSkinTone() prepareForSingleSkinTone()
} }
} }
@ -159,7 +162,7 @@ class EmojiSkinTonePicker: UIView {
let divider = UIView() let divider = UIView()
divider.autoSetDimension(.width, toSize: 1) divider.autoSetDimension(.width, toSize: 1)
divider.backgroundColor = isDarkMode ? .ows_gray75 : .ows_gray05 divider.themeBackgroundColor = .borderSeparator
hStack.addArrangedSubview(divider) hStack.addArrangedSubview(divider)
hStack.addArrangedSubview(.spacer(withWidth: 2)) hStack.addArrangedSubview(.spacer(withWidth: 2))
@ -266,7 +269,7 @@ class EmojiSkinTonePicker: UIView {
let divider = UIView() let divider = UIView()
divider.autoSetDimension(.height, toSize: 1) divider.autoSetDimension(.height, toSize: 1)
divider.backgroundColor = isDarkMode ? .ows_gray75 : .ows_gray05 divider.themeBackgroundColor = .borderSeparator
vStack.addArrangedSubview(divider) vStack.addArrangedSubview(divider)
let leftSpacer = UIView.hStretchingSpacer() let leftSpacer = UIView.hStretchingSpacer()
@ -296,7 +299,7 @@ class EmojiSkinTonePicker: UIView {
let button = OWSButton { handler(emoji) } let button = OWSButton { handler(emoji) }
button.titleLabel?.font = .boldSystemFont(ofSize: 32) button.titleLabel?.font = .boldSystemFont(ofSize: 32)
button.setTitle(emoji.rawValue, for: .normal) 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.layer.cornerRadius = 6
button.clipsToBounds = true button.clipsToBounds = true
button.autoSetDimensions(to: CGSize(width: 38, height: 38)) button.autoSetDimensions(to: CGSize(width: 38, height: 38))

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -122,7 +122,7 @@ final class ReactionListSheet: BaseVC {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
view.backgroundColor = .clear view.themeBackgroundColor = .clear
let swipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(close)) let swipeGestureRecognizer = UISwipeGestureRecognizer(target: self, action: #selector(close))
swipeGestureRecognizer.direction = .down swipeGestureRecognizer.direction = .down
@ -133,6 +133,7 @@ final class ReactionListSheet: BaseVC {
override func viewDidLayoutSubviews() { override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews() super.viewDidLayoutSubviews()
reactionContainer.scrollToItem( reactionContainer.scrollToItem(
at: IndexPath(item: lastSelectedReactionIndex, section: 0), at: IndexPath(item: lastSelectedReactionIndex, section: 0),
at: .centeredHorizontally, at: .centeredHorizontally,
@ -150,7 +151,7 @@ final class ReactionListSheet: BaseVC {
view.addSubview(contentView) view.addSubview(contentView)
contentView.pin([ UIView.HorizontalEdge.leading, UIView.HorizontalEdge.trailing, UIView.VerticalEdge.bottom ], to: view) 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 // 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) contentView.set(.height, to: contentViewHeight)
populateContentView() populateContentView()
} }
@ -163,7 +164,7 @@ final class ReactionListSheet: BaseVC {
// Seperator // Seperator
let seperator = UIView() let seperator = UIView()
seperator.backgroundColor = Colors.border.withAlphaComponent(0.1) seperator.themeBackgroundColor = .borderSeparator
seperator.set(.height, to: 0.5) seperator.set(.height, to: 0.5)
contentView.addSubview(seperator) contentView.addSubview(seperator)
seperator.pin(.leading, to: .leading, of: contentView, withInset: Values.smallSpacing) seperator.pin(.leading, to: .leading, of: contentView, withInset: Values.smallSpacing)
@ -180,7 +181,7 @@ final class ReactionListSheet: BaseVC {
// Line // Line
let line = UIView() let line = UIView()
line.set(.height, to: 0.5) line.set(.height, to: 0.5)
line.backgroundColor = Colors.border.withAlphaComponent(0.5) line.themeBackgroundColor = .borderSeparator
contentView.addSubview(line) contentView.addSubview(line)
line.pin([ UIView.HorizontalEdge.leading, UIView.HorizontalEdge.trailing ], to: contentView) line.pin([ UIView.HorizontalEdge.leading, UIView.HorizontalEdge.trailing ], to: contentView)
line.pin(.top, to: .bottom, of: stackView, withInset: Values.smallSpacing) line.pin(.top, to: .bottom, of: stackView, withInset: Values.smallSpacing)
@ -541,12 +542,12 @@ extension ReactionListSheet {
} }
fileprivate final class FooterCell: UITableViewCell { fileprivate final class FooterCell: UITableViewCell {
private lazy var label: UILabel = { private lazy var label: UILabel = {
let result = UILabel() let result: UILabel = UILabel()
result.textAlignment = .center
result.font = .systemFont(ofSize: Values.smallFontSize) result.font = .systemFont(ofSize: Values.smallFontSize)
result.textColor = Colors.grey.withAlphaComponent(0.8) result.themeTextColor = .textSecondary
result.textAlignment = .center
return result return result
}() }()
@ -554,17 +555,19 @@ extension ReactionListSheet {
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier) super.init(style: style, reuseIdentifier: reuseIdentifier)
setUpViewHierarchy() setUpViewHierarchy()
} }
required init?(coder: NSCoder) { required init?(coder: NSCoder) {
super.init(coder: coder) super.init(coder: coder)
setUpViewHierarchy() setUpViewHierarchy()
} }
private func setUpViewHierarchy() { private func setUpViewHierarchy() {
// Background color // Background color
backgroundColor = Colors.cellBackground themeBackgroundColor = .backgroundSecondary
contentView.addSubview(label) contentView.addSubview(label)
label.pin(to: contentView) label.pin(to: contentView)
@ -572,9 +575,10 @@ extension ReactionListSheet {
} }
func update(moreReactorCount: Int, emoji: String) { 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_ONE".localized(), "\(emoji)") :
String(format: "EMOJI_REACTS_MORE_REACTORS_MUTIPLE".localized(), "\(moreReactorCount)" ,"\(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. // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit import UIKit
import AVFoundation
import GRDB import GRDB
import Curve25519Kit import Curve25519Kit
import SessionUIKit import SessionUIKit
import SessionMessagingKit import SessionMessagingKit
import SessionUtilitiesKit 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 let pageVC = UIPageViewController(transitionStyle: .scroll, navigationOrientation: .horizontal, options: nil)
private var pages: [UIViewController] = [] private var pages: [UIViewController] = []
private var targetVCIndex: Int? private var targetVCIndex: Int?
@ -38,7 +40,7 @@ final class NewDMVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControlle
private lazy var scanQRCodePlaceholderVC: ScanQRCodePlaceholderVC = { private lazy var scanQRCodePlaceholderVC: ScanQRCodePlaceholderVC = {
let result = ScanQRCodePlaceholderVC() let result = ScanQRCodePlaceholderVC()
result.NewDMVC = self result.newDMVC = self
return result return result
}() }()
@ -142,7 +144,7 @@ final class NewDMVC: BaseVC, UIPageViewControllerDataSource, UIPageViewControlle
dismiss(animated: true, completion: nil) dismiss(animated: true, completion: nil)
} }
func controller(_ controller: OWSQRCodeScanningViewController, didDetectQRCodeWith string: String) { func controller(_ controller: QRCodeScanningViewController, didDetectQRCodeWith string: String) {
let hexEncodedPublicKey = string let hexEncodedPublicKey = string
startNewDMIfPossible(with: hexEncodedPublicKey) startNewDMIfPossible(with: hexEncodedPublicKey)
} }
@ -450,7 +452,7 @@ private final class EnterPublicKeyVC: UIViewController {
// MARK: - ScanQRCodePlaceholderVC // MARK: - ScanQRCodePlaceholderVC
private final class ScanQRCodePlaceholderVC: UIViewController { private final class ScanQRCodePlaceholderVC: UIViewController {
weak var NewDMVC: NewDMVC! weak var newDMVC: NewDMVC!
override func viewDidLoad() { override func viewDidLoad() {
// Remove background color // Remove background color
@ -493,12 +495,8 @@ private final class ScanQRCodePlaceholderVC: UIViewController {
} }
@objc private func requestCameraAccess() { @objc private func requestCameraAccess() {
ows_ask(forCameraPermissions: { [weak self] hasCameraAccess in Permissions.requestLibraryPermissionIfNeeded { [weak self] in
if hasCameraAccess { self?.newDMVC.handleCameraAccessGranted()
self?.NewDMVC.handleCameraAccessGranted() }
} else {
// Do nothing
}
})
} }
} }

View File

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

View File

@ -12,9 +12,11 @@ public class AllMediaViewController: UIViewController, UIPageViewControllerDataS
private var pages: [UIViewController] = [] private var pages: [UIViewController] = []
private var targetVCIndex: Int? private var targetVCIndex: Int?
// MARK: Components // MARK: - Components
private lazy var tabBar: TabBar = { private lazy var tabBar: TabBar = {
let tabs = [ let result: TabBar = TabBar(
tabs: [
TabBar.Tab(title: MediaStrings.media) { [weak self] in TabBar.Tab(title: MediaStrings.media) { [weak self] in
guard let self = self else { return } guard let self = self else { return }
self.pageVC.setViewControllers([ self.pages[0] ], direction: .forward, animated: false, completion: nil) self.pageVC.setViewControllers([ self.pages[0] ], direction: .forward, animated: false, completion: nil)
@ -27,7 +29,10 @@ public class AllMediaViewController: UIViewController, UIPageViewControllerDataS
self.navigationItem.rightBarButtonItem = nil self.navigationItem.rightBarButtonItem = nil
} }
] ]
return TabBar(tabs: tabs) )
result.themeBackgroundColor = .backgroundPrimary
return result
}() }()
private var mediaTitleViewController: MediaTileViewController private var mediaTitleViewController: MediaTileViewController
@ -54,11 +59,11 @@ public class AllMediaViewController: UIViewController, UIPageViewControllerDataS
public override func viewDidLoad() { public override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
view.themeBackgroundColor = .backgroundPrimary view.themeBackgroundColor = .backgroundSecondary
// Add a custom back button if this is the only view controller // Add a custom back button if this is the only view controller
if self.navigationController?.viewControllers.first == self { 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 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 Foundation
import MediaPlayer import MediaPlayer
import SessionUIKit
import SignalUtilitiesKit import SignalUtilitiesKit
// This kind of view is tricky. I've tried to organize things in the // This kind of view is tricky. I've tried to organize things in the
@ -145,14 +146,38 @@ import SignalUtilitiesKit
// MARK: - Create Views // MARK: - Create Views
private func createViews() { private func createViews() {
view.themeBackgroundColor = .backgroundPrimary
view.backgroundColor = .black
let contentView = UIView() let contentView = UIView()
contentView.backgroundColor = .black contentView.themeBackgroundColor = .backgroundPrimary
self.view.addSubview(contentView) self.view.addSubview(contentView)
contentView.autoPinEdgesToSuperviewEdges() 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 let imageView = OWSLayerView(frame: CGRect.zero, layoutCallback: { [weak self] _ in
guard let strongSelf = self else { return } guard let strongSelf = self else { return }
strongSelf.updateImageLayout() strongSelf.updateImageLayout()
@ -160,7 +185,10 @@ import SignalUtilitiesKit
imageView.clipsToBounds = true imageView.clipsToBounds = true
self.imageView = imageView self.imageView = imageView
contentView.addSubview(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() let imageLayer = CALayer()
self.imageLayer = imageLayer self.imageLayer = imageLayer
@ -185,23 +213,13 @@ import SignalUtilitiesKit
layer.path = path.cgPath layer.path = path.cgPath
layer.fillRule = .evenOdd layer.fillRule = .evenOdd
layer.fillColor = UIColor.black.cgColor layer.themeFillColor = .black
layer.opacity = 0.75 layer.opacity = 0.75
} }
maskingView.autoPinEdgesToSuperviewEdges() maskingView.pin(.top, to: .top, of: contentView, withInset: (Values.massiveSpacing + Values.smallSpacing))
maskingView.pin(.leading, to: .leading, of: contentView)
let titleLabel = UILabel() maskingView.pin(.trailing, to: .trailing, of: contentView)
titleLabel.textColor = .white maskingView.pin(.bottom, to: .top, of: buttonRow)
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)
contentView.isUserInteractionEnabled = true contentView.isUserInteractionEnabled = true
contentView.addGestureRecognizer(UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(sender:)))) contentView.addGestureRecognizer(UIPinchGestureRecognizer(target: self, action: #selector(handlePinch(sender:))))
@ -427,45 +445,35 @@ import SignalUtilitiesKit
updateImageLayout() updateImageLayout()
} }
private func createButtonRow(contentView: UIView) { private func createButtonRow() -> UIView {
let buttonTopMargin = ScaleFromIPhone5To7Plus(30, 40) let result: UIStackView = UIStackView()
let buttonBottomMargin = ScaleFromIPhone5To7Plus(25, 40) result.axis = .horizontal
result.distribution = .fillEqually
result.alignment = .fill
let buttonRow = UIView() let cancelButton = createButton(title: CommonStrings.cancelButton, action: #selector(cancelPressed))
self.view.addSubview(buttonRow) result.addArrangedSubview(cancelButton)
buttonRow.autoPinWidthToSuperview()
buttonRow.autoPinEdge(toSuperviewEdge: .bottom, withInset: buttonBottomMargin)
buttonRow.autoPinEdge(.top, to: .bottom, of: contentView, withOffset: buttonTopMargin)
let cancelButton = createButton(title: CommonStrings.cancelButton, let doneButton = createButton(title: CommonStrings.doneButton, action: #selector(donePressed))
action: #selector(cancelPressed)) result.addArrangedSubview(doneButton)
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, return result
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)
} }
private func createButton(title: String, action: Selector) -> UIButton { private func createButton(title: String, action: Selector) -> UIButton {
let buttonFont = UIFont.ows_mediumFont(withSize: ScaleFromIPhone5To7Plus(18, 22)) let button: UIButton = UIButton()
let buttonWidth = ScaleFromIPhone5To7Plus(110, 140) button.titleLabel?.font = .systemFont(ofSize: 18)
let buttonHeight = ScaleFromIPhone5To7Plus(35, 45)
let button = UIButton()
button.setTitle(title, for: .normal) button.setTitle(title, for: .normal)
button.setTitleColor(UIColor.white, for: .normal) button.setThemeTitleColor(.textPrimary, for: .normal)
button.titleLabel!.font = buttonFont 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.addTarget(self, action: action, for: .touchUpInside)
button.autoSetDimension(.width, toSize: buttonWidth)
button.autoSetDimension(.height, toSize: buttonHeight)
return button return button
} }

View File

@ -49,8 +49,8 @@ public class DocumentTileViewController: UIViewController, UITableViewDelegate,
} }
lazy var tableView: UITableView = { lazy var tableView: UITableView = {
let result = UITableView(frame: .zero, style: .grouped) let result: UITableView = UITableView()
result.backgroundColor = Colors.navigationBarBackground result.themeBackgroundColor = .backgroundSecondary
result.separatorStyle = .none result.separatorStyle = .none
result.showsVerticalScrollIndicator = false result.showsVerticalScrollIndicator = false
result.register(view: DocumentCell.self) 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. // 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) result.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: 20, right: 0)
if #available(iOS 15.0, *) {
result.sectionHeaderTopPadding = 0
}
return result return result
}() }()
@ -69,7 +73,7 @@ public class DocumentTileViewController: UIViewController, UITableViewDelegate,
// Add a custom back button if this is the only view controller // Add a custom back button if this is the only view controller
if self.navigationController?.viewControllers.first == self { 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 self.navigationItem.leftBarButtonItem = backButton
} }
@ -363,7 +367,8 @@ class DocumentCell: UITableViewCell {
private let iconImageView: UIImageView = { private let iconImageView: UIImageView = {
let result: UIImageView = UIImageView(image: #imageLiteral(resourceName: "File").withRenderingMode(.alwaysTemplate)) let result: UIImageView = UIImageView(image: #imageLiteral(resourceName: "File").withRenderingMode(.alwaysTemplate))
result.translatesAutoresizingMaskIntoConstraints = false result.translatesAutoresizingMaskIntoConstraints = false
result.tintColor = Colors.text result.themeTintColor = .textPrimary
result.contentMode = .scaleAspectFit
return result return result
}() }()
@ -374,7 +379,20 @@ class DocumentCell: UITableViewCell {
result.setContentHuggingPriority(.defaultHigh, for: .horizontal) result.setContentHuggingPriority(.defaultHigh, for: .horizontal)
result.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) result.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
result.font = .boldSystemFont(ofSize: Values.smallFontSize) 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 result.lineBreakMode = .byTruncatingTail
return result return result
@ -386,20 +404,26 @@ class DocumentCell: UITableViewCell {
result.setContentHuggingPriority(.defaultHigh, for: .horizontal) result.setContentHuggingPriority(.defaultHigh, for: .horizontal)
result.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) result.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
result.font = .systemFont(ofSize: Values.smallFontSize) result.font = .systemFont(ofSize: Values.smallFontSize)
result.textColor = Colors.text result.themeTextColor = .textSecondary
result.lineBreakMode = .byTruncatingTail result.lineBreakMode = .byTruncatingTail
return result return result
}() }()
private func setUpViewHierarchy() { private func setUpViewHierarchy() {
backgroundColor = Colors.cellBackground themeBackgroundColor = .clear
selectedBackgroundView = UIView()
selectedBackgroundView?.backgroundColor = Colors.cellSelected
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(iconImageView)
contentView.addSubview(titleLabel) contentView.addSubview(titleLabel)
contentView.addSubview(timeLabel)
contentView.addSubview(detailLabel) contentView.addSubview(detailLabel)
} }
@ -407,57 +431,110 @@ class DocumentCell: UITableViewCell {
private func setupLayout() { private func setupLayout() {
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
contentView.heightAnchor.constraint(equalToConstant: 68),
iconImageView.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: Values.mediumSpacing),
iconImageView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor), iconImageView.centerYAnchor.constraint(equalTo: contentView.centerYAnchor),
iconImageView.widthAnchor.constraint(equalToConstant: Self.iconImageViewSize.width), iconImageView.topAnchor.constraint(
iconImageView.heightAnchor.constraint(equalToConstant: Self.iconImageViewSize.height), 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.leftAnchor.constraint(equalTo: iconImageView.rightAnchor, constant: Values.mediumSpacing),
titleLabel.rightAnchor.constraint(lessThanOrEqualTo: contentView.rightAnchor, constant: -Values.mediumSpacing), titleLabel.rightAnchor.constraint(
titleLabel.topAnchor.constraint(equalTo: iconImageView.topAnchor), 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.leftAnchor.constraint(equalTo: iconImageView.rightAnchor, constant: Values.mediumSpacing),
detailLabel.rightAnchor.constraint(lessThanOrEqualTo: contentView.rightAnchor, constant: -Values.mediumSpacing), detailLabel.rightAnchor.constraint(
detailLabel.bottomAnchor.constraint(equalTo: iconImageView.bottomAnchor), 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 // MARK: - Content
func update(with item: MediaGalleryViewModel.Item) { func update(with item: MediaGalleryViewModel.Item) {
let attachment = item.attachment let attachment = item.attachment
titleLabel.text = attachment.sourceFilename ?? "File" titleLabel.text = (attachment.sourceFilename ?? "File")
detailLabel.text = "\(OWSFormat.formatFileSize(UInt(attachment.byteCount)))" detailLabel.text = "\(OWSFormat.formatFileSize(UInt(attachment.byteCount)))"
timeLabel.text = Date(
timeIntervalSince1970: TimeInterval(item.interactionTimestampMs / 1000)
).formattedForDisplay
} }
} }
class DocumentSectionHeaderView: UIView { 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 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) { override init(frame: CGRect) {
label = UILabel() label = UILabel()
label.textColor = Colors.text label.themeTextColor = .textPrimary
let blurEffect = UIBlurEffect(style: .dark)
let blurEffectView = UIVisualEffectView(effect: blurEffect)
blurEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
super.init(frame: frame) 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) self.addSubview(label)
label.pin(.leading, to: .leading, of: self, withInset: Values.largeSpacing)
blurEffectView.autoPinEdgesToSuperviewEdges() label.pin(.trailing, to: .trailing, of: self, withInset: -Values.largeSpacing)
blurEffectView.isHidden = isLightMode label.center(.vertical, in: self)
label.autoPinEdge(toSuperviewMargin: .trailing)
label.autoPinEdge(toSuperviewMargin: .leading)
label.autoVCenterInSuperview()
} }
@available(*, unavailable, message: "Unimplemented") @available(*, unavailable, message: "Unimplemented")
@ -479,7 +556,7 @@ class DocumentStaticHeaderView: UIView {
addSubview(label) addSubview(label)
label.textColor = Colors.text label.themeTextColor = .textPrimary
label.textAlignment = .center label.textAlignment = .center
label.numberOfLines = 0 label.numberOfLines = 0
label.autoPinEdgesToSuperviewMargins(with: UIEdgeInsets(top: 0, leading: Values.largeSpacing, bottom: 0, trailing: Values.largeSpacing)) label.autoPinEdgesToSuperviewMargins(with: UIEdgeInsets(top: 0, leading: Values.largeSpacing, bottom: 0, trailing: Values.largeSpacing))

View File

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

View File

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

View File

@ -6,6 +6,7 @@ import Foundation
import Photos import Photos
import PromiseKit import PromiseKit
import SessionUIKit import SessionUIKit
import SignalUtilitiesKit
protocol ImagePickerGridControllerDelegate: AnyObject { protocol ImagePickerGridControllerDelegate: AnyObject {
func imagePickerDidCompleteSelection(_ imagePicker: ImagePickerGridController) func imagePickerDidCompleteSelection(_ imagePicker: ImagePickerGridController)
@ -48,7 +49,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
self.view.backgroundColor = Colors.navigationBarBackground self.view.themeBackgroundColor = .backgroundSecondary
library.add(delegate: self) library.add(delegate: self)
@ -71,7 +72,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
let cancelImage = UIImage(imageLiteralResourceName: "X") let cancelImage = UIImage(imageLiteralResourceName: "X")
let cancelButton = UIBarButtonItem(image: cancelImage, style: .plain, target: self, action: #selector(didPressCancel)) let cancelButton = UIBarButtonItem(image: cancelImage, style: .plain, target: self, action: #selector(didPressCancel))
cancelButton.tintColor = Colors.text cancelButton.themeTintColor = .textPrimary
navigationItem.leftBarButtonItem = cancelButton navigationItem.leftBarButtonItem = cancelButton
let titleView = TitleView() let titleView = TitleView()
@ -80,7 +81,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
navigationItem.titleView = titleView navigationItem.titleView = titleView
self.titleView = titleView self.titleView = titleView
collectionView.backgroundColor = Colors.navigationBarBackground collectionView.themeBackgroundColor = .backgroundSecondary
let selectionPanGesture = DirectionalPanGestureRecognizer(direction: [.horizontal], target: self, action: #selector(didPanSelection)) let selectionPanGesture = DirectionalPanGestureRecognizer(direction: [.horizontal], target: self, action: #selector(didPanSelection))
selectionPanGesture.delegate = self selectionPanGesture.delegate = self
@ -105,7 +106,9 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
enum BatchSelectionGestureMode { enum BatchSelectionGestureMode {
case select, deselect case select, deselect
} }
var selectionPanGestureMode: BatchSelectionGestureMode = .select var selectionPanGestureMode: BatchSelectionGestureMode = .select
var hasEverAppeared: Bool = false
@objc @objc
func didPanSelection(_ selectionPanGesture: UIPanGestureRecognizer) { func didPanSelection(_ selectionPanGesture: UIPanGestureRecognizer) {
@ -190,20 +193,9 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
updateLayout() updateLayout()
} }
var hasEverAppeared: Bool = false
override func viewWillAppear(_ animated: Bool) { override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated) 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 // Determine the size of the thumbnails to request
let scale = UIScreen.main.scale let scale = UIScreen.main.scale
let cellSize = collectionViewFlowLayout.itemSize let cellSize = collectionViewFlowLayout.itemSize
@ -362,9 +354,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
// MARK: - Batch Selection // MARK: - Batch Selection
func batchSelectModeDidChange() { func batchSelectModeDidChange() {
guard let delegate = delegate else { guard let delegate = delegate else { return }
return
}
guard let collectionView = collectionView else { guard let collectionView = collectionView else {
owsFailDebug("collectionView was unexpectedly nil") owsFailDebug("collectionView was unexpectedly nil")
@ -397,7 +387,7 @@ class ImagePickerGridController: UICollectionViewController, PhotoLibraryDelegat
let toastText = String(format: toastFormat, NSNumber(value: SignalAttachment.maxAttachmentsAllowed)) 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 kToastInset: CGFloat = 10
let bottomInset = kToastInset + collectionView.contentInset.bottom + view.layoutMargins.bottom 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) 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) let assetItem = photoCollectionContents.assetItem(at: indexPath.item, photoMediaSize: photoMediaSize)
cell.configure(item: assetItem) cell.configure(item: assetItem)
@ -587,11 +575,11 @@ class TitleView: UIView {
addSubview(stackView) addSubview(stackView)
stackView.autoPinEdgesToSuperviewEdges() stackView.autoPinEdgesToSuperviewEdges()
label.textColor = Colors.text
label.font = .boldSystemFont(ofSize: Values.mediumFontSize) label.font = .boldSystemFont(ofSize: Values.mediumFontSize)
label.themeTextColor = .textPrimary
iconView.tintColor = Colors.text
iconView.image = UIImage(named: "navbar_disclosure_down")?.withRenderingMode(.alwaysTemplate) iconView.image = UIImage(named: "navbar_disclosure_down")?.withRenderingMode(.alwaysTemplate)
iconView.themeTintColor = .textPrimary
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(titleTapped))) addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(titleTapped)))
} }

View File

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

View File

@ -16,7 +16,7 @@ class MediaGalleryNavigationController: OWSNavigationController {
private lazy var backgroundView: UIView = { private lazy var backgroundView: UIView = {
let result: UIView = UIView() let result: UIView = UIView()
result.backgroundColor = Colors.navigationBarBackground result.themeBackgroundColor = .backgroundSecondary
return result return result
}() }()
@ -28,17 +28,7 @@ class MediaGalleryNavigationController: OWSNavigationController {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
guard let navigationBar = self.navigationBar as? OWSNavigationBar else { view.themeBackgroundColor = .backgroundSecondary
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
// Insert a view to ensure the nav bar colour goes to the top of the screen // Insert a view to ensure the nav bar colour goes to the top of the screen
relayoutBackgroundView() relayoutBackgroundView()

View File

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

View File

@ -33,6 +33,17 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
return 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) updateTitle(item: item)
updateCaption(item: item) updateCaption(item: item)
setViewControllers([galleryPage], direction: direction, animated: isAnimated) setViewControllers([galleryPage], direction: direction, animated: isAnimated)
@ -93,12 +104,12 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
var footerBar: UIToolbar = { var footerBar: UIToolbar = {
let result: UIToolbar = UIToolbar() let result: UIToolbar = UIToolbar()
result.clipsToBounds = true // hide 1px top-border result.clipsToBounds = true // hide 1px top-border
result.tintColor = Colors.text result.themeTintColor = .textPrimary
result.barTintColor = Colors.navigationBarBackground result.themeBarTintColor = .backgroundPrimary
result.themeBackgroundColor = .backgroundPrimary
result.setBackgroundImage(UIImage(), forToolbarPosition: .any, barMetrics: UIBarMetrics.default) result.setBackgroundImage(UIImage(), forToolbarPosition: .any, barMetrics: UIBarMetrics.default)
result.setShadowImage(UIImage(), forToolbarPosition: .any) result.setShadowImage(UIImage(), forToolbarPosition: .any)
result.isTranslucent = false result.isTranslucent = false
result.backgroundColor = Colors.navigationBarBackground
return result return result
}() }()
@ -115,7 +126,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
// Navigation // 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.leftBarButtonItem = backButton
self.navigationItem.titleView = portraitHeaderView self.navigationItem.titleView = portraitHeaderView
@ -154,9 +165,9 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
} }
// Views // Views
pagerScrollView.backgroundColor = Colors.navigationBarBackground pagerScrollView.themeBackgroundColor = .backgroundSecondary
view.backgroundColor = Colors.navigationBarBackground view.themeBackgroundColor = .backgroundSecondary
captionContainerView.delegate = self captionContainerView.delegate = self
updateCaptionContainerVisibility() updateCaptionContainerVisibility()
@ -169,7 +180,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
let bottomContainer: DynamicallySizedView = DynamicallySizedView() let bottomContainer: DynamicallySizedView = DynamicallySizedView()
bottomContainer.clipsToBounds = true bottomContainer.clipsToBounds = true
bottomContainer.autoresizingMask = .flexibleHeight bottomContainer.autoresizingMask = .flexibleHeight
bottomContainer.backgroundColor = Colors.navigationBarBackground bottomContainer.themeBackgroundColor = .backgroundPrimary
self.bottomContainer = bottomContainer self.bottomContainer = bottomContainer
let bottomStack = UIStackView(arrangedSubviews: [captionContainerView, galleryRailView, footerBar]) let bottomStack = UIStackView(arrangedSubviews: [captionContainerView, galleryRailView, footerBar])
@ -179,7 +190,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
bottomStack.autoPinEdgesToSuperviewEdges() bottomStack.autoPinEdgesToSuperviewEdges()
let galleryRailBlockingView: UIView = UIView() let galleryRailBlockingView: UIView = UIView()
galleryRailBlockingView.backgroundColor = Colors.navigationBarBackground galleryRailBlockingView.themeBackgroundColor = .backgroundPrimary
bottomStack.addSubview(galleryRailBlockingView) bottomStack.addSubview(galleryRailBlockingView)
galleryRailBlockingView.pin(.top, to: .bottom, of: footerBar) galleryRailBlockingView.pin(.top, to: .bottom, of: footerBar)
galleryRailBlockingView.pin(.left, to: .left, of: bottomStack) galleryRailBlockingView.pin(.left, to: .left, of: bottomStack)
@ -197,12 +208,6 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
verticalSwipe.direction = [.up, .down] verticalSwipe.direction = [.up, .down]
view.addGestureRecognizer(verticalSwipe) view.addGestureRecognizer(verticalSwipe)
let navigationBar = navigationController!.navigationBar
navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
navigationBar.shadowImage = UIImage()
navigationBar.isTranslucent = false
navigationBar.barTintColor = Colors.navigationBarBackground
// Notifications // Notifications
NotificationCenter.default.addObserver( NotificationCenter.default.addObserver(
self, self,
@ -316,7 +321,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
target: self, target: self,
action: #selector(didPressShare) action: #selector(didPressShare)
) )
shareBarButton.tintColor = Colors.text shareBarButton.themeTintColor = .textPrimary
return shareBarButton return shareBarButton
}() }()
@ -327,7 +332,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
target: self, target: self,
action: #selector(didPressDelete) action: #selector(didPressDelete)
) )
deleteBarButton.tintColor = Colors.text deleteBarButton.themeTintColor = .textPrimary
return deleteBarButton return deleteBarButton
}() }()
@ -342,7 +347,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
target: self, target: self,
action: #selector(didPressPlayBarButton) action: #selector(didPressPlayBarButton)
) )
videoPlayBarButton.tintColor = Colors.text videoPlayBarButton.themeTintColor = .textPrimary
return videoPlayBarButton return videoPlayBarButton
}() }()
@ -353,7 +358,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
target: self, target: self,
action: #selector(didPressPauseBarButton) action: #selector(didPressPauseBarButton)
) )
videoPauseBarButton.tintColor = Colors.text videoPauseBarButton.themeTintColor = .textPrimary
return videoPauseBarButton return videoPauseBarButton
}() }()
@ -818,9 +823,9 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
}() }()
lazy private var portraitHeaderNameLabel: UILabel = { lazy private var portraitHeaderNameLabel: UILabel = {
let label = UILabel() let label: UILabel = UILabel()
label.textColor = Colors.text
label.font = .systemFont(ofSize: Values.mediumFontSize) label.font = .systemFont(ofSize: Values.mediumFontSize)
label.themeTextColor = .textPrimary
label.textAlignment = .center label.textAlignment = .center
label.adjustsFontSizeToFitWidth = true label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.8 label.minimumScaleFactor = 0.8
@ -829,9 +834,9 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
}() }()
lazy private var portraitHeaderDateLabel: UILabel = { lazy private var portraitHeaderDateLabel: UILabel = {
let label = UILabel() let label: UILabel = UILabel()
label.textColor = Colors.text
label.font = .systemFont(ofSize: Values.verySmallFontSize) label.font = .systemFont(ofSize: Values.verySmallFontSize)
label.themeTextColor = .textPrimary
label.textAlignment = .center label.textAlignment = .center
label.adjustsFontSizeToFitWidth = true label.adjustsFontSizeToFitWidth = true
label.minimumScaleFactor = 0.8 label.minimumScaleFactor = 0.8
@ -840,7 +845,7 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
}() }()
private lazy var portraitHeaderView: UIView = { private lazy var portraitHeaderView: UIView = {
let stackView = UIStackView() let stackView: UIStackView = UIStackView()
stackView.axis = .vertical stackView.axis = .vertical
stackView.alignment = .center stackView.alignment = .center
stackView.spacing = 0 stackView.spacing = 0
@ -915,12 +920,15 @@ class MediaPageViewController: UIPageViewController, UIPageViewControllerDataSou
extension MediaGalleryViewModel.Item: GalleryRailItem { extension MediaGalleryViewModel.Item: GalleryRailItem {
public func buildRailItemView() -> UIView { public func buildRailItemView() -> UIView {
let imageView = UIImageView() let imageView: UIImageView = UIImageView()
imageView.contentMode = .scaleAspectFill imageView.contentMode = .scaleAspectFill
getRailImage().map { [weak imageView] image in
getRailImage()
.map { [weak imageView] image in
guard let imageView = imageView else { return } guard let imageView = imageView else { return }
imageView.image = image imageView.image = image
}.retainUntilComplete() }
.retainUntilComplete()
return imageView return imageView
} }

View File

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

View File

@ -3,6 +3,7 @@
// //
import Foundation import Foundation
import AVFoundation
import PromiseKit import PromiseKit
import CoreServices import CoreServices
@ -54,9 +55,9 @@ class PhotoCapture: NSObject {
self.session.beginConfiguration() self.session.beginConfiguration()
defer { self.session.commitConfiguration() } 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 // verify works without audio permissions
let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice!) let audioDeviceInput = try AVCaptureDeviceInput(device: audioDevice)
if session.canAddInput(audioDeviceInput) { if session.canAddInput(audioDeviceInput) {
// self.session.addInputWithNoConnections(audioDeviceInput) // self.session.addInputWithNoConnections(audioDeviceInput)
session.addInput(audioDeviceInput) session.addInput(audioDeviceInput)

View File

@ -1,10 +1,10 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved. // Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
import Foundation import UIKit
import AVFoundation import AVFoundation
import PromiseKit import PromiseKit
import SessionUIKit
import SignalUtilitiesKit
protocol PhotoCaptureViewControllerDelegate: AnyObject { protocol PhotoCaptureViewControllerDelegate: AnyObject {
func photoCaptureViewController(_ photoCaptureViewController: PhotoCaptureViewController, didFinishProcessingAttachment attachment: SignalAttachment) func photoCaptureViewController(_ photoCaptureViewController: PhotoCaptureViewController, didFinishProcessingAttachment attachment: SignalAttachment)
@ -49,7 +49,7 @@ class PhotoCaptureViewController: OWSViewController {
override func loadView() { override func loadView() {
self.view = UIView() self.view = UIView()
self.view.backgroundColor = .black self.view.themeBackgroundColor = .backgroundSecondary
} }
override func viewDidLoad() { override func viewDidLoad() {
@ -82,7 +82,8 @@ class PhotoCaptureViewController: OWSViewController {
navigationItem.rightBarButtonItems = nil navigationItem.rightBarButtonItems = nil
navigationItem.titleView = recordingTimerView navigationItem.titleView = recordingTimerView
recordingTimerView.sizeToFit() recordingTimerView.sizeToFit()
} else { }
else {
navigationItem.titleView = nil navigationItem.titleView = nil
navigationItem.leftBarButtonItem = dismissControl.barButtonItem navigationItem.leftBarButtonItem = dismissControl.barButtonItem
let fixedSpace = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil) let fixedSpace = UIBarButtonItem(barButtonSystemItem: .fixedSpace, target: nil, action: nil)
@ -114,8 +115,9 @@ class PhotoCaptureViewController: OWSViewController {
let barButtonItem: UIBarButtonItem let barButtonItem: UIBarButtonItem
init(imageName: String, block: @escaping () -> Void) { 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.autoPinToSquareAspectRatio()
button.themeShadowColor = .black
button.layer.shadowOffset = CGSize.zero button.layer.shadowOffset = CGSize.zero
button.layer.shadowOpacity = 0.35 button.layer.shadowOpacity = 0.35
button.layer.shadowRadius = 4 button.layer.shadowRadius = 4
@ -222,10 +224,12 @@ class PhotoCaptureViewController: OWSViewController {
private func setupOrientationMonitoring() { private func setupOrientationMonitoring() {
UIDevice.current.beginGeneratingDeviceOrientationNotifications() UIDevice.current.beginGeneratingDeviceOrientationNotifications()
NotificationCenter.default.addObserver(self, NotificationCenter.default.addObserver(
self,
selector: #selector(didChangeDeviceOrientation), selector: #selector(didChangeDeviceOrientation),
name: UIDevice.orientationDidChangeNotification, name: UIDevice.orientationDidChangeNotification,
object: UIDevice.current) object: UIDevice.current
)
} }
var lastKnownCaptureOrientation: AVCaptureVideoOrientation = .portrait var lastKnownCaptureOrientation: AVCaptureVideoOrientation = .portrait
@ -282,15 +286,14 @@ class PhotoCaptureViewController: OWSViewController {
captureButton.delegate = photoCapture captureButton.delegate = photoCapture
previewView = CapturePreviewView(session: photoCapture.session) previewView = CapturePreviewView(session: photoCapture.session)
photoCapture.startCapture().done { [weak self] in photoCapture.startCapture()
guard let self = self else { return } .done { [weak self] in
self?.showCaptureUI()
self.showCaptureUI() }
}.catch { [weak self] error in .catch { [weak self] error in
guard let self = self else { return } self?.showFailureUI(error: error)
}
self.showFailureUI(error: error) .retainUntilComplete()
}.retainUntilComplete()
} }
private func showCaptureUI() { private func showCaptureUI() {
@ -309,11 +312,17 @@ class PhotoCaptureViewController: OWSViewController {
private func showFailureUI(error: Error) { private func showFailureUI(error: Error) {
Logger.error("error: \(error)") Logger.error("error: \(error)")
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) }
)
)
OWSAlerts.showAlert(title: nil, present(modal, animated: true)
message: error.localizedDescription,
buttonTitle: CommonStrings.dismissButton,
buttonAction: { [weak self] _ in self?.dismiss(animated: true) })
} }
private func updateFlashModeControl() { private func updateFlashModeControl() {
@ -421,16 +430,17 @@ class CaptureButton: UIView {
addSubview(innerButton) addSubview(innerButton)
innerButtonSizeConstraints = autoSetDimensions(to: CGSize(width: defaultDiameter, height: defaultDiameter)) 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.shadowOffset = .zero
innerButton.layer.shadowOpacity = 0.33 innerButton.layer.shadowOpacity = 0.33
innerButton.layer.shadowRadius = 2 innerButton.layer.shadowRadius = 2
innerButton.alpha = 0.33
innerButton.autoPinEdgesToSuperviewEdges() innerButton.autoPinEdgesToSuperviewEdges()
addSubview(zoomIndicator) addSubview(zoomIndicator)
zoomIndicatorSizeConstraints = zoomIndicator.autoSetDimensions(to: CGSize(width: defaultDiameter, height: defaultDiameter)) zoomIndicatorSizeConstraints = zoomIndicator.autoSetDimensions(to: CGSize(width: defaultDiameter, height: defaultDiameter))
zoomIndicator.isUserInteractionEnabled = false zoomIndicator.isUserInteractionEnabled = false
zoomIndicator.layer.borderColor = UIColor.ows_white.cgColor zoomIndicator.themeBorderColor = .white
zoomIndicator.layer.borderWidth = 1.5 zoomIndicator.layer.borderWidth = 1.5
zoomIndicator.autoAlignAxis(.horizontal, toSameAxisOf: innerButton) zoomIndicator.autoAlignAxis(.horizontal, toSameAxisOf: innerButton)
zoomIndicator.autoAlignAxis(.vertical, toSameAxisOf: innerButton) zoomIndicator.autoAlignAxis(.vertical, toSameAxisOf: innerButton)
@ -569,10 +579,10 @@ class RecordingTimerView: UIView {
// MARK: - Subviews // MARK: - Subviews
private lazy var label: UILabel = { private lazy var label: UILabel = {
let label = UILabel() let label: UILabel = UILabel()
label.font = UIFont.ows_monospacedDigitFont(withSize: 20) label.font = .ows_monospacedDigitFont(withSize: 20)
label.themeTextColor = .textPrimary
label.textAlignment = .center label.textAlignment = .center
label.textColor = UIColor.white
label.layer.shadowOffset = CGSize.zero label.layer.shadowOffset = CGSize.zero
label.layer.shadowOpacity = 0.35 label.layer.shadowOpacity = 0.35
label.layer.shadowRadius = 4 label.layer.shadowRadius = 4
@ -587,8 +597,7 @@ class RecordingTimerView: UIView {
icon.layer.shadowOffset = CGSize.zero icon.layer.shadowOffset = CGSize.zero
icon.layer.shadowOpacity = 0.35 icon.layer.shadowOpacity = 0.35
icon.layer.shadowRadius = 4 icon.layer.shadowRadius = 4
icon.themeBackgroundColor = .danger
icon.backgroundColor = .red
icon.autoSetDimensions(to: CGSize(width: iconWidth, height: iconWidth)) icon.autoSetDimensions(to: CGSize(width: iconWidth, height: iconWidth))
icon.alpha = 0 icon.alpha = 0
@ -601,10 +610,12 @@ class RecordingTimerView: UIView {
func startCounting() { func startCounting() {
recordingStartTime = CACurrentMediaTime() recordingStartTime = CACurrentMediaTime()
timer = Timer.weakScheduledTimer(withTimeInterval: 0.1, target: self, selector: #selector(updateView), userInfo: nil, repeats: true) timer = Timer.weakScheduledTimer(withTimeInterval: 0.1, target: self, selector: #selector(updateView), userInfo: nil, repeats: true)
UIView.animate(withDuration: 0.5, UIView.animate(
withDuration: 0.5,
delay: 0, delay: 0,
options: [.autoreverse, .repeat], options: [.autoreverse, .repeat],
animations: { self.icon.alpha = 1 }) animations: { self.icon.alpha = 1 }
)
} }
func stopCounting() { 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 videoBadgeImage = #imageLiteral(resourceName: "ic_gallery_badge_video")
private static let animatedBadgeImage = #imageLiteral(resourceName: "ic_gallery_badge_gif") 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 { override public var isSelected: Bool {
didSet { didSet {
@ -52,18 +52,23 @@ public class PhotoGridViewCell: UICollectionViewCell {
self.contentTypeBadgeView = UIImageView() self.contentTypeBadgeView = UIImageView()
contentTypeBadgeView.isHidden = true contentTypeBadgeView.isHidden = true
let kSelectedBadgeSize = CGSize(width: 32, height: 32)
self.selectedBadgeView = UIImageView() 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.isHidden = true
selectedBadgeView.layer.cornerRadius = (kSelectedBadgeSize.width / 2)
self.highlightedView = UIView() self.highlightedView = UIView()
highlightedView.alpha = 0.2 highlightedView.alpha = 0.2
highlightedView.backgroundColor = Colors.cellSelected highlightedView.themeBackgroundColor = .black
highlightedView.isHidden = true highlightedView.isHidden = true
self.selectedView = UIView() self.selectedView = UIView()
selectedView.alpha = 0.3 selectedView.alpha = 0.3
selectedView.backgroundColor = Colors.cellSelected selectedView.themeBackgroundColor = .black
selectedView.isHidden = true selectedView.isHidden = true
super.init(frame: frame) super.init(frame: frame)
@ -87,9 +92,8 @@ public class PhotoGridViewCell: UICollectionViewCell {
contentTypeBadgeView.autoPinEdge(toSuperviewEdge: .bottom, withInset: 3) contentTypeBadgeView.autoPinEdge(toSuperviewEdge: .bottom, withInset: 3)
contentTypeBadgeView.autoSetDimensions(to: kContentTypeBadgeSize) contentTypeBadgeView.autoSetDimensions(to: kContentTypeBadgeSize)
let kSelectedBadgeSize = CGSize(width: 31, height: 31) selectedBadgeView.autoPinEdge(toSuperviewEdge: .trailing, withInset: Values.verySmallSpacing)
selectedBadgeView.autoPinEdge(toSuperviewEdge: .trailing, withInset: 0) selectedBadgeView.autoPinEdge(toSuperviewEdge: .bottom, withInset: Values.verySmallSpacing)
selectedBadgeView.autoPinEdge(toSuperviewEdge: .bottom, withInset: 0)
selectedBadgeView.autoSetDimensions(to: kSelectedBadgeSize) selectedBadgeView.autoSetDimensions(to: kSelectedBadgeSize)
} }
@ -102,7 +106,7 @@ public class PhotoGridViewCell: UICollectionViewCell {
get { return imageView.image } get { return imageView.image }
set { set {
imageView.image = newValue 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 { didSet {
if oldValue != isInBatchSelectMode { if oldValue != isInBatchSelectMode {
mediaLibraryViewController.batchSelectModeDidChange() mediaLibraryViewController.batchSelectModeDidChange()
guard let topViewController = viewControllers.last else {
return guard let topViewController = viewControllers.last else { return }
}
updateButtons(topViewController: topViewController) updateButtons(topViewController: topViewController)
} }
} }
@ -96,16 +96,19 @@ class SendMediaNavigationController: OWSNavigationController {
doneButton.isHidden = true doneButton.isHidden = true
cameraModeButton.isHidden = true cameraModeButton.isHidden = true
mediaLibraryModeButton.isHidden = true mediaLibraryModeButton.isHidden = true
case is ImagePickerGridController: case is ImagePickerGridController:
batchModeButton.isHidden = isInBatchSelectMode batchModeButton.isHidden = isInBatchSelectMode
doneButton.isHidden = !isInBatchSelectMode || (attachmentDraftCollection.count == 0 && mediaLibrarySelections.count == 0) doneButton.isHidden = !isInBatchSelectMode || (attachmentDraftCollection.count == 0 && mediaLibrarySelections.count == 0)
cameraModeButton.isHidden = false cameraModeButton.isHidden = false
mediaLibraryModeButton.isHidden = true mediaLibraryModeButton.isHidden = true
case is PhotoCaptureViewController: case is PhotoCaptureViewController:
batchModeButton.isHidden = isInBatchSelectMode batchModeButton.isHidden = isInBatchSelectMode
doneButton.isHidden = !isInBatchSelectMode || (attachmentDraftCollection.count == 0 && mediaLibrarySelections.count == 0) doneButton.isHidden = !isInBatchSelectMode || (attachmentDraftCollection.count == 0 && mediaLibrarySelections.count == 0)
cameraModeButton.isHidden = true cameraModeButton.isHidden = true
mediaLibraryModeButton.isHidden = false mediaLibraryModeButton.isHidden = false
default: default:
owsFailDebug("unexpected topViewController: \(topViewController)") owsFailDebug("unexpected topViewController: \(topViewController)")
} }
@ -150,52 +153,60 @@ class SendMediaNavigationController: OWSNavigationController {
private lazy var doneButton: DoneButton = { private lazy var doneButton: DoneButton = {
let button = DoneButton() let button = DoneButton()
button.delegate = self button.delegate = self
button.setShadow()
return button return button
}() }()
private lazy var batchModeButton: UIButton = { private lazy var batchModeButton: UIButton = {
let button = OWSButton(imageName: "media_send_batch_mode_disabled", let button = OWSButton(
tintColor: .ows_gray60, imageName: "media_send_batch_mode_disabled",
block: { [weak self] in self?.didTapBatchModeButton() }) tintColor: .backgroundPrimary,
block: { [weak self] in self?.didTapBatchModeButton() }
let width: CGFloat = type(of: self).bottomButtonWidth )
button.autoSetDimensions(to: CGSize(width: width, height: width)) button.clipsToBounds = true
button.layer.cornerRadius = width / 2 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.imageEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
button.backgroundColor = .ows_white button.layer.cornerRadius = (SendMediaNavigationController.bottomButtonWidth / 2)
button.setShadow() button.set(.width, to: SendMediaNavigationController.bottomButtonWidth)
button.set(.height, to: SendMediaNavigationController.bottomButtonWidth)
return button return button
}() }()
private lazy var cameraModeButton: UIButton = { private lazy var cameraModeButton: UIButton = {
let button = OWSButton(imageName: "settings-avatar-camera-2", let button = OWSButton(
tintColor: .ows_gray60, imageName: "settings-avatar-camera-2",
block: { [weak self] in self?.didTapCameraModeButton() }) tintColor: .backgroundPrimary,
block: { [weak self] in self?.didTapCameraModeButton() }
let width: CGFloat = type(of: self).bottomButtonWidth )
button.autoSetDimensions(to: CGSize(width: width, height: width)) button.clipsToBounds = true
button.layer.cornerRadius = width / 2 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.imageEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
button.backgroundColor = .ows_white button.layer.cornerRadius = (SendMediaNavigationController.bottomButtonWidth / 2)
button.setShadow() button.set(.width, to: SendMediaNavigationController.bottomButtonWidth)
button.set(.height, to: SendMediaNavigationController.bottomButtonWidth)
return button return button
}() }()
private lazy var mediaLibraryModeButton: UIButton = { private lazy var mediaLibraryModeButton: UIButton = {
let button = OWSButton(imageName: "actionsheet_camera_roll_black", let button = OWSButton(
tintColor: .ows_gray60, imageName: "actionsheet_camera_roll_black",
block: { [weak self] in self?.didTapMediaLibraryModeButton() }) tintColor: .backgroundPrimary,
block: { [weak self] in self?.didTapMediaLibraryModeButton() }
let width: CGFloat = type(of: self).bottomButtonWidth )
button.autoSetDimensions(to: CGSize(width: width, height: width)) button.clipsToBounds = true
button.layer.cornerRadius = width / 2 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.imageEdgeInsets = UIEdgeInsets(top: 10, left: 10, bottom: 10, right: 10)
button.backgroundColor = .ows_white button.layer.cornerRadius = (SendMediaNavigationController.bottomButtonWidth / 2)
button.setShadow() button.set(.width, to: SendMediaNavigationController.bottomButtonWidth)
button.set(.height, to: SendMediaNavigationController.bottomButtonWidth)
return button return button
}() }()
@ -243,49 +254,29 @@ class SendMediaNavigationController: OWSNavigationController {
pushViewController(approvalViewController, animated: true) pushViewController(approvalViewController, animated: true)
} }
private func didRequestExit(dontAbandonText: String) { private func didRequestExit() {
if attachmentDraftCollection.count == 0 { guard attachmentDraftCollection.count > 0 else {
self.sendMediaNavDelegate?.sendMediaNavDidCancel(self) self.sendMediaNavDelegate?.sendMediaNavDidCancel(self)
} else { return
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)
} }
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 { 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) { func navigationController(_ navigationController: UINavigationController, willShow viewController: UIViewController, animated: Bool) {
if viewController == captureViewController {
setNavBarBackgroundColor(to: .black)
} else {
setNavBarBackgroundColor(to: Colors.navigationBarBackground)
}
switch viewController { switch viewController {
case is PhotoCaptureViewController: case is PhotoCaptureViewController:
if attachmentDraftCollection.count == 1 && !isInBatchSelectMode { if attachmentDraftCollection.count == 1 && !isInBatchSelectMode {
@ -293,11 +284,13 @@ extension SendMediaNavigationController: UINavigationControllerDelegate {
// they want to discard the previously captured item // they want to discard the previously captured item
discardDraft() discardDraft()
} }
case is ImagePickerGridController: case is ImagePickerGridController:
if attachmentDraftCollection.count == 1 && !isInBatchSelectMode { if attachmentDraftCollection.count == 1 && !isInBatchSelectMode {
isInBatchSelectMode = true isInBatchSelectMode = true
self.mediaLibraryViewController.batchSelectModeDidChange() self.mediaLibraryViewController.batchSelectModeDidChange()
} }
default: default:
break break
} }
@ -307,30 +300,8 @@ extension SendMediaNavigationController: UINavigationControllerDelegate {
// In case back navigation was canceled, we re-apply whatever is showing. // In case back navigation was canceled, we re-apply whatever is showing.
func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) { func navigationController(_ navigationController: UINavigationController, didShow viewController: UIViewController, animated: Bool) {
if viewController == captureViewController {
setNavBarBackgroundColor(to: .black)
} else {
setNavBarBackgroundColor(to: Colors.navigationBarBackground)
}
self.updateButtons(topViewController: viewController) 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 { extension SendMediaNavigationController: PhotoCaptureViewControllerDelegate {
@ -338,14 +309,14 @@ extension SendMediaNavigationController: PhotoCaptureViewControllerDelegate {
attachmentDraftCollection.append(.camera(attachment: attachment)) attachmentDraftCollection.append(.camera(attachment: attachment))
if isInBatchSelectMode { if isInBatchSelectMode {
updateButtons(topViewController: photoCaptureViewController) updateButtons(topViewController: photoCaptureViewController)
} else { }
else {
pushApprovalViewController() pushApprovalViewController()
} }
} }
func photoCaptureViewControllerDidCancel(_ photoCaptureViewController: PhotoCaptureViewController) { 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()
didRequestExit(dontAbandonText: dontAbandonText)
} }
func discardDraft() { func discardDraft() {
@ -364,8 +335,7 @@ extension SendMediaNavigationController: ImagePickerGridControllerDelegate {
} }
func imagePickerDidCancel(_ imagePicker: ImagePickerGridController) { 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()
didRequestExit(dontAbandonText: dontAbandonText)
} }
func showApprovalAfterProcessingAnyMediaLibrarySelections() { func showApprovalAfterProcessingAnyMediaLibrarySelections() {
@ -374,18 +344,21 @@ extension SendMediaNavigationController: ImagePickerGridControllerDelegate {
let backgroundBlock: (ModalActivityIndicatorViewController) -> Void = { modal in let backgroundBlock: (ModalActivityIndicatorViewController) -> Void = { modal in
let attachmentPromises: [Promise<MediaLibraryAttachment>] = mediaLibrarySelections.map { $0.promise } let attachmentPromises: [Promise<MediaLibraryAttachment>] = mediaLibrarySelections.map { $0.promise }
when(fulfilled: attachmentPromises).map { attachments in when(fulfilled: attachmentPromises)
.map { attachments in
Logger.debug("built all attachments") Logger.debug("built all attachments")
modal.dismiss { modal.dismiss {
self.attachmentDraftCollection.selectedFromPicker(attachments: attachments) self.attachmentDraftCollection.selectedFromPicker(attachments: attachments)
self.pushApprovalViewController() self.pushApprovalViewController()
} }
}.catch { error in }
.catch { error in
Logger.error("failed to prepare attachments. error: \(error)") Logger.error("failed to prepare attachments. error: \(error)")
modal.dismiss { modal.dismiss {
OWSAlerts.showAlert(title: NSLocalizedString("IMAGE_PICKER_FAILED_TO_PROCESS_ATTACHMENTS", comment: "alert title")) OWSAlerts.showAlert(title: NSLocalizedString("IMAGE_PICKER_FAILED_TO_PROCESS_ATTACHMENTS", comment: "alert title"))
} }
}.retainUntilComplete() }
.retainUntilComplete()
} }
ModalActivityIndicatorViewController.present(fromViewController: self, ModalActivityIndicatorViewController.present(fromViewController: self,
@ -398,22 +371,17 @@ extension SendMediaNavigationController: ImagePickerGridControllerDelegate {
} }
func imagePicker(_ imagePicker: ImagePickerGridController, didSelectAsset asset: PHAsset, attachmentPromise: Promise<SignalAttachment>) { func imagePicker(_ imagePicker: ImagePickerGridController, didSelectAsset asset: PHAsset, attachmentPromise: Promise<SignalAttachment>) {
guard !mediaLibrarySelections.hasValue(forKey: asset) else { guard !mediaLibrarySelections.hasValue(forKey: asset) else { return }
return
}
let libraryMedia = MediaLibrarySelection(asset: asset, signalAttachmentPromise: attachmentPromise) let libraryMedia = MediaLibrarySelection(asset: asset, signalAttachmentPromise: attachmentPromise)
mediaLibrarySelections.append(key: asset, value: libraryMedia) mediaLibrarySelections.append(key: asset, value: libraryMedia)
updateButtons(topViewController: imagePicker) updateButtons(topViewController: imagePicker)
} }
func imagePicker(_ imagePicker: ImagePickerGridController, didDeselectAsset asset: PHAsset) { func imagePicker(_ imagePicker: ImagePickerGridController, didDeselectAsset asset: PHAsset) {
guard mediaLibrarySelections.hasValue(forKey: asset) else { guard mediaLibrarySelections.hasValue(forKey: asset) else { return }
return
}
mediaLibrarySelections.remove(key: asset)
mediaLibrarySelections.remove(key: asset)
updateButtons(topViewController: imagePicker) updateButtons(topViewController: imagePicker)
} }
@ -599,51 +567,64 @@ private protocol DoneButtonDelegate: AnyObject {
private class DoneButton: UIView { private class DoneButton: UIView {
weak var delegate: DoneButtonDelegate? 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() { init() {
super.init(frame: .zero) super.init(frame: .zero)
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTap(tapGesture:))) let tapGesture = UITapGestureRecognizer(target: self, action: #selector(didTap(tapGesture:)))
addGestureRecognizer(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) addSubview(container)
container.autoPinEdgesToSuperviewMargins() container.pin(to: self)
let stackView = UIStackView(arrangedSubviews: [badge, chevron])
stackView.axis = .horizontal
stackView.alignment = .center
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)
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
// MARK: - Subviews
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) badge.addSubview(badgeLabel)
badgeLabel.autoPinEdgesToSuperviewMargins() badgeLabel.pin(to: badge, withInset: 4)
// Constrain to be a pill that is at least a circle, and maybe wider. // Constrain to be a pill that is at least a circle, and maybe wider.
badgeLabel.autoPin(toAspectRatio: 1.0, relation: .greaterThanOrEqual) badgeLabel.autoPin(toAspectRatio: 1.0, relation: .greaterThanOrEqual)
@ -651,42 +632,84 @@ private class DoneButton: UIView {
badgeLabel.autoPinToSquareAspectRatio() badgeLabel.autoPinToSquareAspectRatio()
} }
return badge let stackView = UIStackView(arrangedSubviews: [badge, chevron])
}() stackView.axis = .horizontal
stackView.alignment = .center
stackView.spacing = 9
private lazy var badgeLabel: UILabel = { container.addSubview(stackView)
let label = UILabel() stackView.pin(.top, to: .top, of: container, withInset: 7)
label.textColor = .ows_white stackView.pin(.leading, to: .leading, of: container, withInset: 8)
label.font = UIFont.ows_dynamicTypeSubheadline.ows_monospaced() stackView.pin(.trailing, to: .trailing, of: container, withInset: -8)
label.textAlignment = .center stackView.pin(.bottom, to: .bottom, of: container, withInset: -7)
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 required init?(coder aDecoder: NSCoder) {
}() fatalError("init(coder:) has not been implemented")
}
@objc // MARK: - Functions
func didTap(tapGesture: UITapGestureRecognizer) {
func updateCount() {
guard let delegate = delegate else { return }
badgeLabel.text = numberFormatter.string(for: delegate.doneButtonCount)
}
// MARK: - Interaction
@objc func didTap(tapGesture: UITapGestureRecognizer) {
delegate?.doneButtonWasTapped(self) 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 // MARK: - SendMediaNavDelegate
protocol SendMediaNavDelegate: AnyObject { protocol SendMediaNavDelegate: AnyObject {
func sendMediaNavDidCancel(_ sendMediaNavigationController: SendMediaNavigationController) func sendMediaNavDidCancel(_ sendMediaNavigationController: SendMediaNavigationController?)
func sendMediaNav(_ sendMediaNavigationController: SendMediaNavigationController, didApproveAttachments attachments: [SignalAttachment], forThreadId threadId: String, messageText: String?) func sendMediaNav(_ sendMediaNavigationController: SendMediaNavigationController, didApproveAttachments attachments: [SignalAttachment], forThreadId threadId: String, messageText: String?)
func sendMediaNavInitialMessageText(_ sendMediaNavigationController: SendMediaNavigationController) -> 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 { if Environment.shared?.callManager.wrappedValue?.currentCall == nil {
UserDefaults.sharedLokiProject?.set(false, forKey: "isCallOngoing") UserDefaults.sharedLokiProject?.set(false, forKey: "isCallOngoing")
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -38,8 +38,8 @@ final class SeedReminderView: UIView {
let result = UILabel() let result = UILabel()
result.font = .systemFont(ofSize: Values.verySmallFontSize) result.font = .systemFont(ofSize: Values.verySmallFontSize)
result.themeTextColor = .textSecondary result.themeTextColor = .textSecondary
result.numberOfLines = 0
result.lineBreakMode = .byWordWrapping result.lineBreakMode = .byWordWrapping
result.numberOfLines = 2
return result return result
}() }()
@ -66,8 +66,17 @@ final class SeedReminderView: UIView {
// Set background color // Set background color
themeBackgroundColor = .conversationButton_background 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 // Set up label stack view
let labelStackView = UIStackView(arrangedSubviews: [ titleLabel, subtitleLabel ]) let labelStackView = UIStackView(arrangedSubviews: [ titleLabel, subtitleContainerView ])
labelStackView.axis = .vertical labelStackView.axis = .vertical
labelStackView.spacing = 4 labelStackView.spacing = 4
@ -103,12 +112,12 @@ final class SeedReminderView: UIView {
stackView.pin(to: self) stackView.pin(to: self)
} }
// MARK: Updating // MARK: - Updating
func setProgress(_ progress: Float, animated isAnimated: Bool) { func setProgress(_ progress: Float, animated isAnimated: Bool) {
progressIndicatorView.setProgress(progress, animated: isAnimated) progressIndicatorView.setProgress(progress, animated: isAnimated)
} }
// MARK: Updating
@objc private func handleContinueButtonTapped() { @objc private func handleContinueButtonTapped() {
delegate?.handleContinueButtonTapped(from: self) delegate?.handleContinueButtonTapped(from: self)
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,6 +1,7 @@
//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved. // Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
import UIKit
import SessionUIKit
public protocol CaptionContainerViewDelegate: AnyObject { public protocol CaptionContainerViewDelegate: AnyObject {
func captionContainerViewDidUpdateText(_ captionContainerView: CaptionContainerView) func captionContainerViewDidUpdateText(_ captionContainerView: CaptionContainerView)
@ -100,8 +101,8 @@ private class CaptionView: UIView {
let textView = CaptionTextView() let textView = CaptionTextView()
textView.font = UIFont.ows_dynamicTypeBody textView.font = UIFont.ows_dynamicTypeBody
textView.textColor = Colors.text textView.themeTextColor = .textPrimary
textView.backgroundColor = .clear textView.themeBackgroundColor = .clear
textView.isEditable = false textView.isEditable = false
textView.isSelectable = 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) hasAtLeastOneReadReceipt: (cellViewModel.interactionHasAtLeastOneReadReceipt ?? false)
) )
statusIndicatorView.image = stateInfo?.image statusIndicatorView.image = stateInfo?.image
statusIndicatorView.themeTintColor = stateInfo?.tintColor statusIndicatorView.themeTintColor = stateInfo?.themeTintColor
statusIndicatorView.isHidden = ( statusIndicatorView.isHidden = (
cellViewModel.interactionVariant != .standardOutgoing && cellViewModel.interactionVariant != .standardOutgoing &&
cellViewModel.interactionState != .skipped cellViewModel.interactionState != .skipped
@ -456,7 +456,7 @@ public final class FullConversationCell: UITableViewCell {
} }
else if cellViewModel.threadOnlyNotifyForMentions == true { else if cellViewModel.threadOnlyNotifyForMentions == true {
let imageAttachment = NSTextAttachment() 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) imageAttachment.bounds = CGRect(x: 0, y: -2, width: Values.smallFontSize, height: Values.smallFontSize)
let imageString = NSAttributedString(attachment: imageAttachment) let imageString = NSAttributedString(attachment: imageAttachment)

View File

@ -25,7 +25,7 @@ public class LoadingViewController: UIViewController {
private var logoView: UIImageView = { private var logoView: UIImageView = {
let result: UIImageView = UIImageView(image: #imageLiteral(resourceName: "SessionGreen64")) let result: UIImageView = UIImageView(image: #imageLiteral(resourceName: "SessionGreen64"))
result.contentMode = .scaleAspectFit result.contentMode = .scaleAspectFit
result.layer.shadowColor = Theme.PrimaryColor.green.color.cgColor result.themeShadowColorForced = .primary(.green)
result.layer.shadowOffset = .zero result.layer.shadowOffset = .zero
result.layer.shadowRadius = 3 result.layer.shadowRadius = 3
result.layer.shadowOpacity = 0 result.layer.shadowOpacity = 0
@ -37,8 +37,8 @@ public class LoadingViewController: UIViewController {
let result: UIProgressView = UIProgressView(progressViewStyle: .bar) let result: UIProgressView = UIProgressView(progressViewStyle: .bar)
result.clipsToBounds = true result.clipsToBounds = true
result.progress = 0 result.progress = 0
result.tintColor = Theme.PrimaryColor.green.color result.themeTintColorForced = .primary(.green)
result.progressTintColor = Theme.classicDark.colors[.textPrimary]?.withAlphaComponent(0.1) result.themeProgressTintColorForced = .theme(.classicDark, color: .textPrimary, alpha: 0.1)
result.layer.cornerRadius = 6 result.layer.cornerRadius = 6
return result return result
@ -48,7 +48,7 @@ public class LoadingViewController: UIViewController {
let result: UILabel = UILabel() let result: UILabel = UILabel()
result.font = UIFont.systemFont(ofSize: Values.mediumFontSize) result.font = UIFont.systemFont(ofSize: Values.mediumFontSize)
result.text = "DATABASE_VIEW_OVERLAY_TITLE".localized() result.text = "DATABASE_VIEW_OVERLAY_TITLE".localized()
result.textColor = Theme.classicDark.colors[.textPrimary] result.themeTextColorForced = .theme(.classicDark, color: .textPrimary)
result.textAlignment = .center result.textAlignment = .center
result.numberOfLines = 0 result.numberOfLines = 0
result.lineBreakMode = .byWordWrapping result.lineBreakMode = .byWordWrapping
@ -60,7 +60,7 @@ public class LoadingViewController: UIViewController {
let result: UILabel = UILabel() let result: UILabel = UILabel()
result.font = UIFont.systemFont(ofSize: Values.verySmallFontSize) result.font = UIFont.systemFont(ofSize: Values.verySmallFontSize)
result.text = "DATABASE_VIEW_OVERLAY_SUBTITLE".localized() result.text = "DATABASE_VIEW_OVERLAY_SUBTITLE".localized()
result.textColor = Theme.classicDark.colors[.textPrimary] result.themeTextColorForced = .theme(.classicDark, color: .textPrimary)
result.textAlignment = .center result.textAlignment = .center
result.numberOfLines = 0 result.numberOfLines = 0
result.lineBreakMode = .byWordWrapping result.lineBreakMode = .byWordWrapping
@ -84,7 +84,7 @@ public class LoadingViewController: UIViewController {
override public func loadView() { override public func loadView() {
self.view = UIView() 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.logoView)
self.view.addSubview(self.labelStack) 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.opaque = NO;
self.userInteractionEnabled = NO; self.userInteractionEnabled = NO;
self.backgroundColor = [UIColor clearColor];
} }
- (void)setFrame:(CGRect)frame - (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.
import UIKit
import SessionUIKit
final class ScanQRCodeWrapperVC: BaseVC { final class ScanQRCodeWrapperVC: BaseVC {
var delegate: (UIViewController & OWSQRScannerDelegate)? = nil var delegate: (UIViewController & QRScannerDelegate)? = nil
var isPresentedModally = false var isPresentedModally = false
private let message: String private let message: String
private let scanQRCodeVC = OWSQRCodeScanningViewController() private let scanQRCodeVC = QRCodeScanningViewController()
// MARK: Settings
override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait } override var supportedInterfaceOrientations: UIInterfaceOrientationMask { return .portrait }
// MARK: Lifecycle // MARK: - Lifecycle
init(message: String) { init(message: String) {
self.message = message self.message = message
super.init(nibName: nil, bundle: nil) super.init(nibName: nil, bundle: nil)
@ -24,6 +28,9 @@ final class ScanQRCodeWrapperVC : BaseVC {
override func viewDidLoad() { override func viewDidLoad() {
super.viewDidLoad() super.viewDidLoad()
title = "Scan QR Code"
// Set up navigation bar if needed // Set up navigation bar if needed
if isPresentedModally { if isPresentedModally {
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(close)) 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.pin(.trailing, to: .trailing, of: view)
scanQRCodeVCView.autoPinEdge(.top, to: .top, of: view) scanQRCodeVCView.autoPinEdge(.top, to: .top, of: view)
scanQRCodeVCView.autoPinToSquareAspectRatio() scanQRCodeVCView.autoPinToSquareAspectRatio()
// Set up bottom view // Set up bottom view
let bottomView = UIView() let bottomView = UIView()
view.addSubview(bottomView) view.addSubview(bottomView)
@ -44,37 +52,35 @@ final class ScanQRCodeWrapperVC : BaseVC {
bottomView.pin(.leading, to: .leading, of: view) bottomView.pin(.leading, to: .leading, of: view)
bottomView.pin(.trailing, to: .trailing, of: view) bottomView.pin(.trailing, to: .trailing, of: view)
bottomView.pin(.bottom, to: .bottom, of: view) bottomView.pin(.bottom, to: .bottom, of: view)
// Set up explanation label // Set up explanation label
let explanationLabel = UILabel() let explanationLabel = UILabel()
explanationLabel.text = message explanationLabel.text = message
explanationLabel.textColor = Colors.text explanationLabel.themeTextColor = .textPrimary
explanationLabel.font = .systemFont(ofSize: Values.smallFontSize) explanationLabel.font = .systemFont(ofSize: Values.smallFontSize)
explanationLabel.numberOfLines = 0
explanationLabel.lineBreakMode = .byWordWrapping
explanationLabel.textAlignment = .center explanationLabel.textAlignment = .center
explanationLabel.lineBreakMode = .byWordWrapping
explanationLabel.numberOfLines = 0
bottomView.addSubview(explanationLabel) bottomView.addSubview(explanationLabel)
explanationLabel.autoPinWidthToSuperview(withMargin: 32) explanationLabel.autoPinWidthToSuperview(withMargin: 32)
explanationLabel.autoPinHeightToSuperview(withMargin: 32) explanationLabel.autoPinHeightToSuperview(withMargin: 32)
// Title
title = "Scan QR Code"
} }
override func viewDidAppear(_ animated: Bool) { override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated) super.viewDidAppear(animated)
UIDevice.current.ows_setOrientation(.portrait) 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() { @objc private func close() {
presentingViewController?.dismiss(animated: true, completion: nil) presentingViewController?.dismiss(animated: true, completion: nil)
} }
public func startCapture() { 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, attributedExplanation: NSAttributedString? = nil,
stateToShow: State = .always, stateToShow: State = .always,
confirmTitle: String? = nil, confirmTitle: String? = nil,
confirmStyle: ThemeValue = .textPrimary, confirmStyle: ThemeValue = .alert_text,
cancelTitle: String = "TXT_CANCEL_TITLE".localized(), cancelTitle: String = "TXT_CANCEL_TITLE".localized(),
cancelStyle: ThemeValue = .danger, cancelStyle: ThemeValue = .danger,
dismissOnConfirm: Bool = true, dismissOnConfirm: Bool = true,
@ -115,7 +115,7 @@ public class ConfirmationModal: Modal {
private lazy var titleLabel: UILabel = { private lazy var titleLabel: UILabel = {
let result: UILabel = UILabel() let result: UILabel = UILabel()
result.font = .boldSystemFont(ofSize: Values.mediumFontSize) result.font = .boldSystemFont(ofSize: Values.mediumFontSize)
result.themeTextColor = .textPrimary result.themeTextColor = .alert_text
result.textAlignment = .center result.textAlignment = .center
result.lineBreakMode = .byWordWrapping result.lineBreakMode = .byWordWrapping
result.numberOfLines = 0 result.numberOfLines = 0
@ -126,7 +126,7 @@ public class ConfirmationModal: Modal {
private lazy var explanationLabel: UILabel = { private lazy var explanationLabel: UILabel = {
let result: UILabel = UILabel() let result: UILabel = UILabel()
result.font = .systemFont(ofSize: Values.smallFontSize) result.font = .systemFont(ofSize: Values.smallFontSize)
result.themeTextColor = .textPrimary result.themeTextColor = .alert_text
result.textAlignment = .center result.textAlignment = .center
result.lineBreakMode = .byWordWrapping result.lineBreakMode = .byWordWrapping
result.numberOfLines = 0 result.numberOfLines = 0

View File

@ -58,6 +58,13 @@ public class Modal: BaseVC, UIGestureRecognizerDelegate {
self.afterClosed = afterClosed self.afterClosed = afterClosed
super.init(nibName: nil, bundle: nil) 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) { 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 "Session-Swift.h"
#import <MobileCoreServices/UTCoreTypes.h> #import <MobileCoreServices/UTCoreTypes.h>
#import <SignalUtilitiesKit/UIUtil.h>
#import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h> #import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN

View File

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

View File

@ -1,6 +1,7 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved. // Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit import UIKit
import SessionUIKit
extension UINavigationBar { extension UINavigationBar {
func generateSnapshot(in coordinateSpace: UICoordinateSpace) -> (UIView, CGRect)? { func generateSnapshot(in coordinateSpace: UICoordinateSpace) -> (UIView, CGRect)? {
@ -31,7 +32,7 @@ extension UINavigationBar {
height: frame.maxY height: frame.maxY
) )
) )
snapshotView.backgroundColor = backgroundColor snapshotView.themeBackgroundColorForced = self.themeBackgroundColorForced
let imageView: UIImageView = UIImageView(image: image) let imageView: UIImageView = UIImageView(image: image)
imageView.frame = frame 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 <AVFoundation/AVFoundation.h>
#import <Photos/Photos.h> #import <Photos/Photos.h>
#import <SignalCoreKit/Threading.h> #import <SignalCoreKit/Threading.h>
#import <SignalUtilitiesKit/UIUtil.h>
NS_ASSUME_NONNULL_BEGIN 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) } guard variant == .standardOutgoing else { return (nil, .textPrimary) }
switch (self, hasAtLeastOneReadReceipt) { switch (self, hasAtLeastOneReadReceipt) {

View File

@ -6,8 +6,6 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
extern NSString *const OWSWindowManagerCallDidChangeNotification;
extern NSString *const IsScreenBlockActiveDidChangeNotification; extern NSString *const IsScreenBlockActiveDidChangeNotification;
// This VC can become first responder // This VC can become first responder
@ -32,27 +30,10 @@ extern const UIWindowLevel UIWindowLevel_Background;
- (void)setupWithRootWindow:(UIWindow *)rootWindow screenBlockingWindow:(UIWindow *)screenBlockingWindow; - (void)setupWithRootWindow:(UIWindow *)rootWindow screenBlockingWindow:(UIWindow *)screenBlockingWindow;
@property (nonatomic, readonly) UIWindow *rootWindow; @property (nonatomic, readonly) UIWindow *rootWindow;
@property (nonatomic, readonly) UIWindow *menuActionsWindow;
@property (nonatomic) BOOL isScreenBlockActive; @property (nonatomic) BOOL isScreenBlockActive;
- (BOOL)isAppWindow:(UIWindow *)window; - (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 @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@ -8,31 +8,11 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
NSString *const OWSWindowManagerCallDidChangeNotification = @"OWSWindowManagerCallDidChangeNotification";
NSString *const IsScreenBlockActiveDidChangeNotification = @"IsScreenBlockActiveDidChangeNotification"; NSString *const IsScreenBlockActiveDidChangeNotification = @"IsScreenBlockActiveDidChangeNotification";
const CGFloat OWSWindowManagerCallBannerHeight(void)
{
return CurrentAppContext().statusBarHeight + 20;
}
// Behind everything, especially the root window. // Behind everything, especially the root window.
const UIWindowLevel UIWindowLevel_Background = -1.f; 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 // In front of the status bar and CallView
const UIWindowLevel UIWindowLevel_ScreenBlocking(void); const UIWindowLevel UIWindowLevel_ScreenBlocking(void);
const UIWindowLevel UIWindowLevel_ScreenBlocking(void) const UIWindowLevel UIWindowLevel_ScreenBlocking(void)
@ -40,36 +20,6 @@ const UIWindowLevel UIWindowLevel_ScreenBlocking(void)
return UIWindowLevelStatusBar + 2.f; 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 - #pragma mark -
@implementation OWSWindowRootViewController @implementation OWSWindowRootViewController
@ -114,22 +64,10 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
// UIWindowLevelNormal // UIWindowLevelNormal
@property (nonatomic) UIWindow *rootWindow; @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_Background if inactive,
// UIWindowLevel_ScreenBlocking() if active. // UIWindowLevel_ScreenBlocking() if active.
@property (nonatomic) UIWindow *screenBlockingWindow; @property (nonatomic) UIWindow *screenBlockingWindow;
@property (nonatomic) BOOL shouldShowCallView;
@property (nonatomic, nullable) UIViewController *callViewController;
@end @end
#pragma mark - #pragma mark -
@ -157,9 +95,6 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
self.rootWindow = rootWindow; self.rootWindow = rootWindow;
self.screenBlockingWindow = screenBlockingWindow; self.screenBlockingWindow = screenBlockingWindow;
self.callViewWindow = [self createCallViewWindow:rootWindow];
self.menuActionsWindow = [self createMenuActionsWindowWithRoowWindow:rootWindow];
[[NSNotificationCenter defaultCenter] addObserver:self [[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(didChangeStatusBarFrame:) selector:@selector(didChangeStatusBarFrame:)
name:UIApplicationDidChangeStatusBarFrameNotification name:UIApplicationDidChangeStatusBarFrameNotification
@ -175,47 +110,10 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
- (void)didChangeStatusBarFrame:(NSNotification *)notification - (void)didChangeStatusBarFrame:(NSNotification *)notification
{ {
} }
- (void)applicationWillResignActive:(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 - (void)setIsScreenBlockActive:(BOOL)isScreenBlockActive
@ -231,92 +129,7 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
- (BOOL)isAppWindow:(UIWindow *)window - (BOOL)isAppWindow:(UIWindow *)window
{ {
return (window == self.rootWindow || window == self.callViewWindow return (window == self.rootWindow || window == self.screenBlockingWindow);
|| 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;
} }
#pragma mark - Window State #pragma mark - Window State
@ -332,30 +145,13 @@ const UIWindowLevel UIWindowLevel_MessageActions(void)
// Show Screen Block. // Show Screen Block.
[self ensureRootWindowHidden]; [self ensureRootWindowHidden];
[self ensureCallViewWindowHidden];
[self ensureMessageActionsWindowHidden];
[self ensureScreenBlockWindowShown]; [self ensureScreenBlockWindowShown];
} else if (self.callViewController && self.shouldShowCallView) { }
// Show Call View. else {
[self ensureRootWindowHidden];
[self ensureCallViewWindowShown];
[self ensureMessageActionsWindowHidden];
[self ensureScreenBlockWindowHidden];
} else {
// Show Root Window // Show Root Window
[self ensureRootWindowShown]; [self ensureRootWindowShown];
[self ensureCallViewWindowHidden];
[self ensureScreenBlockWindowHidden]; [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; 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 - (void)ensureScreenBlockWindowShown
{ {
self.screenBlockingWindow.windowLevel = UIWindowLevel_ScreenBlocking(); self.screenBlockingWindow.windowLevel = UIWindowLevel_ScreenBlocking();

View File

@ -62,20 +62,20 @@ final class SAEScreenLockViewController: ScreenLockViewController {
ThemeManager.onThemeChange(observer: self.unlockButton) { [weak self] theme, _ in ThemeManager.onThemeChange(observer: self.unlockButton) { [weak self] theme, _ in
switch theme.interfaceStyle { switch theme.interfaceStyle {
case .light: case .light:
self?.unlockButton.setTitleColor(theme.colors[.textPrimary], for: .normal) self?.unlockButton.setThemeTitleColorForced(.theme(theme, color: .textPrimary), for: .normal)
self?.unlockButton.setBackgroundImage( self?.unlockButton.setThemeBackgroundColorForced(
theme.colors[.textPrimary]?.withAlphaComponent(0.3).toImage(), .theme(theme, color: .textPrimary),
for: .highlighted for: .highlighted
) )
self?.unlockButton.layer.borderColor = theme.colors[.textPrimary]?.cgColor self?.unlockButton.themeBorderColorForced = .theme(theme, color: .textPrimary)
default: default:
self?.unlockButton.setTitleColor(Theme.PrimaryColor.green.color, for: .normal) self?.unlockButton.setThemeTitleColorForced(.primary(.green), for: .normal)
self?.unlockButton.setBackgroundImage( self?.unlockButton.setThemeBackgroundColorForced(
Theme.PrimaryColor.green.color.withAlphaComponent(0.3).toImage(), .primary(.green, alpha: 0.3),
for: .highlighted 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? { func frontmostViewController() -> UIViewController? {
return rootViewController.findFrontmostViewController(true) return rootViewController.findFrontmostViewController(ignoringAlerts: true)
} }
func appDocumentDirectoryPath() -> String { func appDocumentDirectoryPath() -> String {

View File

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

View File

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

View File

@ -82,7 +82,10 @@ public enum ThemeManager {
// Note: We have to trigger this directly or the 'TraitObservingWindow' won't actually // 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 // 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() { public static func applyWindowStyling() {
mainWindow?.overrideUserInterfaceStyle = { mainWindow?.overrideUserInterfaceStyle = {
guard !ThemeManager.matchSystemNightModeSetting else { return .unspecified }
switch ThemeManager.currentTheme.interfaceStyle { switch ThemeManager.currentTheme.interfaceStyle {
case .light: return .light case .light: return .light
case .dark, .unspecified: return .dark case .dark, .unspecified: return .dark

View File

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

View File

@ -74,6 +74,7 @@ internal enum Theme_ClassicLight: ThemeColors {
.appearance_buttonHighlight: .classicLight4, .appearance_buttonHighlight: .classicLight4,
// Alert // Alert
.alert_text: .classicLight0,
.alert_background: .classicLight6, .alert_background: .classicLight6,
.alert_buttonBackground: .classicLight6, .alert_buttonBackground: .classicLight6,
.alert_buttonHighlight: .classicLight4, .alert_buttonHighlight: .classicLight4,
@ -96,6 +97,7 @@ internal enum Theme_ClassicLight: ThemeColors {
// ContextMenu // ContextMenu
.contextMenu_background: .classicLight6, .contextMenu_background: .classicLight6,
.contextMenu_highlight: .primary, .contextMenu_highlight: .primary,
.contextMenu_text: .classicLight0,
.contextMenu_textHighlight: .classicLight0, .contextMenu_textHighlight: .classicLight0,
// Call // 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 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 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 oceanLight0: UIColor = #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1) // #000000
static let oceanLight1: UIColor = #colorLiteral(red: 0.4156862745, green: 0.431372549, blue: 0.5647058824, alpha: 1) // #6A6E90 static let oceanLight1: UIColor = #colorLiteral(red: 0.09803921569, green: 0.2039215686, blue: 0.3647058824, alpha: 1) // #19345D
static let oceanLight2: UIColor = #colorLiteral(red: 0.3607843137, green: 0.6666666667, blue: 0.8, alpha: 1) // #5CAACC static let oceanLight2: UIColor = #colorLiteral(red: 0.4156862745, green: 0.431372549, blue: 0.5647058824, alpha: 1) // #6A6E90
static let oceanLight3: UIColor = #colorLiteral(red: 0.7019607843, green: 0.9294117647, blue: 0.9490196078, alpha: 1) // #B3EDF2 static let oceanLight3: UIColor = #colorLiteral(red: 0.3607843137, green: 0.6666666667, blue: 0.8, alpha: 1) // #5CAACC
static let oceanLight4: UIColor = #colorLiteral(red: 0.9058823529, green: 0.9529411765, blue: 0.9568627451, alpha: 1) // #E7F3F4 static let oceanLight4: UIColor = #colorLiteral(red: 0.7019607843, green: 0.9294117647, blue: 0.9490196078, alpha: 1) // #B3EDF2
static let oceanLight5: UIColor = #colorLiteral(red: 0.9254901961, green: 0.9803921569, blue: 0.9843137255, alpha: 1) // #ECFAFB static let oceanLight5: UIColor = #colorLiteral(red: 0.9058823529, green: 0.9529411765, blue: 0.9568627451, alpha: 1) // #E7F3F4
static let oceanLight6: UIColor = #colorLiteral(red: 0.9882352941, green: 1, blue: 1, alpha: 1) // #FCFFFF 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 { public extension UIColor {

View File

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

View File

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

View File

@ -125,6 +125,7 @@ public enum ThemeValue {
case appearance_buttonHighlight case appearance_buttonHighlight
// Alert // Alert
case alert_text
case alert_background case alert_background
case alert_buttonBackground case alert_buttonBackground
case alert_buttonHighlight case alert_buttonHighlight
@ -147,6 +148,7 @@ public enum ThemeValue {
// ContextMenu // ContextMenu
case contextMenu_background case contextMenu_background
case contextMenu_highlight case contextMenu_highlight
case contextMenu_text
case contextMenu_textHighlight case contextMenu_textHighlight
// Call // Call
@ -157,3 +159,40 @@ public enum ThemeValue {
case reactions_contextBackground case reactions_contextBackground
case reactions_contextMoreBackground 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 } 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? { var themeTintColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.tintColor, to: newValue) } set { ThemeManager.set(self, keyPath: \.tintColor, to: newValue) }
get { return nil } 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? { var themeBorderColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.layer.borderColor, to: newValue) } set { ThemeManager.set(self, keyPath: \.layer.borderColor, to: newValue) }
get { return nil } 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? { var themeShadowColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.layer.shadowColor, to: newValue) } set { ThemeManager.set(self, keyPath: \.layer.shadowColor, to: newValue) }
get { return nil } 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 { public extension UILabel {
@ -29,6 +133,32 @@ public extension UILabel {
set { ThemeManager.set(self, keyPath: \.textColor, to: newValue) } set { ThemeManager.set(self, keyPath: \.textColor, to: newValue) }
get { return nil } 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 { public extension UITextView {
@ -36,6 +166,32 @@ public extension UITextView {
set { ThemeManager.set(self, keyPath: \.textColor, to: newValue) } set { ThemeManager.set(self, keyPath: \.textColor, to: newValue) }
get { return nil } 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 { public extension UITextField {
@ -43,6 +199,32 @@ public extension UITextField {
set { ThemeManager.set(self, keyPath: \.textColor, to: newValue) } set { ThemeManager.set(self, keyPath: \.textColor, to: newValue) }
get { return nil } 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 { 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) { func setThemeTitleColor(_ value: ThemeValue?, for state: UIControl.State) {
let keyPath: KeyPath<UIButton, UIColor?> = \.titleLabel?.textColor 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 { public extension UISwitch {
@ -117,12 +345,57 @@ public extension UIProgressView {
get { return nil } 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? { var themeTrackTintColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.trackTintColor, to: newValue) } set { ThemeManager.set(self, keyPath: \.trackTintColor, to: newValue) }
get { return nil } 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 { public extension UIContextualAction {
var themeBackgroundColor: ThemeValue? { var themeBackgroundColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.backgroundColor, to: newValue) } set { ThemeManager.set(self, keyPath: \.backgroundColor, to: newValue) }
@ -136,13 +409,96 @@ public extension CAShapeLayer {
get { return nil } 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? { var themeFillColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.fillColor, to: newValue) } set { ThemeManager.set(self, keyPath: \.fillColor, to: newValue) }
get { return nil } 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 { 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? { var themeBorderColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.borderColor, to: newValue) } set { ThemeManager.set(self, keyPath: \.borderColor, to: newValue) }
get { return nil } get { return nil }
@ -153,3 +509,42 @@ public extension CALayer {
get { return nil } 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 import UIKit
public extension UIImage { public extension UIImage {
func withTint(_ color: UIColor) -> UIImage? { func withTint(_ color: UIColor) -> UIImage? {
let template = self.withRenderingMode(.alwaysTemplate) let template = self.withRenderingMode(.alwaysTemplate)
let imageView = UIImageView(image: template) let imageView = UIImageView(image: template)
imageView.tintColor = color imageView.themeTintColorForced = .color(color)
return imageView.toImage(isOpaque: imageView.isOpaque, scale: UIScreen.main.scale) 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; - (NSArray<NSLayoutConstraint *> *)autoPinToEdgesOfView:(UIView *)view;
- (void)traverseViewHierarchyWithVisitor:(UIViewVisitorBlock)visitor;
#pragma mark - Containers #pragma mark - Containers
+ (UIView *)containerView; + (UIView *)containerView;
+ (UIView *)verticalStackWithSubviews:(NSArray<UIView *> *)subviews spacing:(int)spacing; + (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 @end
#pragma mark - #pragma mark -

View File

@ -439,36 +439,6 @@ CGFloat ScaleFromIPhone5(CGFloat iPhone5Value)
return container; 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 @end
#pragma mark - #pragma mark -

View File

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

View File

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

View File

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

View File

@ -6,7 +6,7 @@ import Foundation
import UIKit import UIKit
import SessionUIKit import SessionUIKit
protocol AttachmentCaptionToolbarDelegate: class { protocol AttachmentCaptionToolbarDelegate: AnyObject {
func attachmentCaptionToolbarDidEdit(_ attachmentCaptionToolbar: AttachmentCaptionToolbar) func attachmentCaptionToolbarDidEdit(_ attachmentCaptionToolbar: AttachmentCaptionToolbar)
func attachmentCaptionToolbarDidComplete() func attachmentCaptionToolbarDidComplete()
} }
@ -49,7 +49,7 @@ class AttachmentCaptionToolbar: UIView, UITextViewDelegate {
// sizing when used as an input accessory view. // sizing when used as an input accessory view.
self.autoresizingMask = .flexibleHeight self.autoresizingMask = .flexibleHeight
self.translatesAutoresizingMaskIntoConstraints = false self.translatesAutoresizingMaskIntoConstraints = false
self.backgroundColor = UIColor.clear self.themeBackgroundColor = .clear
textView.delegate = self textView.delegate = self
@ -92,12 +92,12 @@ class AttachmentCaptionToolbar: UIView, UITextViewDelegate {
let lengthLimitLabel = UILabel() let lengthLimitLabel = UILabel()
// Length Limit Label shown when the user inputs too long of a message // 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.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 lengthLimitLabel.textAlignment = .center
// Add shadow in case overlayed on white content // Add shadow in case overlayed on white content
lengthLimitLabel.layer.shadowColor = UIColor.black.cgColor lengthLimitLabel.themeShadowColor = .black
lengthLimitLabel.layer.shadowOffset = .zero lengthLimitLabel.layer.shadowOffset = .zero
lengthLimitLabel.layer.shadowOpacity = 0.8 lengthLimitLabel.layer.shadowOpacity = 0.8
lengthLimitLabel.layer.shadowRadius = 2.0 lengthLimitLabel.layer.shadowRadius = 2.0
@ -127,11 +127,11 @@ class AttachmentCaptionToolbar: UIView, UITextViewDelegate {
let textView = AttachmentTextView() let textView = AttachmentTextView()
textView.keyboardAppearance = isLightMode ? .default : .dark textView.keyboardAppearance = isLightMode ? .default : .dark
textView.backgroundColor = .clear textView.themeBackgroundColor = .clear
textView.tintColor = .white textView.themeTintColor = .textPrimary
textView.font = UIFont.ows_dynamicTypeBody textView.font = UIFont.ows_dynamicTypeBody
textView.textColor = .white textView.themeTextColor = .textPrimary
textView.textContainerInset = UIEdgeInsets(top: 7, left: 7, bottom: 7, right: 7) textView.textContainerInset = UIEdgeInsets(top: 7, left: 7, bottom: 7, right: 7)
return textView 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 { class AddMoreRailItem: GalleryRailItem {
func buildRailItemView() -> UIView { func buildRailItemView() -> UIView {
let view = 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)) let iconView = UIImageView(image: #imageLiteral(resourceName: "ic_plus_24").withRenderingMode(.alwaysTemplate))
iconView.tintColor = .ows_white iconView.themeTintColor = .textPrimary
view.addSubview(iconView) view.addSubview(iconView)
iconView.setCompressionResistanceHigh() iconView.setCompressionResistanceHigh()
iconView.setContentHuggingHigh() iconView.setContentHuggingHigh()
@ -67,8 +67,8 @@ class SignalAttachmentItem: Hashable {
// MARK: Hashable // MARK: Hashable
public var hashValue: Int { func hash(into hasher: inout Hasher) {
return attachment.hashValue attachment.hash(into: &hasher)
} }
// MARK: Equatable // MARK: Equatable

View File

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

View File

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

View File

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

View File

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

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