Applied theming to a number of screens, some minor cleanup and bug fixes

Updated the HomeVC, SettingsVC and GlobalSearch UI to use theming
Removed the "fade view" gradients from the various screens
Added a simple log to the PagedDatabaseObserver to make debugging easier
Updated the FullConversationCell to also show the "read" state for messages
Updated the read receipt icons to use SFSymbols directly
Updated the PlaceholderIcon to use the PrimaryColour's as it's colour options
This commit is contained in:
Morgan Pretty 2022-08-12 17:28:00 +10:00
parent d56cee8234
commit ea32e407a9
74 changed files with 839 additions and 783 deletions

View File

@ -107,7 +107,6 @@
4CA485BB2232339F004B9E7D /* PhotoCaptureViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CA485BA2232339F004B9E7D /* PhotoCaptureViewController.swift */; };
4CC613362227A00400E21A3A /* ConversationSearch.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CC613352227A00400E21A3A /* ConversationSearch.swift */; };
5163CBC4F53274C88D1F88F8 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 782B65234A707D762FEAFD3B /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionUtilitiesKit.framework */; };
63A15A5E6605581543B4A5B4 /* Pods_SessionUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5DEB8C073F5E3C418BFB96C3 /* Pods_SessionUIKit.framework */; };
70377AAB1918450100CAF501 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 70377AAA1918450100CAF501 /* MobileCoreServices.framework */; };
71B1D8AF3ADE2BD191256496 /* Pods_GlobalDependencies_Session.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 48AD214D67ABED845101E795 /* Pods_GlobalDependencies_Session.framework */; };
768A1A2B17FC9CD300E00ED8 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 768A1A2A17FC9CD300E00ED8 /* libz.dylib */; };
@ -158,6 +157,7 @@
7BFD1A8C2747150E00FB91B9 /* TurnServerInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFD1A8B2747150E00FB91B9 /* TurnServerInfo.swift */; };
7BFD1A972747689000FB91B9 /* Session-Turn-Server in Resources */ = {isa = PBXBuildFile; fileRef = 7BFD1A962747689000FB91B9 /* Session-Turn-Server */; };
7BFFB33C27D02F5800BEA04E /* CallPermissionRequestModal.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7BFFB33B27D02F5800BEA04E /* CallPermissionRequestModal.swift */; };
821EFD1644285AC2D3733D27 /* Pods_GlobalDependencies_SessionUIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9C58C3ADF46C718488458C2 /* Pods_GlobalDependencies_SessionUIKit.framework */; };
92EB2776D36B22D2E0552A05 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionMessagingKit_SessionMessagingKitTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 2691123A7F231EDD8226C4B5 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionMessagingKit_SessionMessagingKitTests.framework */; };
98547545DAF8E7916DF9F0BF /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_SessionNotificationServiceExtension.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6F84A214B9A1C0CCF6DB09C8 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_SessionNotificationServiceExtension.framework */; };
A11CD70D17FA230600A2D1B1 /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A11CD70C17FA230600A2D1B1 /* QuartzCore.framework */; };
@ -521,7 +521,6 @@
C3D0972B2510499C00F6E3E4 /* BackgroundPoller.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D0972A2510499C00F6E3E4 /* BackgroundPoller.swift */; };
C3D90A1125773888002C9DF5 /* Colors.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C39DD28724F3318C008590FC /* Colors.xcassets */; };
C3D90A5C25773A25002C9DF5 /* SessionUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A679255388CC00C340D1 /* SessionUtilitiesKit.framework */; };
C3D90A7A25773A93002C9DF5 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3F0A5EB255C970D007BE2A3 /* Configuration.swift */; };
C3D9E35525675EE10040E4F3 /* MIMETypeUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB41255A580C00E217F9 /* MIMETypeUtil.m */; };
C3D9E35E25675F640040E4F3 /* OWSFileSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDA8E255A57FD00E217F9 /* OWSFileSystem.m */; };
C3D9E379256760340040E4F3 /* MIMETypeUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDAFC255A580600E217F9 /* MIMETypeUtil.h */; settings = {ATTRIBUTES = (Public, ); }; };
@ -530,7 +529,6 @@
C3D9E3A4256763DE0040E4F3 /* AppContext.h in Headers */ = {isa = PBXBuildFile; fileRef = C33FDB8A255A581200E217F9 /* AppContext.h */; settings = {ATTRIBUTES = (Public, ); }; };
C3D9E3BE25676AD70040E4F3 /* (null) in Sources */ = {isa = PBXBuildFile; };
C3D9E3BF25676AD70040E4F3 /* (null) in Sources */ = {isa = PBXBuildFile; };
C3D9E43125676D3D0040E4F3 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D9E43025676D3D0040E4F3 /* Configuration.swift */; };
C3D9E4C02567767F0040E4F3 /* DataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDBB6255A581600E217F9 /* DataSource.m */; };
C3D9E4D12567777D0040E4F3 /* OWSMediaUtils.swift in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB22255A580900E217F9 /* OWSMediaUtils.swift */; };
C3D9E4DA256778410040E4F3 /* UIImage+OWS.m in Sources */ = {isa = PBXBuildFile; fileRef = C33FDB81255A581100E217F9 /* UIImage+OWS.m */; };
@ -656,6 +654,12 @@
FD37E9D928A230F2003AE748 /* TraitObservingWindow.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD37E9D828A230F2003AE748 /* TraitObservingWindow.swift */; };
FD37E9DB28A244E9003AE748 /* ThemePreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD37E9DA28A244E9003AE748 /* ThemePreviewView.swift */; };
FD37E9DD28A384EB003AE748 /* PrimaryColorSelectionView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD37E9DC28A384EB003AE748 /* PrimaryColorSelectionView.swift */; };
FD37E9EF28A5ED70003AE748 /* SessionUtilitiesKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C3C2A679255388CC00C340D1 /* SessionUtilitiesKit.framework */; platformFilter = ios; };
FD37E9F628A5F106003AE748 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD37E9F528A5F106003AE748 /* Configuration.swift */; };
FD37E9F928A5F14A003AE748 /* _001_ThemePreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD37E9F828A5F14A003AE748 /* _001_ThemePreferences.swift */; };
FD37E9FD28A5F216003AE748 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = C3D9E43025676D3D0040E4F3 /* Configuration.swift */; };
FD37E9FF28A5F2CD003AE748 /* Configuration.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD37E9FE28A5F2CD003AE748 /* Configuration.swift */; };
FD37EA0128A60473003AE748 /* UIKit+Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD37EA0028A60473003AE748 /* UIKit+Theme.swift */; };
FD3AABE928306BBD00E5099A /* ThreadPickerViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3AABE828306BBD00E5099A /* ThreadPickerViewModel.swift */; };
FD3C905C27E3FBEF00CD579F /* BatchRequestInfoSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3C905B27E3FBEF00CD579F /* BatchRequestInfoSpec.swift */; };
FD3C906027E410F700CD579F /* FileUploadResponseSpec.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD3C905F27E410F700CD579F /* FileUploadResponseSpec.swift */; };
@ -942,6 +946,13 @@
remoteGlobalIDString = C33FD9AA255A548A00E217F9;
remoteInfo = SignalUtilitiesKit;
};
FD37E9F128A5ED70003AE748 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D221A080169C9E5E00537ABF /* Project object */;
proxyType = 1;
remoteGlobalIDString = C3C2A678255388CC00C340D1;
remoteInfo = SessionUtilitiesKit;
};
FD83B9B427CF200A005E1583 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = D221A080169C9E5E00537ABF /* Project object */;
@ -1005,6 +1016,7 @@
/* Begin PBXFileReference section */
0BF4561630A52BE96F164CF6 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SignalUtilitiesKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SignalUtilitiesKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
0E836037CC97CE5A47735596 /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionSnodeKit.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionSnodeKit.app store release.xcconfig"; path = "Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionSnodeKit/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionSnodeKit.app store release.xcconfig"; sourceTree = "<group>"; };
18EAE958B8C12503F2C294DF /* Pods-GlobalDependencies-SessionUIKit.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-SessionUIKit.app store release.xcconfig"; path = "Target Support Files/Pods-GlobalDependencies-SessionUIKit/Pods-GlobalDependencies-SessionUIKit.app store release.xcconfig"; sourceTree = "<group>"; };
1A0882BF820F5B44969F91F1 /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig"; path = "Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.debug.xcconfig"; sourceTree = "<group>"; };
245BF74EF6348E2D4125033F /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.app store release.xcconfig"; path = "Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-SessionNotificationServiceExtension.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>"; };
@ -1128,11 +1140,11 @@
4CA485BA2232339F004B9E7D /* PhotoCaptureViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PhotoCaptureViewController.swift; sourceTree = "<group>"; };
4CC613352227A00400E21A3A /* ConversationSearch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConversationSearch.swift; sourceTree = "<group>"; };
506FA2159653FF9F446D97D1 /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionMessagingKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionMessagingKit.debug.xcconfig"; path = "Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionMessagingKit/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionMessagingKit.debug.xcconfig"; sourceTree = "<group>"; };
510955DC99A0FD84F2D1C159 /* Pods-GlobalDependencies-SessionUIKit.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-SessionUIKit.debug.xcconfig"; path = "Target Support Files/Pods-GlobalDependencies-SessionUIKit/Pods-GlobalDependencies-SessionUIKit.debug.xcconfig"; sourceTree = "<group>"; };
5442DF945D862CEDF7F8AC49 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionUtilitiesKit_SessionUtilitiesKitTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GlobalDependencies_FrameworkAndExtensionDependencies_ExtendedDependencies_SessionUtilitiesKit_SessionUtilitiesKitTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
5626DC0D5F62C1C2C64E4AFC /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionShareExtension.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionShareExtension.app store release.xcconfig"; path = "Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionShareExtension/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionShareExtension.app store release.xcconfig"; sourceTree = "<group>"; };
56F41C56FC7B2F381E440FB0 /* Pods-GlobalDependencies-Session.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-Session.debug.xcconfig"; path = "Target Support Files/Pods-GlobalDependencies-Session/Pods-GlobalDependencies-Session.debug.xcconfig"; sourceTree = "<group>"; };
58A6BA91F634756FA0BEC9E5 /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit-SessionUtilitiesKitTests.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit-SessionUtilitiesKitTests.app store release.xcconfig"; path = "Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit-SessionUtilitiesKitTests/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionUtilitiesKit-SessionUtilitiesKitTests.app store release.xcconfig"; sourceTree = "<group>"; };
5DEB8C073F5E3C418BFB96C3 /* Pods_SessionUIKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_SessionUIKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6737124ECBC2DFEE2DD716D3 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_SessionSnodeKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GlobalDependencies_FrameworkAndExtensionDependencies_SessionSnodeKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
6BE8FBF62464A7177034A0AB /* Pods-GlobalDependencies-Session.app store release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-Session.app store release.xcconfig"; path = "Target Support Files/Pods-GlobalDependencies-Session/Pods-GlobalDependencies-Session.app store release.xcconfig"; sourceTree = "<group>"; };
6F84A214B9A1C0CCF6DB09C8 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_SessionNotificationServiceExtension.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GlobalDependencies_FrameworkAndExtensionDependencies_SessionNotificationServiceExtension.framework; sourceTree = BUILT_PRODUCTS_DIR; };
@ -1198,6 +1210,7 @@
A1C32D4D17A0652C000A904E /* AddressBook.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBook.framework; path = System/Library/Frameworks/AddressBook.framework; sourceTree = SDKROOT; };
A1C32D4F17A06537000A904E /* AddressBookUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AddressBookUI.framework; path = System/Library/Frameworks/AddressBookUI.framework; sourceTree = SDKROOT; };
A1FDCBEE16DAA6C300868894 /* AVFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AVFoundation.framework; path = System/Library/Frameworks/AVFoundation.framework; sourceTree = SDKROOT; };
A9C58C3ADF46C718488458C2 /* Pods_GlobalDependencies_SessionUIKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_GlobalDependencies_SessionUIKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B60EDE031A05A01700D73516 /* AudioToolbox.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AudioToolbox.framework; path = System/Library/Frameworks/AudioToolbox.framework; sourceTree = SDKROOT; };
B646D10E1AA5461A004133BA /* fr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = fr; path = fr.lproj/Localizable.strings; sourceTree = "<group>"; };
B657DDC91911A40500F45B0C /* Signal.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = Signal.entitlements; sourceTree = "<group>"; };
@ -1608,7 +1621,6 @@
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>"; };
C3F0A5B2255C915C007BE2A3 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
C3F0A5EB255C970D007BE2A3 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
D0CE0424239A1574F683D2D7 /* Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionMessagingKit-SessionMessagingKitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionMessagingKit-SessionMessagingKitTests.debug.xcconfig"; path = "Target Support Files/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionMessagingKit-SessionMessagingKitTests/Pods-GlobalDependencies-FrameworkAndExtensionDependencies-ExtendedDependencies-SessionMessagingKit-SessionMessagingKitTests.debug.xcconfig"; sourceTree = "<group>"; };
D2179CFB16BB0B3A0006F3AB /* CoreTelephony.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreTelephony.framework; path = System/Library/Frameworks/CoreTelephony.framework; sourceTree = SDKROOT; };
D2179CFD16BB0B480006F3AB /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
@ -1707,6 +1719,10 @@
FD37E9D828A230F2003AE748 /* TraitObservingWindow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TraitObservingWindow.swift; sourceTree = "<group>"; };
FD37E9DA28A244E9003AE748 /* ThemePreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemePreviewView.swift; sourceTree = "<group>"; };
FD37E9DC28A384EB003AE748 /* PrimaryColorSelectionView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrimaryColorSelectionView.swift; sourceTree = "<group>"; };
FD37E9F528A5F106003AE748 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
FD37E9F828A5F14A003AE748 /* _001_ThemePreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = _001_ThemePreferences.swift; sourceTree = "<group>"; };
FD37E9FE28A5F2CD003AE748 /* Configuration.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Configuration.swift; sourceTree = "<group>"; };
FD37EA0028A60473003AE748 /* UIKit+Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIKit+Theme.swift"; sourceTree = "<group>"; };
FD3AABE828306BBD00E5099A /* ThreadPickerViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreadPickerViewModel.swift; sourceTree = "<group>"; };
FD3C905B27E3FBEF00CD579F /* BatchRequestInfoSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchRequestInfoSpec.swift; sourceTree = "<group>"; };
FD3C905F27E410F700CD579F /* FileUploadResponseSpec.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FileUploadResponseSpec.swift; sourceTree = "<group>"; };
@ -1902,7 +1918,8 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
63A15A5E6605581543B4A5B4 /* Pods_SessionUIKit.framework in Frameworks */,
FD37E9EF28A5ED70003AE748 /* SessionUtilitiesKit.framework in Frameworks */,
821EFD1644285AC2D3733D27 /* Pods_GlobalDependencies_SessionUIKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -2028,6 +2045,8 @@
6BE8FBF62464A7177034A0AB /* Pods-GlobalDependencies-Session.app store release.xcconfig */,
EC5C23F9D234F558BE5E41DE /* Pods-SessionUIKit.debug.xcconfig */,
29CF8C79F41BF00B1C2E59A0 /* Pods-SessionUIKit.app store release.xcconfig */,
510955DC99A0FD84F2D1C159 /* Pods-GlobalDependencies-SessionUIKit.debug.xcconfig */,
18EAE958B8C12503F2C294DF /* Pods-GlobalDependencies-SessionUIKit.app store release.xcconfig */,
);
path = Pods;
sourceTree = "<group>";
@ -2677,9 +2696,11 @@
isa = PBXGroup;
children = (
C331FF422558F9E400070591 /* Meta */,
FD37E9F428A5F0FB003AE748 /* Database */,
C331FFCC2558FAF300070591 /* Components */,
C331FF5E2558FA0F00070591 /* Style Guide */,
C331FFAE2558FA7700070591 /* Utilities */,
FD37E9F528A5F106003AE748 /* Configuration.swift */,
);
path = SessionUIKit;
sourceTree = "<group>";
@ -2738,7 +2759,6 @@
isa = PBXGroup;
children = (
C33FD9B7255A54A300E217F9 /* Meta */,
C3F0A5EB255C970D007BE2A3 /* Configuration.swift */,
C36096ED25AD20FD008B62B2 /* Media Viewing & Editing */,
C38BBA0D255E321C0041B9A3 /* Messaging */,
C36096EF25AD2268008B62B2 /* Profile Pictures */,
@ -2746,6 +2766,7 @@
C3851CD225624B060061EEB0 /* Shared Views */,
C360970125AD22D3008B62B2 /* Shared View Controllers */,
C3CA3B11255CF17200F4C6D4 /* Utilities */,
C3D9E43025676D3D0040E4F3 /* Configuration.swift */,
);
path = SignalUtilitiesKit;
sourceTree = "<group>";
@ -3147,8 +3168,7 @@
B8A582AE258C65D000AFD84C /* Networking */,
B8A582AD258C655E00AFD84C /* PromiseKit */,
FD09796527F6B0A800936362 /* Utilities */,
FDCDB8EF2817ABCE00352A0C /* Utilities */,
C3D9E43025676D3D0040E4F3 /* Configuration.swift */,
FD37E9FE28A5F2CD003AE748 /* Configuration.swift */,
);
path = SessionUtilitiesKit;
sourceTree = "<group>";
@ -3411,7 +3431,7 @@
6F84A214B9A1C0CCF6DB09C8 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_SessionNotificationServiceExtension.framework */,
6737124ECBC2DFEE2DD716D3 /* Pods_GlobalDependencies_FrameworkAndExtensionDependencies_SessionSnodeKit.framework */,
48AD214D67ABED845101E795 /* Pods_GlobalDependencies_Session.framework */,
5DEB8C073F5E3C418BFB96C3 /* Pods_SessionUIKit.framework */,
A9C58C3ADF46C718488458C2 /* Pods_GlobalDependencies_SessionUIKit.framework */,
);
name = Frameworks;
sourceTree = "<group>";
@ -3447,6 +3467,7 @@
FD09797127FAA2F500936362 /* Optional+Utilities.swift */,
FD09797C27FBDB2000936362 /* Notification+Utilities.swift */,
FDF222082818D2B0000A4995 /* NSAttributedString+Utilities.swift */,
FDCDB8F02817ABE600352A0C /* Optional+Utilities.swift */,
);
path = Utilities;
sourceTree = "<group>";
@ -3605,6 +3626,7 @@
FD37E9C928A1E4BD003AE748 /* Theme+ClassicLight.swift */,
FD37E9D228A1FCDB003AE748 /* Theme+OceanDark.swift */,
FD37E9D428A1FCE8003AE748 /* Theme+OceanLight.swift */,
FD37EA0028A60473003AE748 /* UIKit+Theme.swift */,
);
path = Themes;
sourceTree = "<group>";
@ -3619,6 +3641,22 @@
path = Views;
sourceTree = "<group>";
};
FD37E9F428A5F0FB003AE748 /* Database */ = {
isa = PBXGroup;
children = (
FD37E9F728A5F143003AE748 /* Migrations */,
);
path = Database;
sourceTree = "<group>";
};
FD37E9F728A5F143003AE748 /* Migrations */ = {
isa = PBXGroup;
children = (
FD37E9F828A5F14A003AE748 /* _001_ThemePreferences.swift */,
);
path = Migrations;
sourceTree = "<group>";
};
FD3C905D27E410DB00CD579F /* Common Networking */ = {
isa = PBXGroup;
children = (
@ -3908,14 +3946,6 @@
path = Models;
sourceTree = "<group>";
};
FDCDB8EF2817ABCE00352A0C /* Utilities */ = {
isa = PBXGroup;
children = (
FDCDB8F02817ABE600352A0C /* Optional+Utilities.swift */,
);
path = Utilities;
sourceTree = "<group>";
};
FDE7214E287E50D50093DF33 /* Scripts */ = {
isa = PBXGroup;
children = (
@ -4107,6 +4137,7 @@
buildRules = (
);
dependencies = (
FD37E9F228A5ED70003AE748 /* PBXTargetDependency */,
);
name = SessionUIKit;
productName = SessionUIKit;
@ -4633,7 +4664,7 @@
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-SessionUIKit-checkManifestLockResult.txt",
"$(DERIVED_FILE_DIR)/Pods-GlobalDependencies-SessionUIKit-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
@ -4880,13 +4911,16 @@
C331FFE32558FB0000070591 /* TabBar.swift in Sources */,
FD37E9D528A1FCE8003AE748 /* Theme+OceanLight.swift in Sources */,
FD37E9C828A1D73F003AE748 /* Theme+PrimaryColors.swift in Sources */,
FD37EA0128A60473003AE748 /* UIKit+Theme.swift in Sources */,
FD37E9CF28A1EB1B003AE748 /* Theme.swift in Sources */,
C331FFB92558FA8D00070591 /* UIView+Constraints.swift in Sources */,
C331FF962558FA6B00070591 /* Colors.swift in Sources */,
FD37E9F628A5F106003AE748 /* Configuration.swift in Sources */,
C331FFE02558FB0000070591 /* SearchBar.swift in Sources */,
C331FF982558FA6B00070591 /* AppMode.swift in Sources */,
C331FFE82558FB0000070591 /* TextView.swift in Sources */,
FD37E9D728A20B5D003AE748 /* UIColor+Utilities.swift in Sources */,
FD37E9F928A5F14A003AE748 /* _001_ThemePreferences.swift in Sources */,
FD37E9C328A1C6F3003AE748 /* ThemeManager.swift in Sources */,
C331FF9A2558FA6B00070591 /* Values.swift in Sources */,
FD37E9C628A1D4EC003AE748 /* Theme+ClassicDark.swift in Sources */,
@ -4909,6 +4943,7 @@
C33FDC7D255A582000E217F9 /* OWSDispatch.m in Sources */,
C38EF247255B6D67007E1867 /* NSAttributedString+OWS.m in Sources */,
C33FDD49255A582000E217F9 /* ParamParser.swift in Sources */,
FD37E9FD28A5F216003AE748 /* Configuration.swift in Sources */,
C38EF3C5255B6DE7007E1867 /* OWSViewController+ImageEditor.swift in Sources */,
C38EF2A5255B6D93007E1867 /* Identicon+ObjC.swift in Sources */,
C38EF385255B6DD2007E1867 /* AttachmentTextToolbar.swift in Sources */,
@ -4929,7 +4964,6 @@
C38EF3C1255B6DE7007E1867 /* ImageEditorBrushViewController.swift in Sources */,
C33FDD32255A582000E217F9 /* OWSOperation.m in Sources */,
C3F0A530255C80BC007BE2A3 /* NoopNotificationsManager.swift in Sources */,
C3D90A7A25773A93002C9DF5 /* Configuration.swift in Sources */,
C33FDD8D255A582000E217F9 /* OWSSignalAddress.swift in Sources */,
C38EF388255B6DD2007E1867 /* AttachmentApprovalViewController.swift in Sources */,
C38EF2A7255B6D93007E1867 /* ProfilePictureView.swift in Sources */,
@ -5067,7 +5101,6 @@
FDCDB8E42817819600352A0C /* (null) in Sources */,
C32C5DC9256DD935003C73A2 /* ProxiedContentDownloader.swift in Sources */,
C3D9E4C02567767F0040E4F3 /* DataSource.m in Sources */,
C3D9E43125676D3D0040E4F3 /* Configuration.swift in Sources */,
C32C5DD2256DD9E5003C73A2 /* LRUCache.swift in Sources */,
FD9004152818B46300ABAAF6 /* JobRunner.swift in Sources */,
C3A7211A2558BCA10043A11F /* DiffieHellman.swift in Sources */,
@ -5077,6 +5110,7 @@
C3BBE0AA2554D4DE0050F1E3 /* Dictionary+Utilities.swift in Sources */,
C3D9E4DA256778410040E4F3 /* UIImage+OWS.m in Sources */,
C32C600F256E07F5003C73A2 /* NSUserDefaults+OWS.m in Sources */,
FD37E9FF28A5F2CD003AE748 /* Configuration.swift in Sources */,
C3D9E35E25675F640040E4F3 /* OWSFileSystem.m in Sources */,
FD09797D27FBDB2000936362 /* Notification+Utilities.swift in Sources */,
FDC6D7602862B3F600B04575 /* Dependencies.swift in Sources */,
@ -5645,6 +5679,12 @@
target = C33FD9AA255A548A00E217F9 /* SignalUtilitiesKit */;
targetProxy = C3D90A7025773A44002C9DF5 /* PBXContainerItemProxy */;
};
FD37E9F228A5ED70003AE748 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
platformFilter = ios;
target = C3C2A678255388CC00C340D1 /* SessionUtilitiesKit */;
targetProxy = FD37E9F128A5ED70003AE748 /* PBXContainerItemProxy */;
};
FD83B9B527CF200A005E1583 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = C3C2A678255388CC00C340D1 /* SessionUtilitiesKit */;
@ -5989,7 +6029,7 @@
};
C331FF242558F9D400070591 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = EC5C23F9D234F558BE5E41DE /* Pods-SessionUIKit.debug.xcconfig */;
baseConfigurationReference = 510955DC99A0FD84F2D1C159 /* Pods-GlobalDependencies-SessionUIKit.debug.xcconfig */;
buildSettings = {
APPLICATION_EXTENSION_API_ONLY = YES;
CLANG_ANALYZER_NONNULL = YES;
@ -6046,7 +6086,7 @@
};
C331FF252558F9D400070591 /* App Store Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 29CF8C79F41BF00B1C2E59A0 /* Pods-SessionUIKit.app store release.xcconfig */;
baseConfigurationReference = 18EAE958B8C12503F2C294DF /* Pods-GlobalDependencies-SessionUIKit.app store release.xcconfig */;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
APPLICATION_EXTENSION_API_ONLY = YES;

View File

@ -82,8 +82,6 @@ final class EditClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegat
override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
setUpNavBarStyle()
setNavBarTitle("Edit Group")
let backButton = UIBarButtonItem(title: "Back", style: .plain, target: nil, action: nil)

View File

@ -45,9 +45,6 @@ final class NewClosedGroupVC: BaseVC, UITableViewDataSource, UITableViewDelegate
override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
setUpNavBarStyle()
let customTitleFontSize = Values.largeFontSize
setNavBarTitle("vc_create_closed_group_title".localized(), customFontSize: customTitleFontSize)

View File

@ -317,11 +317,6 @@ final class ConversationVC: BaseVC, OWSConversationSettingsViewDelegate, Convers
override func viewDidLoad() {
super.viewDidLoad()
// Gradient
setUpGradientBackground()
// Nav bar
setUpNavBarStyle()
navigationItem.titleView = titleView
// Note: We need to update the nav bar buttons here (with invalid data) because if we don't the

View File

@ -185,32 +185,40 @@ final class QuoteView: UIView {
let isOutgoing = (direction == .outgoing)
bodyLabel.font = .systemFont(ofSize: Values.smallFontSize)
bodyLabel.attributedText = body
.map {
MentionUtilities.highlightMentions(
in: $0,
threadVariant: threadVariant,
currentUserPublicKey: currentUserPublicKey,
currentUserBlindedPublicKey: currentUserBlindedPublicKey,
isOutgoingMessage: isOutgoing,
attributes: [:]
)
}
.defaulting(
to: attachment.map {
NSAttributedString(string: MIMETypeUtil.isAudio($0.contentType) ? "Audio" : "Document")
}
)
.defaulting(to: NSAttributedString(string: "Document"))
bodyLabel.themeTextColor = (direction == .outgoing ?
.messageBubble_outgoingText :
.messageBubble_incomingText
)
let bodyLabelSize = bodyLabel.systemLayoutSizeFitting(availableSpace)
ThemeManager.onThemeChange(observer: bodyLabel) { [weak bodyLabel] theme, primaryColor in
let targetThemeColor: ThemeValue = (direction == .outgoing ?
.messageBubble_outgoingText :
.messageBubble_incomingText
)
guard let textColor: UIColor = theme.colors[targetThemeColor] else { return }
bodyLabel?.attributedText = body
.map {
MentionUtilities.highlightMentions(
in: $0,
threadVariant: threadVariant,
currentUserPublicKey: currentUserPublicKey,
currentUserBlindedPublicKey: currentUserBlindedPublicKey,
isOutgoingMessage: isOutgoing,
textColor: textColor,
primaryColor: primaryColor,
attributes: [:]
)
}
.defaulting(
to: attachment.map {
NSAttributedString(string: MIMETypeUtil.isAudio($0.contentType) ? "Audio" : "Document")
}
)
.defaulting(to: NSAttributedString(string: "Document"))
}
// Label stack view
let bodyLabelSize = bodyLabel.systemLayoutSizeFitting(availableSpace)
var authorLabelHeight: CGFloat?
if threadVariant == .openGroup || threadVariant == .closedGroup {
let isCurrentUser: Bool = [
currentUserPublicKey,

View File

@ -300,10 +300,12 @@ final class VisibleMessageCell: MessageCell, UITextViewDelegate, BodyTextViewDel
authorLabelHeightConstraint.constant = (cellViewModel.senderName != nil ? authorLabelSize.height : 0)
// Message status image view
let (image, tintColor, backgroundColor) = getMessageStatusImage(for: cellViewModel)
let (image, tintColor) = cellViewModel.state.statusIconInfo(
variant: cellViewModel.variant,
hasAtLeastOneReadReceipt: cellViewModel.hasAtLeastOneReadReceipt
)
messageStatusImageView.image = image
messageStatusImageView.themeTintColor = tintColor
messageStatusImageView.themeBackgroundColor = backgroundColor
messageStatusImageView.isHidden = (
cellViewModel.variant != .standardOutgoing ||
cellViewModel.variant == .infoCall ||
@ -838,34 +840,6 @@ final class VisibleMessageCell: MessageCell, UITextViewDelegate, BodyTextViewDel
}
}
private func getMessageStatusImage(for cellViewModel: MessageViewModel) -> (image: UIImage?, tintColor: ThemeValue?, backgroundColor: ThemeValue?) {
guard cellViewModel.variant == .standardOutgoing else { return (nil, nil, nil) }
let image: UIImage
var tintColor: ThemeValue? = nil
var backgroundColor: ThemeValue? = nil
switch (cellViewModel.state, cellViewModel.hasAtLeastOneReadReceipt) {
case (.sending, _):
image = #imageLiteral(resourceName: "CircleDotDotDot").withRenderingMode(.alwaysTemplate)
tintColor = .textPrimary
case (.sent, false), (.skipped, _):
image = #imageLiteral(resourceName: "CircleCheck").withRenderingMode(.alwaysTemplate)
tintColor = .textPrimary
case (.sent, true):
image = isLightMode ? #imageLiteral(resourceName: "FilledCircleCheckLightMode") : #imageLiteral(resourceName: "FilledCircleCheckDarkMode")
backgroundColor = isLightMode ? .black : .white
case (.failed, _):
image = #imageLiteral(resourceName: "message_status_failed").withRenderingMode(.alwaysTemplate)
tintColor = .danger
}
return (image, tintColor, backgroundColor)
}
private func getSize(for cellViewModel: MessageViewModel) -> CGSize {
guard let mediaAttachments: [Attachment] = cellViewModel.attachments?.filter({ $0.isVisualMedia }) else {
preconditionFailure()
@ -959,7 +933,7 @@ final class VisibleMessageCell: MessageCell, UITextViewDelegate, BodyTextViewDel
result.isUserInteractionEnabled = true
result.delegate = delegate
ThemeManager.onThemeChange(observer: result) { [weak result] theme, _ in
ThemeManager.onThemeChange(observer: result) { [weak result] theme, primaryColor in
guard
let actualTextColor: UIColor = theme.colors[textColor],
let backgroundPrimaryColor: UIColor = theme.colors[.backgroundPrimary],
@ -975,6 +949,8 @@ final class VisibleMessageCell: MessageCell, UITextViewDelegate, BodyTextViewDel
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
isOutgoingMessage: isOutgoing,
textColor: actualTextColor,
primaryColor: primaryColor,
attributes: [
.foregroundColor: actualTextColor,
.font: UIFont.systemFont(ofSize: getFontSize(for: cellViewModel))

View File

@ -25,9 +25,9 @@ final class ProfilePictureVC: BaseVC {
override func viewDidLoad() {
view.backgroundColor = .clear
setUpGradientBackground()
setUpNavBarStyle()
setNavBarTitle(snTitle)
// Close button
let closeButton = UIBarButtonItem(image: #imageLiteral(resourceName: "X"), style: .plain, target: self, action: #selector(close))
closeButton.tintColor = Colors.text

View File

@ -62,9 +62,8 @@ final class NewDMVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControll
// MARK: Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
setUpNavBarStyle()
setNavBarTitle(NSLocalizedString("vc_create_private_chat_title", comment: ""))
setNavBarTitle("vc_create_private_chat_title".localized())
let navigationBar = navigationController!.navigationBar
// Set up navigation bar buttons
let closeButton = UIBarButtonItem(image: #imageLiteral(resourceName: "X"), style: .plain, target: self, action: #selector(close))

View File

@ -9,10 +9,11 @@ import NVActivityIndicatorView
class EmptySearchResultCell: UITableViewCell {
private lazy var messageLabel: UILabel = {
let result = UILabel()
result.text = "CONVERSATION_SEARCH_NO_RESULTS".localized()
result.themeTextColor = .textPrimary
result.textAlignment = .center
result.numberOfLines = 3
result.textColor = Colors.text
result.text = NSLocalizedString("CONVERSATION_SEARCH_NO_RESULTS", comment: "")
return result
}()
@ -20,12 +21,14 @@ class EmptySearchResultCell: UITableViewCell {
let result = NVActivityIndicatorView(frame: CGRect.zero, type: .circleStrokeSpin, color: Colors.text, padding: nil)
result.set(.width, to: 40)
result.set(.height, to: 40)
return result
}()
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
backgroundColor = .clear
themeBackgroundColor = .clear
selectionStyle = .none
contentView.addSubview(messageLabel)
@ -54,7 +57,8 @@ class EmptySearchResultCell: UITableViewCell {
spinner.stopAnimating()
spinner.startAnimating()
messageLabel.isHidden = true
} else {
}
else {
spinner.stopAnimating()
messageLabel.isHidden = false
}

View File

@ -50,9 +50,10 @@ class GlobalSearchViewController: BaseVC, UITableViewDelegate, UITableViewDataSo
internal lazy var searchBar: SearchBar = {
let result: SearchBar = SearchBar()
result.tintColor = Colors.text
result.themeTintColor = .textPrimary
result.delegate = self
result.showsCancelButton = true
return result
}()
@ -74,8 +75,6 @@ class GlobalSearchViewController: BaseVC, UITableViewDelegate, UITableViewDataSo
public override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
tableView.dataSource = self
tableView.delegate = self
view.addSubview(tableView)
@ -116,9 +115,10 @@ class GlobalSearchViewController: BaseVC, UITableViewDelegate, UITableViewDataSo
if UIDevice.current.isIPad {
let ipadCancelButton = UIButton()
ipadCancelButton.setTitle("Cancel", for: .normal)
ipadCancelButton.setThemeTitleColor(.textPrimary, for: .normal)
ipadCancelButton.addTarget(self, action: #selector(cancel), for: .touchUpInside)
ipadCancelButton.setTitleColor(Colors.text, for: .normal)
searchBarContainer.addSubview(ipadCancelButton)
ipadCancelButton.pin(.trailing, to: .trailing, of: searchBarContainer)
ipadCancelButton.autoVCenterInSuperview()
searchBar.autoPinEdgesToSuperviewEdges(with: UIEdgeInsets.zero, excludingEdge: .trailing)
@ -312,16 +312,19 @@ extension GlobalSearchViewController {
}
let titleLabel = UILabel()
titleLabel.font = .boldSystemFont(ofSize: Values.largeFontSize)
titleLabel.text = title
titleLabel.textColor = Colors.text
titleLabel.font = .boldSystemFont(ofSize: Values.mediumFontSize)
titleLabel.themeTextColor = .textPrimary
let container = UIView()
container.backgroundColor = Colors.cellBackground
container.layoutMargins = UIEdgeInsets(top: Values.smallSpacing, left: Values.mediumSpacing, bottom: Values.smallSpacing, right: Values.mediumSpacing)
container.themeBackgroundColor = .backgroundPrimary
container.addSubview(titleLabel)
titleLabel.autoPinEdgesToSuperviewMargins()
titleLabel.pin(.top, to: .top, of: container, withInset: Values.mediumSpacing)
titleLabel.pin(.bottom, to: .bottom, of: container, withInset: -Values.mediumSpacing)
titleLabel.pin(.left, to: .left, of: container, withInset: Values.largeSpacing)
titleLabel.pin(.right, to: .right, of: container, withInset: -Values.largeSpacing)
return container
}

View File

@ -41,14 +41,21 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
private lazy var seedReminderView: SeedReminderView = {
let result = SeedReminderView(hasContinueButton: true)
let title = "You're almost finished! 80%"
let attributedTitle = NSMutableAttributedString(string: title)
attributedTitle.addAttribute(.foregroundColor, value: Colors.accent, range: (title as NSString).range(of: "80%"))
result.title = attributedTitle
result.subtitle = NSLocalizedString("view_seed_reminder_subtitle_1", comment: "")
result.subtitle = "view_seed_reminder_subtitle_1".localized()
result.setProgress(0.8, animated: false)
result.delegate = self
result.isHidden = !self.viewModel.state.showViewedSeedBanner
ThemeManager.onThemeChange(observer: result) { [weak result] _, primaryColor in
let attributedTitle = NSMutableAttributedString(string: title)
attributedTitle.addAttribute(
.foregroundColor,
value: primaryColor.color,
range: (title as NSString).range(of: "80%")
)
result?.title = attributedTitle
}
return result
}()
@ -56,7 +63,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
let result: UILabel = UILabel()
result.font = UIFont.systemFont(ofSize: Values.smallFontSize)
result.text = "LOADING_CONVERSATIONS".localized()
result.textColor = Colors.text
result.themeTextColor = .textPrimary
result.textAlignment = .center
result.numberOfLines = 0
@ -65,7 +72,6 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
private lazy var tableView: UITableView = {
let result = UITableView()
result.backgroundColor = .clear
result.separatorStyle = .none
result.contentInset = UIEdgeInsets(
top: 0,
@ -94,23 +100,15 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
private lazy var newConversationButtonSet: NewConversationButtonSet = {
let result = NewConversationButtonSet()
result.delegate = self
return result
}()
private lazy var fadeView: UIView = {
let result = UIView()
let gradient = Gradients.homeVCFade
result.setGradient(gradient)
result.isUserInteractionEnabled = false
return result
}()
private lazy var emptyStateView: UIView = {
let explanationLabel = UILabel()
explanationLabel.font = .systemFont(ofSize: Values.smallFontSize)
explanationLabel.text = "vc_home_empty_state_message".localized()
explanationLabel.textColor = Colors.text
explanationLabel.themeTextColor = .textPrimary
explanationLabel.textAlignment = .center
explanationLabel.lineBreakMode = .byWordWrapping
explanationLabel.numberOfLines = 0
@ -142,11 +140,6 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
// Preparation
SessionApp.homeViewController.mutate { $0 = self }
// Gradient & nav bar
setUpGradientBackground()
if navigationController?.navigationBar != nil {
setUpNavBarStyle()
}
updateNavBarButtons()
setUpNavBarSessionHeading()
@ -174,12 +167,6 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
}
tableView.pin(.trailing, to: .trailing, of: view)
tableView.pin(.bottom, to: .bottom, of: view)
view.addSubview(fadeView)
fadeView.pin(.leading, to: .leading, of: view)
let topInset = 0.15 * view.height()
fadeView.pin(.top, to: .top, of: view, withInset: topInset)
fadeView.pin(.trailing, to: .trailing, of: view)
fadeView.pin(.bottom, to: .bottom, of: view)
// Empty state view
view.addSubview(emptyStateView)
@ -431,14 +418,6 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
rightBarButtonItem.isAccessibilityElement = true
navigationItem.rightBarButtonItem = rightBarButtonItem
}
@objc override internal func handleAppModeChangedNotification(_ notification: Notification) {
super.handleAppModeChangedNotification(notification)
let gradient = Gradients.homeVCFade
fadeView.setGradient(gradient) // Re-do the gradient
tableView.reloadData()
}
// MARK: - UITableViewDataSource
@ -478,7 +457,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
switch section.model {
case .loadMore:
let loadingIndicator: UIActivityIndicatorView = UIActivityIndicatorView(style: .medium)
loadingIndicator.tintColor = Colors.text
loadingIndicator.themeTintColor = .textPrimary
loadingIndicator.alpha = 0.5
loadingIndicator.startAnimating()
@ -557,7 +536,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
let hide = UITableViewRowAction(style: .destructive, title: "TXT_HIDE_TITLE".localized()) { _, _ in
Storage.shared.write { db in db[.hasHiddenMessageRequests] = true }
}
hide.backgroundColor = Colors.destructive
hide.themeBackgroundColor = .danger
return [hide]
@ -606,7 +585,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
self?.present(alert, animated: true, completion: nil)
}
delete.backgroundColor = Colors.destructive
delete.themeBackgroundColor = .danger
let pin: UITableViewRowAction = UITableViewRowAction(
style: .normal,
@ -621,6 +600,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
.updateAll(db, SessionThread.Columns.isPinned.set(to: !threadViewModel.threadIsPinned))
}
}
pin.themeBackgroundColor = .conversationButton_pinBackground
guard threadViewModel.threadVariant == .contact && !threadViewModel.threadIsNoteToSelf else {
return [ delete, pin ]
@ -650,7 +630,7 @@ final class HomeVC: BaseVC, UITableViewDataSource, UITableViewDelegate, NewConve
.retainUntilComplete()
}
}
block.backgroundColor = Colors.unimportant
block.themeBackgroundColor = .backgroundTertiary
return [ delete, block, pin ]

View File

@ -69,15 +69,6 @@ class MessageRequestsViewController: BaseVC, UITableViewDelegate, UITableViewDat
return result
}()
private lazy var fadeView: UIView = {
let result: UIView = UIView()
result.translatesAutoresizingMaskIntoConstraints = false
result.isUserInteractionEnabled = false
result.setGradient(Gradients.homeVCFade)
return result
}()
private lazy var clearAllButton: OutlineButton = {
let result: OutlineButton = OutlineButton(style: .destructive, size: .medium)
result.translatesAutoresizingMaskIntoConstraints = false
@ -102,7 +93,6 @@ class MessageRequestsViewController: BaseVC, UITableViewDelegate, UITableViewDat
// the dataSource has the correct data)
view.addSubview(tableView)
view.addSubview(emptyStateLabel)
view.addSubview(fadeView)
view.addSubview(clearAllButton)
setupLayout()
@ -162,12 +152,7 @@ class MessageRequestsViewController: BaseVC, UITableViewDelegate, UITableViewDat
emptyStateLabel.leftAnchor.constraint(equalTo: view.leftAnchor, constant: Values.mediumSpacing),
emptyStateLabel.rightAnchor.constraint(equalTo: view.rightAnchor, constant: -Values.mediumSpacing),
emptyStateLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor),
fadeView.topAnchor.constraint(equalTo: view.topAnchor, constant: (0.15 * view.bounds.height)),
fadeView.leftAnchor.constraint(equalTo: view.leftAnchor),
fadeView.rightAnchor.constraint(equalTo: view.rightAnchor),
fadeView.bottomAnchor.constraint(equalTo: view.bottomAnchor),
clearAllButton.centerXAnchor.constraint(equalTo: view.centerXAnchor),
clearAllButton.bottomAnchor.constraint(
equalTo: view.safeAreaLayoutGuide.bottomAnchor,
@ -259,14 +244,6 @@ class MessageRequestsViewController: BaseVC, UITableViewDelegate, UITableViewDat
}
}
}
@objc override internal func handleAppModeChangedNotification(_ notification: Notification) {
super.handleAppModeChangedNotification(notification)
let gradient = Gradients.homeVCFade
fadeView.setGradient(gradient) // Re-do the gradient
tableView.reloadData()
}
// MARK: - UITableViewDataSource

View File

@ -28,7 +28,7 @@ class MessageRequestsCell: UITableViewCell {
let result: UIView = UIView()
result.translatesAutoresizingMaskIntoConstraints = false
result.clipsToBounds = true
result.backgroundColor = Colors.sessionMessageRequestsBubble
result.themeBackgroundColor = .conversationButton_unreadBubbleBackground
result.layer.cornerRadius = (Values.mediumProfilePictureSize / 2)
return result
@ -37,7 +37,7 @@ class MessageRequestsCell: UITableViewCell {
private let iconImageView: UIImageView = {
let result: UIImageView = UIImageView(image: #imageLiteral(resourceName: "message_requests").withRenderingMode(.alwaysTemplate))
result.translatesAutoresizingMaskIntoConstraints = false
result.tintColor = Colors.sessionMessageRequestsIcon
result.themeTintColor = .conversationButton_unreadBubbleText
return result
}()
@ -48,8 +48,8 @@ class MessageRequestsCell: UITableViewCell {
result.setContentHuggingPriority(.defaultHigh, for: .horizontal)
result.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
result.font = .boldSystemFont(ofSize: Values.mediumFontSize)
result.text = NSLocalizedString("MESSAGE_REQUESTS_TITLE", comment: "")
result.textColor = Colors.sessionMessageRequestsTitle
result.text = "MESSAGE_REQUESTS_TITLE".localized()
result.themeTextColor = .textPrimary
result.lineBreakMode = .byTruncatingTail
return result
@ -59,7 +59,7 @@ class MessageRequestsCell: UITableViewCell {
let result: UIView = UIView()
result.translatesAutoresizingMaskIntoConstraints = false
result.clipsToBounds = true
result.backgroundColor = Colors.text.withAlphaComponent(Values.veryLowOpacity)
result.themeBackgroundColor = .conversationButton_unreadBubbleBackground
result.layer.cornerRadius = (FullConversationCell.unreadCountViewSize / 2)
return result
@ -69,17 +69,16 @@ class MessageRequestsCell: UITableViewCell {
let result = UILabel()
result.translatesAutoresizingMaskIntoConstraints = false
result.font = .boldSystemFont(ofSize: Values.verySmallFontSize)
result.textColor = Colors.text
result.themeTextColor = .conversationButton_unreadBubbleText
result.textAlignment = .center
return result
}()
private func setUpViewHierarchy() {
backgroundColor = Colors.cellPinned
themeBackgroundColor = .conversationButton_unreadBackground
selectedBackgroundView = UIView()
selectedBackgroundView?.backgroundColor = Colors.cellSelected
selectedBackgroundView?.themeBackgroundColor = .conversationButton_unreadHighlight
contentView.addSubview(iconContainerView)
contentView.addSubview(titleLabel)
@ -115,7 +114,7 @@ class MessageRequestsCell: UITableViewCell {
unreadCountView.leftAnchor.constraint(equalTo: titleLabel.rightAnchor, constant: (Values.smallSpacing / 2)),
unreadCountView.centerYAnchor.constraint(equalTo: titleLabel.centerYAnchor),
unreadCountView.widthAnchor.constraint(equalToConstant: FullConversationCell.unreadCountViewSize),
unreadCountView.widthAnchor.constraint(greaterThanOrEqualToConstant: FullConversationCell.unreadCountViewSize),
unreadCountView.heightAnchor.constraint(equalToConstant: FullConversationCell.unreadCountViewSize),
unreadCountLabel.topAnchor.constraint(equalTo: unreadCountView.topAnchor),

View File

@ -8,7 +8,8 @@ final class NewConversationButtonSet : UIView {
private var expandedButton: NewConversationButton?
var delegate: NewConversationButtonSetDelegate?
// MARK: Settings
// MARK: - Settings
private let spacing = Values.veryLargeSpacing
private let iconSize = CGFloat(24)
private let maxDragDistance = CGFloat(56)
@ -16,53 +17,81 @@ final class NewConversationButtonSet : UIView {
static let collapsedButtonSize = CGFloat(60)
static let expandedButtonSize = CGFloat(72)
// MARK: Components
// MARK: - Components
private lazy var mainButton = NewConversationButton(isMainButton: true, icon: #imageLiteral(resourceName: "Plus").scaled(to: CGSize(width: iconSize, height: iconSize)))
private lazy var newDMButton = NewConversationButton(isMainButton: false, icon: #imageLiteral(resourceName: "Message").scaled(to: CGSize(width: iconSize, height: iconSize)))
private lazy var createClosedGroupButton = NewConversationButton(isMainButton: false, icon: #imageLiteral(resourceName: "Group").scaled(to: CGSize(width: iconSize, height: iconSize)))
private lazy var joinOpenGroupButton = NewConversationButton(isMainButton: false, icon: #imageLiteral(resourceName: "Globe").scaled(to: CGSize(width: iconSize, height: iconSize)))
private lazy var newDMLabel: UILabel = {
let result: UILabel = UILabel()
private lazy var newDMLabel: UIView = {
let result: UIView = UIView()
result.translatesAutoresizingMaskIntoConstraints = false
result.font = UIFont.systemFont(ofSize: Values.verySmallFontSize, weight: .bold)
result.text = NSLocalizedString("NEW_CONVERSATION_MENU_DIRECT_MESSAGE", comment: "").uppercased()
result.textColor = Colors.grey
result.textAlignment = .center
result.themeBackgroundColor = .backgroundPrimary
result.layer.cornerRadius = 4
let label: UILabel = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = .boldSystemFont(ofSize: Values.verySmallFontSize)
label.text = "NEW_CONVERSATION_MENU_DIRECT_MESSAGE".localized().uppercased()
label.themeTextColor = .textPrimary
label.textAlignment = .center
result.addSubview(label)
label.pin(to: result, withInset: 4)
return result
}()
private lazy var createClosedGroupLabel: UILabel = {
let result: UILabel = UILabel()
private lazy var createClosedGroupLabel: UIView = {
let result: UIView = UIView()
result.translatesAutoresizingMaskIntoConstraints = false
result.font = UIFont.systemFont(ofSize: Values.verySmallFontSize, weight: .bold)
result.text = NSLocalizedString("NEW_CONVERSATION_MENU_CLOSED_GROUP", comment: "").uppercased()
result.textColor = Colors.grey
result.textAlignment = .center
result.themeBackgroundColor = .backgroundPrimary
result.layer.cornerRadius = 4
let label: UILabel = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = .boldSystemFont(ofSize: Values.verySmallFontSize)
label.text = "NEW_CONVERSATION_MENU_CLOSED_GROUP".localized().uppercased()
label.themeTextColor = .textPrimary
label.textAlignment = .center
result.addSubview(label)
label.pin(to: result, withInset: 4)
return result
}()
private lazy var joinOpenGroupLabel: UILabel = {
let result: UILabel = UILabel()
private lazy var joinOpenGroupLabel: UIView = {
let result: UIView = UIView()
result.translatesAutoresizingMaskIntoConstraints = false
result.font = UIFont.systemFont(ofSize: Values.verySmallFontSize, weight: .bold)
result.text = NSLocalizedString("NEW_CONVERSATION_MENU_OPEN_GROUP", comment: "").uppercased()
result.textColor = Colors.grey
result.textAlignment = .center
result.themeBackgroundColor = .backgroundPrimary
result.layer.cornerRadius = 4
let label: UILabel = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
label.font = .boldSystemFont(ofSize: Values.verySmallFontSize)
label.text = "NEW_CONVERSATION_MENU_OPEN_GROUP".localized().uppercased()
label.themeTextColor = .textPrimary
label.textAlignment = .center
result.addSubview(label)
label.pin(to: result, withInset: 4)
return result
}()
// MARK: Initialization
// MARK: - Initialization
override init(frame: CGRect) {
super.init(frame: frame)
setUpViewHierarchy()
}
required init?(coder: NSCoder) {
super.init(coder: coder)
setUpViewHierarchy()
}
@ -75,49 +104,61 @@ final class NewConversationButtonSet : UIView {
createClosedGroupButton.isAccessibilityElement = true
joinOpenGroupButton.accessibilityLabel = "Join open group button"
joinOpenGroupButton.isAccessibilityElement = true
let inset = (NewConversationButtonSet.expandedButtonSize - NewConversationButtonSet.collapsedButtonSize) / 2
addSubview(joinOpenGroupLabel)
addSubview(joinOpenGroupButton)
horizontalButtonConstraints[joinOpenGroupButton] = joinOpenGroupButton.pin(.left, to: .left, of: self, withInset: inset)
verticalButtonConstraints[joinOpenGroupButton] = joinOpenGroupButton.pin(.bottom, to: .bottom, of: self, withInset: -inset)
joinOpenGroupLabel.center(.horizontal, in: joinOpenGroupButton)
joinOpenGroupLabel.pin(.top, to: .bottom, of: joinOpenGroupButton, withInset: 8)
addSubview(newDMLabel)
addSubview(newDMButton)
newDMButton.center(.horizontal, in: self)
verticalButtonConstraints[newDMButton] = newDMButton.pin(.top, to: .top, of: self, withInset: inset)
newDMLabel.center(.horizontal, in: newDMButton)
newDMLabel.pin(.top, to: .bottom, of: newDMButton, withInset: 8)
addSubview(createClosedGroupLabel)
addSubview(createClosedGroupButton)
horizontalButtonConstraints[createClosedGroupButton] = createClosedGroupButton.pin(.right, to: .right, of: self, withInset: -inset)
verticalButtonConstraints[createClosedGroupButton] = createClosedGroupButton.pin(.bottom, to: .bottom, of: self, withInset: -inset)
createClosedGroupLabel.center(.horizontal, in: createClosedGroupButton)
createClosedGroupLabel.pin(.top, to: .bottom, of: createClosedGroupButton, withInset: 8)
addSubview(mainButton)
mainButton.center(.horizontal, in: self)
mainButton.pin(.bottom, to: .bottom, of: self, withInset: -inset)
let width = 2 * NewConversationButtonSet.expandedButtonSize + 2 * spacing + NewConversationButtonSet.collapsedButtonSize
set(.width, to: width)
let height = NewConversationButtonSet.expandedButtonSize + spacing + NewConversationButtonSet.collapsedButtonSize
set(.height, to: height)
collapse(withAnimation: false)
isUserInteractionEnabled = true
let joinOpenGroupButtonTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleJoinOpenGroupButtonTapped))
joinOpenGroupButton.addGestureRecognizer(joinOpenGroupButtonTapGestureRecognizer)
let createNewPrivateChatButtonTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleCreateNewPrivateChatButtonTapped))
newDMButton.addGestureRecognizer(createNewPrivateChatButtonTapGestureRecognizer)
let createNewClosedGroupButtonTapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(handleCreateNewClosedGroupButtonTapped))
createClosedGroupButton.addGestureRecognizer(createNewClosedGroupButtonTapGestureRecognizer)
}
// MARK: Interaction
// MARK: - Interaction
@objc private func handleJoinOpenGroupButtonTapped() { delegate?.joinOpenGroup() }
@objc private func handleCreateNewPrivateChatButtonTapped() { delegate?.createNewDM() }
@objc private func handleCreateNewClosedGroupButtonTapped() { delegate?.createClosedGroup() }
private func expand(isUserDragging: Bool) {
let views = [ joinOpenGroupButton, joinOpenGroupLabel, newDMButton, newDMLabel, createClosedGroupButton, createClosedGroupLabel ]
UIView.animate(withDuration: 0.25, animations: {
views.forEach { $0.alpha = 1 }
let inset = (NewConversationButtonSet.expandedButtonSize - NewConversationButtonSet.collapsedButtonSize) / 2
@ -137,6 +178,7 @@ final class NewConversationButtonSet : UIView {
isUserDragging = false
let buttons = [ joinOpenGroupButton, newDMButton, createClosedGroupButton ]
let labels = [ joinOpenGroupLabel, newDMLabel, createClosedGroupLabel ]
UIView.animate(withDuration: isAnimated ? 0.25 : 0) {
labels.forEach { label in
label.alpha = 0
@ -264,27 +306,67 @@ final class NewConversationButtonSet : UIView {
}
}
// MARK: Delegate
// MARK: - Delegate
protocol NewConversationButtonSetDelegate {
func joinOpenGroup()
func createNewDM()
func createClosedGroup()
}
// MARK: Button
private final class NewConversationButton : UIImageView {
// MARK: - Button
private final class NewConversationButton: UIImageView {
private let isMainButton: Bool
private let icon: UIImage
var widthConstraint: NSLayoutConstraint!
var heightConstraint: NSLayoutConstraint!
// MARK: - UI
private let innerShadowLayer: CALayer = {
let result: CALayer = CALayer()
result.masksToBounds = true
result.themeShadowColor = .menuButton_innerShadow
result.position = CGPoint(
x: (NewConversationButtonSet.collapsedButtonSize / 2),
y: (NewConversationButtonSet.collapsedButtonSize / 2)
)
result.bounds = CGRect(
x: 0,
y: 0,
width: NewConversationButtonSet.collapsedButtonSize,
height: NewConversationButtonSet.collapsedButtonSize
)
result.cornerRadius = (NewConversationButtonSet.collapsedButtonSize / 2)
result.shadowOffset = .zero
result.shadowOpacity = 0.4
result.shadowRadius = 2
let cutout: UIBezierPath = UIBezierPath(
roundedRect: result.bounds
.insetBy(dx: result.shadowRadius, dy: result.shadowRadius),
cornerRadius: (NewConversationButtonSet.collapsedButtonSize / 2)
).reversing()
let path: UIBezierPath = UIBezierPath(
roundedRect: result.bounds,
cornerRadius: (NewConversationButtonSet.collapsedButtonSize / 2)
)
path.append(cutout)
result.shadowPath = path.cgPath
return result
}()
// MARK: - Initialization
init(isMainButton: Bool, icon: UIImage) {
self.isMainButton = isMainButton
self.icon = icon
super.init(frame: CGRect.zero)
setUpViewHierarchy()
NotificationCenter.default.addObserver(self, selector: #selector(handleAppModeChangedNotification(_:)), name: .appModeChanged, object: nil)
}
override init(frame: CGRect) {
@ -294,26 +376,39 @@ private final class NewConversationButton : UIImageView {
required init?(coder: NSCoder) {
preconditionFailure("Use init(isMainButton:) instead.")
}
deinit {
NotificationCenter.default.removeObserver(self)
}
private func setUpViewHierarchy(isUpdate: Bool = false) {
let newConversationButtonCollapsedBackground = isLightMode ? UIColor(hex: 0xF5F5F5) : UIColor(hex: 0x1F1F1F)
backgroundColor = isMainButton ? Colors.accent : newConversationButtonCollapsedBackground
let size = NewConversationButtonSet.collapsedButtonSize
layer.cornerRadius = size / 2
let glowColor = isMainButton ? Colors.expandedButtonGlowColor : (isLightMode ? UIColor.black.withAlphaComponent(0.4) : UIColor.black)
let glowConfiguration = UIView.CircularGlowConfiguration(size: size, color: glowColor, isAnimated: false, radius: isLightMode ? 4 : 6)
setCircularGlow(with: glowConfiguration)
layer.masksToBounds = false
let iconColor = (isMainButton && isLightMode) ? UIColor.white : (isLightMode ? UIColor.black : UIColor.white)
image = icon.asTintedImage(color: iconColor)!
clipsToBounds = false
image = icon.withRenderingMode(.alwaysTemplate)
contentMode = .center
layer.cornerRadius = (NewConversationButtonSet.collapsedButtonSize / 2)
themeBackgroundColor = (isMainButton ? .menuButton_background : .backgroundTertiary)
themeTintColor = .menuButton_icon
if isMainButton {
themeShadowColor = .menuButton_outerShadow
layer.shadowRadius = 15
layer.shadowOpacity = 0.3
layer.shadowOffset = .zero
layer.cornerRadius = (NewConversationButtonSet.collapsedButtonSize / 2)
layer.shadowPath = UIBezierPath(
ovalIn: CGRect(
origin: CGPoint.zero,
size: CGSize(
width: NewConversationButtonSet.collapsedButtonSize,
height: NewConversationButtonSet.collapsedButtonSize
)
)
).cgPath
self.layer.addSublayer(innerShadowLayer)
}
if !isUpdate {
widthConstraint = set(.width, to: size)
heightConstraint = set(.height, to: size)
widthConstraint = set(.width, to: NewConversationButtonSet.collapsedButtonSize)
heightConstraint = set(.height, to: NewConversationButtonSet.collapsedButtonSize)
}
}

View File

@ -89,8 +89,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
mainWindow.rootViewController = self.loadingViewController
mainWindow.makeKeyAndVisible()
adapt(appMode: AppModeManager.getAppModeOrSystemDefault())
// This must happen in appDidFinishLaunching or earlier to ensure we don't
// miss notifications.
// Setting the delegate also seems to prevent us from getting the legacy notification
@ -156,7 +154,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
UserDefaults.sharedLokiProject?[.isMainAppActive] = true
ensureRootViewController()
adapt(appMode: AppModeManager.getAppModeOrSystemDefault())
AppReadiness.runNowOrWhenAppDidBecomeReady { [weak self] in
self?.handleActivation()

View File

@ -1,12 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "CircleDotDotDot.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -1,12 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "FilledCircleCheckDarkMode.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -1,12 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "FilledCircleCheckLightMode.pdf"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@ -1,23 +0,0 @@
{
"images" : [
{
"idiom" : "universal",
"filename" : "error-12@1x.png",
"scale" : "1x"
},
{
"idiom" : "universal",
"filename" : "error-12@2x.png",
"scale" : "2x"
},
{
"idiom" : "universal",
"filename" : "error-12@3x.png",
"scale" : "3x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 220 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 423 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 701 B

View File

@ -628,7 +628,7 @@
"modal_call_missed_tips_explanation" = "Call missed from '%@' because you needed to enable the 'Voice and video calls' permission in the Privacy Settings.";
"media_saved" = "Media saved by %@.";
"screenshot_taken" = "%@ took a screenshot.";
"SEARCH_SECTION_CONTACTS" = "Contacts and Groups";
"SEARCH_SECTION_CONTACTS" = "Contacts & Groups";
"SEARCH_SECTION_MESSAGES" = "Messages";
"SEARCH_SECTION_RECENT" = "Recent";
"RECENT_SEARCH_LAST_MESSAGE_DATETIME" = "last message: %@";

View File

@ -628,7 +628,7 @@
"modal_call_missed_tips_explanation" = "Llamada perdida de '%@' porque necesitas habilitar el permiso de 'Llamadas de voz y video' en la configuración de privacidad.";
"media_saved" = "Media saved by %@.";
"screenshot_taken" = "%@ tomó una captura de pantalla.";
"SEARCH_SECTION_CONTACTS" = "Contacts and Groups";
"SEARCH_SECTION_CONTACTS" = "Contacts & Groups";
"SEARCH_SECTION_MESSAGES" = "Messages";
"SEARCH_SECTION_RECENT" = "Recent";
"RECENT_SEARCH_LAST_MESSAGE_DATETIME" = "last message: %@";

View File

@ -628,7 +628,7 @@
"modal_call_missed_tips_explanation" = "Call missed from '%@' because you needed to enable the 'Voice and video calls' permission in the Privacy Settings.";
"media_saved" = "Media saved by %@.";
"screenshot_taken" = "%@ took a screenshot.";
"SEARCH_SECTION_CONTACTS" = "Contacts and Groups";
"SEARCH_SECTION_CONTACTS" = "Contacts & Groups";
"SEARCH_SECTION_MESSAGES" = "Messages";
"SEARCH_SECTION_RECENT" = "Recent";
"RECENT_SEARCH_LAST_MESSAGE_DATETIME" = "last message: %@";

View File

@ -628,7 +628,7 @@
"modal_call_missed_tips_explanation" = "Call missed from '%@' because you needed to enable the 'Voice and video calls' permission in the Privacy Settings.";
"media_saved" = "Media saved by %@.";
"screenshot_taken" = "%@ took a screenshot.";
"SEARCH_SECTION_CONTACTS" = "Contacts and Groups";
"SEARCH_SECTION_CONTACTS" = "Contacts & Groups";
"SEARCH_SECTION_MESSAGES" = "Messages";
"SEARCH_SECTION_RECENT" = "Recent";
"RECENT_SEARCH_LAST_MESSAGE_DATETIME" = "last message: %@";

View File

@ -628,7 +628,7 @@
"modal_call_missed_tips_explanation" = "Propušten poziv od '%@' jer 'Audio i video pozivi' nemaju dopuštenje u Postavkama privatnosti.";
"media_saved" = "%@ je spremio/la medij.";
"screenshot_taken" = "%@ je napravio/la snimku zaslona.";
"SEARCH_SECTION_CONTACTS" = "Contacts and Groups";
"SEARCH_SECTION_CONTACTS" = "Contacts & Groups";
"SEARCH_SECTION_MESSAGES" = "Messages";
"SEARCH_SECTION_RECENT" = "Recent";
"RECENT_SEARCH_LAST_MESSAGE_DATETIME" = "last message: %@";

View File

@ -628,7 +628,7 @@
"modal_call_missed_tips_explanation" = "Call missed from '%@' because you needed to enable the 'Voice and video calls' permission in the Privacy Settings.";
"media_saved" = "Media saved by %@.";
"screenshot_taken" = "%@ took a screenshot.";
"SEARCH_SECTION_CONTACTS" = "Contacts and Groups";
"SEARCH_SECTION_CONTACTS" = "Contacts & Groups";
"SEARCH_SECTION_MESSAGES" = "Messages";
"SEARCH_SECTION_RECENT" = "Recent";
"RECENT_SEARCH_LAST_MESSAGE_DATETIME" = "last message: %@";

View File

@ -628,7 +628,7 @@
"modal_call_missed_tips_explanation" = "Oproep gemist van '%@' omdat je de 'Spraak- en video-oproep' permissie nodig hebt in de privacy-instellingen.";
"media_saved" = "Media opgeslagen door %@.";
"screenshot_taken" = "%@ heeft een schermafbeelding genomen.";
"SEARCH_SECTION_CONTACTS" = "Contacts and Groups";
"SEARCH_SECTION_CONTACTS" = "Contacts & Groups";
"SEARCH_SECTION_MESSAGES" = "Messages";
"SEARCH_SECTION_RECENT" = "Recent";
"RECENT_SEARCH_LAST_MESSAGE_DATETIME" = "last message: %@";

View File

@ -628,7 +628,7 @@
"modal_call_missed_tips_explanation" = "Chamada perdida de '%@', você precisa habilitar a permissão de 'Voz e Video' nas configurações de Privacidade.";
"media_saved" = "Mídia salva por %@.";
"screenshot_taken" = "%@ fez uma captura de tela.";
"SEARCH_SECTION_CONTACTS" = "Contacts and Groups";
"SEARCH_SECTION_CONTACTS" = "Contacts & Groups";
"SEARCH_SECTION_MESSAGES" = "Messages";
"SEARCH_SECTION_RECENT" = "Recent";
"RECENT_SEARCH_LAST_MESSAGE_DATETIME" = "last message: %@";

View File

@ -628,7 +628,7 @@
"modal_call_missed_tips_explanation" = "Call missed from '%@' because you needed to enable the 'Voice and video calls' permission in the Privacy Settings.";
"media_saved" = "Media saved by %@.";
"screenshot_taken" = "%@ took a screenshot.";
"SEARCH_SECTION_CONTACTS" = "Contacts and Groups";
"SEARCH_SECTION_CONTACTS" = "Contacts & Groups";
"SEARCH_SECTION_MESSAGES" = "Messages";
"SEARCH_SECTION_RECENT" = "Recent";
"RECENT_SEARCH_LAST_MESSAGE_DATETIME" = "last message: %@";

View File

@ -628,7 +628,7 @@
"modal_call_missed_tips_explanation" = "Call missed from '%@' because you needed to enable the 'Voice and video calls' permission in the Privacy Settings.";
"media_saved" = "Media saved by %@.";
"screenshot_taken" = "%@ took a screenshot.";
"SEARCH_SECTION_CONTACTS" = "Contacts and Groups";
"SEARCH_SECTION_CONTACTS" = "Contacts & Groups";
"SEARCH_SECTION_MESSAGES" = "Messages";
"SEARCH_SECTION_RECENT" = "Recent";
"RECENT_SEARCH_LAST_MESSAGE_DATETIME" = "last message: %@";

View File

@ -628,7 +628,7 @@
"modal_call_missed_tips_explanation" = "Call missed from '%@' because you needed to enable the 'Voice and video calls' permission in the Privacy Settings.";
"media_saved" = "Media saved by %@.";
"screenshot_taken" = "%@ took a screenshot.";
"SEARCH_SECTION_CONTACTS" = "Contacts and Groups";
"SEARCH_SECTION_CONTACTS" = "Contacts & Groups";
"SEARCH_SECTION_MESSAGES" = "Messages";
"SEARCH_SECTION_RECENT" = "Recent";
"RECENT_SEARCH_LAST_MESSAGE_DATETIME" = "last message: %@";

View File

@ -628,7 +628,7 @@
"modal_call_missed_tips_explanation" = "Call missed from '%@' because you needed to enable the 'Voice and video calls' permission in the Privacy Settings.";
"media_saved" = "Media saved by %@.";
"screenshot_taken" = "%@ took a screenshot.";
"SEARCH_SECTION_CONTACTS" = "Contacts and Groups";
"SEARCH_SECTION_CONTACTS" = "Contacts & Groups";
"SEARCH_SECTION_MESSAGES" = "Messages";
"SEARCH_SECTION_RECENT" = "Recent";
"RECENT_SEARCH_LAST_MESSAGE_DATETIME" = "last message: %@";

View File

@ -628,7 +628,7 @@
"modal_call_missed_tips_explanation" = "Call missed from '%@' because you needed to enable the 'Voice and video calls' permission in the Privacy Settings.";
"media_saved" = "%@ 儲存了媒體";
"screenshot_taken" = "%@ 擷取了螢幕畫面";
"SEARCH_SECTION_CONTACTS" = "Contacts and Groups";
"SEARCH_SECTION_CONTACTS" = "Contacts & Groups";
"SEARCH_SECTION_MESSAGES" = "Messages";
"SEARCH_SECTION_RECENT" = "Recent";
"RECENT_SEARCH_LAST_MESSAGE_DATETIME" = "last message: %@";

View File

@ -232,7 +232,7 @@ public class NotificationPresenter: NSObject, NotificationsProtocol {
)
DispatchQueue.main.async {
notificationBody = MentionUtilities.highlightMentions(
notificationBody = MentionUtilities.highlightMentionsNoAttributes(
in: (notificationBody ?? ""),
threadVariant: thread.variant,
currentUserPublicKey: userPublicKey,

View File

@ -25,8 +25,6 @@ final class DisplayNameVC: BaseVC {
override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
setUpNavBarStyle()
setUpNavBarSessionIcon()
// Set up title label

View File

@ -1,5 +1,9 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
final class FakeChatView : UIView {
import UIKit
import SessionUIKit
final class FakeChatView: UIView {
private let spacing = Values.mediumSpacing
var contentOffset: CGPoint {
@ -8,11 +12,11 @@ final class FakeChatView : UIView {
}
private lazy var chatBubbles = [
getChatBubble(withText: NSLocalizedString("view_fake_chat_bubble_1", comment: ""), wasSentByCurrentUser: true),
getChatBubble(withText: NSLocalizedString("view_fake_chat_bubble_2", comment: ""), wasSentByCurrentUser: false),
getChatBubble(withText: NSLocalizedString("view_fake_chat_bubble_3", comment: ""), wasSentByCurrentUser: true),
getChatBubble(withText: NSLocalizedString("view_fake_chat_bubble_4", comment: ""), wasSentByCurrentUser: false),
getChatBubble(withText: NSLocalizedString("view_fake_chat_bubble_5", comment: ""), wasSentByCurrentUser: false)
getChatBubble(withText: "view_fake_chat_bubble_1".localized(), wasSentByCurrentUser: true),
getChatBubble(withText: "view_fake_chat_bubble_2".localized(), wasSentByCurrentUser: false),
getChatBubble(withText: "view_fake_chat_bubble_3".localized(), wasSentByCurrentUser: true),
getChatBubble(withText: "view_fake_chat_bubble_4".localized(), wasSentByCurrentUser: false),
getChatBubble(withText: "view_fake_chat_bubble_5".localized(), wasSentByCurrentUser: false)
]
private lazy var scrollView: UIScrollView = {
@ -67,25 +71,35 @@ final class FakeChatView : UIView {
bubbleView.layer.shadowRadius = isLightMode ? 4 : 8
bubbleView.layer.shadowOpacity = isLightMode ? 0.16 : 0.24
bubbleView.layer.shadowOffset = CGSize.zero
let backgroundColor = wasSentByCurrentUser ? Colors.fakeChatBubbleBackground : Colors.accent
bubbleView.backgroundColor = backgroundColor
bubbleView.themeBackgroundColor = (wasSentByCurrentUser ?
.messageBubble_outgoingBackground :
.messageBubble_incomingBackground
)
let label = UILabel()
let textColor = wasSentByCurrentUser ? Colors.text : Colors.fakeChatBubbleText
label.textColor = textColor
label.font = .boldSystemFont(ofSize: Values.mediumFontSize)
label.numberOfLines = 0
label.lineBreakMode = .byWordWrapping
label.text = text
label.themeTextColor = (wasSentByCurrentUser ?
.messageBubble_outgoingText :
.messageBubble_incomingText
)
label.lineBreakMode = .byWordWrapping
label.numberOfLines = 0
bubbleView.addSubview(label)
label.pin(to: bubbleView, withInset: 12)
result.addSubview(bubbleView)
bubbleView.pin(.top, to: .top, of: result)
result.pin(.bottom, to: .bottom, of: bubbleView)
if wasSentByCurrentUser {
bubbleView.pin(.trailing, to: .trailing, of: result)
} else {
}
else {
result.pin(.leading, to: .leading, of: bubbleView)
}
return result
}
@ -93,6 +107,7 @@ final class FakeChatView : UIView {
let animationDuration = FakeChatView.animationDuration
let delayBetweenMessages = FakeChatView.chatDelay
chatBubbles.forEach { $0.alpha = 0 }
Timer.scheduledTimer(withTimeInterval: FakeChatView.startDelay, repeats: false) { [weak self] _ in
self?.showChatBubble(at: 0)
Timer.scheduledTimer(withTimeInterval: 1.5 * delayBetweenMessages, repeats: false) { _ in
@ -124,11 +139,13 @@ final class FakeChatView : UIView {
private func showChatBubble(at index: Int) {
let chatBubble = chatBubbles[index]
UIView.animate(withDuration: FakeChatView.animationDuration) {
chatBubble.alpha = 1
}
let scale = FakeChatView.popAnimationStartScale
chatBubble.transform = CGAffineTransform(scaleX: scale, y: scale)
UIView.animate(withDuration: FakeChatView.animationDuration, delay: 0, usingSpringWithDamping: 0.68, initialSpringVelocity: 4, options: .curveEaseInOut, animations: {
chatBubble.transform = CGAffineTransform(scaleX: 1, y: 1)
}, completion: nil)

View File

@ -39,15 +39,13 @@ final class LandingVC: BaseVC {
override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
setUpNavBarStyle()
setUpNavBarSessionIcon()
// Title label
let titleLabel = UILabel()
titleLabel.font = .boldSystemFont(ofSize: isIPhone5OrSmaller ? Values.largeFontSize : Values.veryLargeFontSize)
titleLabel.text = "vc_landing_title_2".localized()
titleLabel.textColor = Colors.text
titleLabel.themeTextColor = .textPrimary
titleLabel.lineBreakMode = .byWordWrapping
titleLabel.numberOfLines = 0
@ -67,7 +65,7 @@ final class LandingVC: BaseVC {
let linkButton = UIButton()
linkButton.titleLabel?.font = .boldSystemFont(ofSize: Values.smallFontSize)
linkButton.setTitle("vc_landing_link_button_title".localized(), for: .normal)
linkButton.setTitleColor(Colors.text, for: UIControl.State.normal)
linkButton.setThemeTitleColor(.textPrimary, for: .normal)
linkButton.addTarget(self, action: #selector(link), for: .touchUpInside)
// Link button container

View File

@ -51,9 +51,8 @@ final class LinkDeviceVC: BaseVC, UIPageViewControllerDataSource, UIPageViewCont
// MARK: Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
setUpNavBarStyle()
setNavBarTitle(NSLocalizedString("vc_link_device_title", comment: ""))
setNavBarTitle("vc_link_device_title".localized())
let navigationBar = navigationController!.navigationBar
// Page VC
let hasCameraAccess = (AVCaptureDevice.authorizationStatus(for: .video) == .authorized)

View File

@ -35,8 +35,6 @@ final class PNModeVC : BaseVC, OptionViewDelegate {
override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
setUpNavBarStyle()
setUpNavBarSessionIcon()
let learnMoreButton = UIBarButtonItem(image: #imageLiteral(resourceName: "ic_info"), style: .plain, target: self, action: #selector(learnMore))

View File

@ -50,8 +50,6 @@ final class RegisterVC : BaseVC {
// MARK: Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
setUpNavBarStyle()
setUpNavBarSessionIcon()
// Set up title label

View File

@ -47,8 +47,6 @@ final class RestoreVC: BaseVC {
override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
setUpNavBarStyle()
setUpNavBarSessionIcon()
// Set up title label

View File

@ -18,8 +18,8 @@ final class SeedReminderView: UIView {
private lazy var progressIndicatorView: UIProgressView = {
let result = UIProgressView()
result.progressViewStyle = .bar
result.progressTintColor = Colors.accent
result.backgroundColor = isLightMode ? UIColor(hex: 0x000000).withAlphaComponent(0.1) : UIColor(hex: 0xFFFFFF).withAlphaComponent(0.1)
result.themeProgressTintColor = .primary
result.themeBackgroundColor = .borderSeparator
result.set(.height, to: SeedReminderView.progressBarThickness)
return result
@ -28,7 +28,7 @@ final class SeedReminderView: UIView {
lazy var titleLabel: UILabel = {
let result = UILabel()
result.font = .boldSystemFont(ofSize: Values.smallFontSize)
result.textColor = Colors.text
result.themeTextColor = .textPrimary
result.lineBreakMode = .byTruncatingTail
return result
@ -36,10 +36,11 @@ final class SeedReminderView: UIView {
lazy var subtitleLabel: UILabel = {
let result = UILabel()
result.textColor = Colors.text.withAlphaComponent(Values.mediumOpacity)
result.font = .systemFont(ofSize: Values.verySmallFontSize)
result.lineBreakMode = .byWordWrapping
result.themeTextColor = .textSecondary
result.numberOfLines = 0
result.lineBreakMode = .byWordWrapping
return result
}()
@ -63,7 +64,7 @@ final class SeedReminderView: UIView {
private func setUpViewHierarchy() {
// Set background color
backgroundColor = Colors.cellBackground
themeBackgroundColor = .conversationButton_background
// Set up label stack view
let labelStackView = UIStackView(arrangedSubviews: [ titleLabel, subtitleLabel ])
@ -92,7 +93,7 @@ final class SeedReminderView: UIView {
// Set up separator
let separator = UIView()
separator.set(.height, to: Values.separatorThickness)
separator.backgroundColor = Colors.separator
separator.themeBackgroundColor = .borderSeparator
// Set up stack view
let stackView = UIStackView(arrangedSubviews: [ progressIndicatorView, contentStackView, separator ])

View File

@ -60,8 +60,6 @@ final class SeedVC: BaseVC {
override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
setUpNavBarStyle()
setNavBarTitle("vc_seed_title".localized())
// Set up navigation bar buttons

View File

@ -55,8 +55,6 @@ final class JoinOpenGroupVC: BaseVC, UIPageViewControllerDataSource, UIPageViewC
override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
setUpNavBarStyle()
setNavBarTitle("vc_join_public_chat_title".localized())
// Navigation bar buttons

View File

@ -37,14 +37,12 @@ final class PathVC: BaseVC {
override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
setUpNavBar()
setUpViewHierarchy()
registerObservers()
}
private func setUpNavBar() {
setUpNavBarStyle()
setNavBarTitle("vc_path_title".localized())
}

View File

@ -54,8 +54,6 @@ final class QRCodeVC : BaseVC, UIPageViewControllerDataSource, UIPageViewControl
override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
setUpNavBarStyle()
setNavBarTitle("vc_qr_code_title".localized())
// Set up page VC

View File

@ -127,8 +127,6 @@ final class SettingsVC: BaseVC, AvatarViewHelperDelegate {
override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
setUpNavBarStyle()
setNavBarTitle("vc_settings_title".localized())
// Navigation bar buttons

View File

@ -33,45 +33,6 @@ class BaseVC: UIViewController {
view.themeBackgroundColor = .backgroundPrimary
setNeedsStatusBarAppearanceUpdate()
NotificationCenter.default.addObserver(self, selector: #selector(handleAppModeChangedNotification(_:)), name: .appModeChanged, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(appDidBecomeActive(_:)), name: .OWSApplicationDidBecomeActive, object: nil)
}
internal func ensureWindowBackground() {
let appMode = AppModeManager.shared.currentAppMode
switch appMode {
case .light:
UIApplication.shared.delegate?.window??.backgroundColor = .white
case .dark:
UIApplication.shared.delegate?.window??.backgroundColor = .black
}
}
internal func setUpGradientBackground() {
hasGradient = true
view.backgroundColor = .clear
let gradient = Gradients.defaultBackground
view.setGradient(gradient)
}
internal func setUpNavBarStyle() {
guard let navigationBar = navigationController?.navigationBar else { return }
if #available(iOS 15.0, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = Colors.navigationBarBackground
appearance.shadowColor = .clear
navigationBar.standardAppearance = appearance;
navigationBar.scrollEdgeAppearance = navigationBar.standardAppearance
} else {
navigationBar.setBackgroundImage(UIImage(), for: UIBarMetrics.default)
navigationBar.shadowImage = UIImage()
navigationBar.isTranslucent = false
navigationBar.barTintColor = Colors.navigationBarBackground
}
navigationItem.backButtonTitle = ""
}
internal func setNavBarTitle(_ title: String, customFontSize: CGFloat? = nil) {
@ -115,27 +76,4 @@ class BaseVC: UIViewController {
navigationItem.titleView = logoImageView
}
deinit {
NotificationCenter.default.removeObserver(self)
}
@objc func appDidBecomeActive(_ notification: Notification) {
// To be implemented by child class
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
SNLog("Current trait collection: \(UITraitCollection.current), previous trait collection: \(previousTraitCollection)")
if LKAppModeUtilities.isSystemDefault {
NotificationCenter.default.post(name: .appModeChanged, object: nil)
}
}
@objc internal func handleAppModeChangedNotification(_ notification: Notification) {
if hasGradient {
setUpGradientBackground() // Re-do the gradient
}
ensureWindowBackground()
}
}

View File

@ -6,6 +6,9 @@ import SignalUtilitiesKit
import SessionMessagingKit
public final class FullConversationCell: UITableViewCell {
public static let unreadCountViewSize: CGFloat = 20
private static let statusIndicatorSize: CGFloat = 14
// MARK: - UI
private let accentLineView: UIView = UIView()
@ -15,7 +18,7 @@ public final class FullConversationCell: UITableViewCell {
private lazy var displayNameLabel: UILabel = {
let result: UILabel = UILabel()
result.font = .boldSystemFont(ofSize: Values.mediumFontSize)
result.textColor = Colors.text
result.themeTextColor = .textPrimary
result.lineBreakMode = .byTruncatingTail
return result
@ -23,12 +26,11 @@ public final class FullConversationCell: UITableViewCell {
private lazy var unreadCountView: UIView = {
let result: UIView = UIView()
result.backgroundColor = Colors.text.withAlphaComponent(Values.veryLowOpacity)
let size = FullConversationCell.unreadCountViewSize
result.set(.width, greaterThanOrEqualTo: size)
result.set(.height, to: size)
result.layer.masksToBounds = true
result.layer.cornerRadius = (size / 2)
result.clipsToBounds = true
result.themeBackgroundColor = .conversationButton_unreadBubbleBackground
result.layer.cornerRadius = (FullConversationCell.unreadCountViewSize / 2)
result.set(.width, greaterThanOrEqualTo: FullConversationCell.unreadCountViewSize)
result.set(.height, to: FullConversationCell.unreadCountViewSize)
return result
}()
@ -36,7 +38,7 @@ public final class FullConversationCell: UITableViewCell {
private lazy var unreadCountLabel: UILabel = {
let result: UILabel = UILabel()
result.font = .boldSystemFont(ofSize: Values.verySmallFontSize)
result.textColor = Colors.text
result.themeTextColor = .conversationButton_unreadBubbleText
result.textAlignment = .center
return result
@ -44,12 +46,11 @@ public final class FullConversationCell: UITableViewCell {
private lazy var hasMentionView: UIView = {
let result: UIView = UIView()
result.backgroundColor = Colors.accent
let size = FullConversationCell.unreadCountViewSize
result.set(.width, to: size)
result.set(.height, to: size)
result.layer.masksToBounds = true
result.layer.cornerRadius = (size / 2)
result.clipsToBounds = true
result.themeBackgroundColor = .conversationButton_unreadBubbleBackground
result.layer.cornerRadius = (FullConversationCell.unreadCountViewSize / 2)
result.set(.width, to: FullConversationCell.unreadCountViewSize)
result.set(.height, to: FullConversationCell.unreadCountViewSize)
return result
}()
@ -57,7 +58,7 @@ public final class FullConversationCell: UITableViewCell {
private lazy var hasMentionLabel: UILabel = {
let result: UILabel = UILabel()
result.font = .boldSystemFont(ofSize: Values.verySmallFontSize)
result.textColor = Colors.text
result.themeTextColor = .conversationButton_unreadBubbleText
result.text = "@"
result.textAlignment = .center
@ -65,13 +66,15 @@ public final class FullConversationCell: UITableViewCell {
}()
private lazy var isPinnedIcon: UIImageView = {
let result: UIImageView = UIImageView(image: UIImage(named: "Pin")?.withRenderingMode(.alwaysTemplate))
let result: UIImageView = UIImageView(
image: UIImage(named: "Pin")?
.withRenderingMode(.alwaysTemplate)
)
result.clipsToBounds = true
result.themeTintColor = .textPrimary
result.contentMode = .scaleAspectFit
let size = FullConversationCell.unreadCountViewSize
result.set(.width, to: size)
result.set(.height, to: size)
result.tintColor = Colors.pinIcon
result.layer.masksToBounds = true
result.set(.width, to: FullConversationCell.unreadCountViewSize)
result.set(.height, to: FullConversationCell.unreadCountViewSize)
return result
}()
@ -79,7 +82,7 @@ public final class FullConversationCell: UITableViewCell {
private lazy var timestampLabel: UILabel = {
let result: UILabel = UILabel()
result.font = .systemFont(ofSize: Values.smallFontSize)
result.textColor = Colors.text
result.themeTextColor = .textSecondary
result.lineBreakMode = .byTruncatingTail
result.alpha = Values.lowOpacity
@ -89,7 +92,7 @@ public final class FullConversationCell: UITableViewCell {
private lazy var snippetLabel: UILabel = {
let result: UILabel = UILabel()
result.font = .systemFont(ofSize: Values.smallFontSize)
result.textColor = Colors.text
result.themeTextColor = .textPrimary
result.lineBreakMode = .byTruncatingTail
return result
@ -99,9 +102,9 @@ public final class FullConversationCell: UITableViewCell {
private lazy var statusIndicatorView: UIImageView = {
let result: UIImageView = UIImageView()
result.clipsToBounds = true
result.contentMode = .scaleAspectFit
result.layer.cornerRadius = (FullConversationCell.statusIndicatorSize / 2)
result.layer.masksToBounds = true
return result
}()
@ -124,15 +127,11 @@ public final class FullConversationCell: UITableViewCell {
return result
}()
// MARK: Settings
public static let unreadCountViewSize: CGFloat = 20
private static let statusIndicatorSize: CGFloat = 14
// MARK: - Initialization
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
setUpViewHierarchy()
}
@ -145,11 +144,11 @@ public final class FullConversationCell: UITableViewCell {
let cellHeight: CGFloat = 68
// Background color
backgroundColor = Colors.cellBackground
themeBackgroundColor = .conversationButton_background
// Highlight color
let selectedBackgroundView = UIView()
selectedBackgroundView.backgroundColor = Colors.cellSelected
selectedBackgroundView.themeBackgroundColor = .conversationButton_highlight
self.selectedBackgroundView = selectedBackgroundView
// Accent line view
@ -247,31 +246,42 @@ public final class FullConversationCell: UITableViewCell {
isPinnedIcon.isHidden = true
unreadCountView.isHidden = true
hasMentionView.isHidden = true
displayNameLabel.attributedText = NSMutableAttributedString(
string: cellViewModel.displayName,
attributes: [ .foregroundColor: Colors.text]
)
timestampLabel.isHidden = false
timestampLabel.text = cellViewModel.lastInteractionDate.formattedForDisplay
bottomLabelStackView.isHidden = false
snippetLabel.attributedText = getHighlightedSnippet(
content: Interaction.previewText(
variant: (cellViewModel.interactionVariant ?? .standardIncoming),
body: cellViewModel.interactionBody,
authorDisplayName: cellViewModel.authorName(for: .contact),
attachmentDescriptionInfo: cellViewModel.interactionAttachmentDescriptionInfo,
attachmentCount: cellViewModel.interactionAttachmentCount,
isOpenGroupInvitation: (cellViewModel.interactionIsOpenGroupInvitation == true)
),
authorName: (cellViewModel.authorId != cellViewModel.currentUserPublicKey ?
cellViewModel.authorName(for: .contact) :
nil
),
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
searchText: searchText.lowercased(),
fontSize: Values.smallFontSize
)
ThemeManager.onThemeChange(observer: displayNameLabel) { [weak displayNameLabel] theme, _ in
guard let textColor: UIColor = theme.colors[.textPrimary] else { return }
displayNameLabel?.attributedText = NSMutableAttributedString(
string: cellViewModel.displayName,
attributes: [ .foregroundColor: textColor ]
)
}
ThemeManager.onThemeChange(observer: displayNameLabel) { [weak self, weak snippetLabel] theme, _ in
guard let textColor: UIColor = theme.colors[.textPrimary] else { return }
snippetLabel?.attributedText = self?.getHighlightedSnippet(
content: Interaction.previewText(
variant: (cellViewModel.interactionVariant ?? .standardIncoming),
body: cellViewModel.interactionBody,
authorDisplayName: cellViewModel.authorName(for: .contact),
attachmentDescriptionInfo: cellViewModel.interactionAttachmentDescriptionInfo,
attachmentCount: cellViewModel.interactionAttachmentCount,
isOpenGroupInvitation: (cellViewModel.interactionIsOpenGroupInvitation == true)
),
authorName: (cellViewModel.authorId != cellViewModel.currentUserPublicKey ?
cellViewModel.authorName(for: .contact) :
nil
),
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
searchText: searchText.lowercased(),
fontSize: Values.smallFontSize,
textColor: textColor
)
}
}
public func updateForContactAndGroupSearchResult(with cellViewModel: SessionThreadViewModel, searchText: String) {
@ -288,26 +298,39 @@ public final class FullConversationCell: UITableViewCell {
unreadCountView.isHidden = true
hasMentionView.isHidden = true
timestampLabel.isHidden = true
displayNameLabel.attributedText = getHighlightedSnippet(
content: cellViewModel.displayName,
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
searchText: searchText.lowercased(),
fontSize: Values.mediumFontSize
)
ThemeManager.onThemeChange(observer: displayNameLabel) { [weak self, weak displayNameLabel] theme, _ in
guard let textColor: UIColor = theme.colors[.textPrimary] else { return }
displayNameLabel?.attributedText = self?.getHighlightedSnippet(
content: cellViewModel.displayName,
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
searchText: searchText.lowercased(),
fontSize: Values.mediumFontSize,
textColor: textColor
)
}
switch cellViewModel.threadVariant {
case .contact, .openGroup: bottomLabelStackView.isHidden = true
case .closedGroup:
bottomLabelStackView.isHidden = (cellViewModel.threadMemberNames ?? "").isEmpty
snippetLabel.attributedText = getHighlightedSnippet(
content: (cellViewModel.threadMemberNames ?? ""),
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
searchText: searchText.lowercased(),
fontSize: Values.smallFontSize
)
ThemeManager.onThemeChange(observer: displayNameLabel) { [weak self, weak snippetLabel] theme, _ in
guard let textColor: UIColor = theme.colors[.textPrimary] else { return }
if cellViewModel.threadVariant == .closedGroup {
snippetLabel?.attributedText = self?.getHighlightedSnippet(
content: (cellViewModel.threadMemberNames ?? ""),
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey,
searchText: searchText.lowercased(),
fontSize: Values.smallFontSize,
textColor: textColor
)
}
}
}
}
@ -315,14 +338,21 @@ public final class FullConversationCell: UITableViewCell {
public func update(with cellViewModel: SessionThreadViewModel) {
let unreadCount: UInt = (cellViewModel.threadUnreadCount ?? 0)
backgroundColor = (cellViewModel.threadIsPinned ? Colors.cellPinned : Colors.cellBackground)
themeBackgroundColor = (unreadCount > 0 ?
.conversationButton_unreadBackground :
.conversationButton_background
)
self.selectedBackgroundView?.themeBackgroundColor = (unreadCount > 0 ?
.conversationButton_unreadHighlight :
.conversationButton_highlight
)
if cellViewModel.threadIsBlocked == true {
accentLineView.backgroundColor = Colors.destructive
accentLineView.themeBackgroundColor = .danger
accentLineView.alpha = 1
}
else {
accentLineView.backgroundColor = Colors.accent
accentLineView.themeBackgroundColor = .conversationButton_unreadStripBackground
accentLineView.alpha = (unreadCount > 0 ? 1 : 0.0001) // Setting the alpha to exactly 0 causes an issue on iOS 12
}
@ -357,37 +387,37 @@ public final class FullConversationCell: UITableViewCell {
typingIndicatorView.startAnimation()
}
else {
snippetLabel.attributedText = getSnippet(cellViewModel: cellViewModel)
typingIndicatorView.isHidden = true
typingIndicatorView.stopAnimation()
}
statusIndicatorView.backgroundColor = nil
switch (cellViewModel.interactionVariant, cellViewModel.interactionState) {
case (.standardOutgoing, .sending):
statusIndicatorView.image = #imageLiteral(resourceName: "CircleDotDotDot").withRenderingMode(.alwaysTemplate)
statusIndicatorView.tintColor = Colors.text
statusIndicatorView.isHidden = false
case (.standardOutgoing, .sent):
statusIndicatorView.image = #imageLiteral(resourceName: "CircleCheck").withRenderingMode(.alwaysTemplate)
statusIndicatorView.tintColor = Colors.text
statusIndicatorView.isHidden = false
case (.standardOutgoing, .failed):
statusIndicatorView.image = #imageLiteral(resourceName: "message_status_failed").withRenderingMode(.alwaysTemplate)
statusIndicatorView.tintColor = Colors.destructive
statusIndicatorView.isHidden = false
default:
statusIndicatorView.isHidden = true
ThemeManager.onThemeChange(observer: snippetLabel) { [weak self, weak snippetLabel] theme, _ in
guard let textColor: UIColor = theme.colors[.textPrimary] else { return }
snippetLabel?.attributedText = self?.getSnippet(
cellViewModel: cellViewModel,
textColor: textColor
)
}
}
let stateInfo = cellViewModel.interactionState?.statusIconInfo(
variant: (cellViewModel.interactionVariant ?? .standardOutgoing),
hasAtLeastOneReadReceipt: (cellViewModel.interactionHasAtLeastOneReadReceipt ?? false)
)
statusIndicatorView.image = stateInfo?.image
statusIndicatorView.themeTintColor = stateInfo?.tintColor
statusIndicatorView.isHidden = (
cellViewModel.interactionVariant != .standardOutgoing &&
cellViewModel.interactionState != .skipped
)
}
// MARK: - Snippet generation
private func getSnippet(cellViewModel: SessionThreadViewModel) -> NSMutableAttributedString {
private func getSnippet(
cellViewModel: SessionThreadViewModel,
textColor: UIColor
) -> NSMutableAttributedString {
// If we don't have an interaction then do nothing
guard cellViewModel.interactionId != nil else { return NSMutableAttributedString() }
@ -398,13 +428,13 @@ public final class FullConversationCell: UITableViewCell {
string: "\u{e067} ",
attributes: [
.font: UIFont.ows_elegantIconsFont(10),
.foregroundColor :Colors.unimportant
.foregroundColor: textColor
]
))
}
else if cellViewModel.threadOnlyNotifyForMentions == true {
let imageAttachment = NSTextAttachment()
imageAttachment.image = UIImage(named: "NotifyMentions.png")?.asTintedImage(color: Colors.unimportant)
imageAttachment.image = UIImage(named: "NotifyMentions.png")?.asTintedImage(color: textColor)
imageAttachment.bounds = CGRect(x: 0, y: -2, width: Values.smallFontSize, height: Values.smallFontSize)
let imageString = NSAttributedString(attachment: imageAttachment)
@ -413,30 +443,22 @@ public final class FullConversationCell: UITableViewCell {
string: " ",
attributes: [
.font: UIFont.ows_elegantIconsFont(10),
.foregroundColor: Colors.unimportant
.foregroundColor: textColor
]
))
}
let font: UIFont = ((cellViewModel.threadUnreadCount ?? 0) > 0 ?
.boldSystemFont(ofSize: Values.smallFontSize) :
.systemFont(ofSize: Values.smallFontSize)
)
if cellViewModel.threadVariant == .closedGroup || cellViewModel.threadVariant == .openGroup {
let authorName: String = cellViewModel.authorName(for: cellViewModel.threadVariant)
result.append(NSAttributedString(
string: "\(authorName): ",
attributes: [
.font: font,
.foregroundColor: Colors.text
]
attributes: [ .foregroundColor: textColor ]
))
}
result.append(NSAttributedString(
string: MentionUtilities.highlightMentions(
string: MentionUtilities.highlightMentionsNoAttributes(
in: Interaction.previewText(
variant: (cellViewModel.interactionVariant ?? .standardIncoming),
body: cellViewModel.interactionBody,
@ -450,10 +472,7 @@ public final class FullConversationCell: UITableViewCell {
currentUserPublicKey: cellViewModel.currentUserPublicKey,
currentUserBlindedPublicKey: cellViewModel.currentUserBlindedPublicKey
),
attributes: [
.font: font,
.foregroundColor: Colors.text
]
attributes: [ .foregroundColor: textColor ]
))
return result
@ -465,7 +484,8 @@ public final class FullConversationCell: UITableViewCell {
currentUserPublicKey: String,
currentUserBlindedPublicKey: String?,
searchText: String,
fontSize: CGFloat
fontSize: CGFloat,
textColor: UIColor
) -> NSAttributedString {
guard !content.isEmpty, content != "NOTE_TO_SELF".localized() else {
return NSMutableAttributedString(
@ -473,7 +493,7 @@ public final class FullConversationCell: UITableViewCell {
"\(authorName ?? ""): \(content)" :
content
),
attributes: [ .foregroundColor: Colors.text ]
attributes: [ .foregroundColor: textColor ]
)
}
@ -481,7 +501,7 @@ public final class FullConversationCell: UITableViewCell {
//
// Note: The 'threadVariant' is used for profile context but in the search results
// we don't want to include the truncated id as part of the name so we exclude it
let mentionReplacedContent: String = MentionUtilities.highlightMentions(
let mentionReplacedContent: String = MentionUtilities.highlightMentionsNoAttributes(
in: content,
threadVariant: .contact,
currentUserPublicKey: currentUserPublicKey,
@ -490,7 +510,7 @@ public final class FullConversationCell: UITableViewCell {
let result: NSMutableAttributedString = NSMutableAttributedString(
string: mentionReplacedContent,
attributes: [
.foregroundColor: Colors.text
.foregroundColor: textColor
.withAlphaComponent(Values.lowOpacity)
]
)
@ -523,7 +543,7 @@ public final class FullConversationCell: UITableViewCell {
}
let legacyRange: NSRange = NSRange(range, in: normalizedSnippet)
result.addAttribute(.foregroundColor, value: Colors.text, range: legacyRange)
result.addAttribute(.foregroundColor, value: textColor, range: legacyRange)
result.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: fontSize), range: legacyRange)
}
}

View File

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

View File

@ -28,7 +28,7 @@ final class ScanQRCodeWrapperVC : BaseVC {
if isPresentedModally {
navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .stop, target: self, action: #selector(close))
}
setUpGradientBackground()
// Set up scan QR code VC
scanQRCodeVC.scanDelegate = delegate
let scanQRCodeVCView = scanQRCodeVC.view!

View File

@ -45,9 +45,9 @@ final class UserSelectionVC: BaseVC, UITableViewDataSource, UITableViewDelegate
override func viewDidLoad() {
super.viewDidLoad()
setUpGradientBackground()
setUpNavBarStyle()
setNavBarTitle(navBarTitle)
navigationItem.rightBarButtonItem = UIBarButtonItem(barButtonSystemItem: .done, target: self, action: #selector(handleDoneButtonTapped))
view.addSubview(tableView)
tableView.pin(to: view)

View File

@ -6,20 +6,23 @@ import SessionUIKit
import SessionMessagingKit
public enum MentionUtilities {
public static func highlightMentions(
public static func highlightMentionsNoAttributes(
in string: String,
threadVariant: SessionThread.Variant,
currentUserPublicKey: String,
currentUserBlindedPublicKey: String?
) -> String {
/// **Note:** We are returning the string here so the 'textColor' and 'primaryColor' values are irrelevant
return highlightMentions(
in: string,
threadVariant: threadVariant,
currentUserPublicKey: currentUserPublicKey,
currentUserBlindedPublicKey: currentUserBlindedPublicKey,
isOutgoingMessage: false,
textColor: .black,
primaryColor: Theme.PrimaryColor.green,
attributes: [:]
).string // isOutgoingMessage and attributes are irrelevant
).string
}
public static func highlightMentions(
@ -28,6 +31,8 @@ public enum MentionUtilities {
currentUserPublicKey: String?,
currentUserBlindedPublicKey: String?,
isOutgoingMessage: Bool,
textColor: UIColor,
primaryColor: Theme.PrimaryColor,
attributes: [NSAttributedString.Key: Any]
) -> NSAttributedString {
guard
@ -87,18 +92,19 @@ public enum MentionUtilities {
// to maintain a "rounded rect" effect rather than a "pill" effect
result.addAttribute(.currentUserMentionBackgroundCornerRadius, value: (8 * sizeDiff), range: mention.range)
result.addAttribute(.currentUserMentionBackgroundPadding, value: (3 * sizeDiff), range: mention.range)
result.addAttribute(.currentUserMentionBackgroundColor, value: Colors.accent, range: mention.range)
result.addAttribute(.foregroundColor, value: UIColor.black, range: mention.range)
result.addAttribute(.currentUserMentionBackgroundColor, value: primaryColor.color, range: mention.range)
result.addAttribute(
.foregroundColor,
value: UIColor.black, // Note: This text should always be black
range: mention.range
)
}
else {
let color: UIColor = {
switch (isLightMode, isOutgoingMessage) {
case (_, true): return .black
case (true, false): return .black
case (false, false): return Colors.accent
}
}()
result.addAttribute(.foregroundColor, value: color, range: mention.range)
result.addAttribute(
.foregroundColor,
value: (isOutgoingMessage ? primaryColor.color : textColor),
range: mention.range
)
}
}

View File

@ -4,6 +4,7 @@ import Foundation
import GRDB
import SignalCoreKit
import SessionUtilitiesKit
import SessionUIKit
public struct RecipientState: Codable, Equatable, FetchableRecord, PersistableRecord, TableRecord, ColumnExpressible {
public static var databaseTableName: String { "recipientState" }
@ -63,6 +64,19 @@ public struct RecipientState: Codable, Equatable, FetchableRecord, PersistableRe
return "MESSAGE_STATUS_SENT".localized()
}
}
public func statusIconInfo(variant: Interaction.Variant, hasAtLeastOneReadReceipt: Bool) -> (image: UIImage?, tintColor: ThemeValue) {
guard variant == .standardOutgoing else { return (nil, .textPrimary) }
switch (self, hasAtLeastOneReadReceipt) {
case (.sending, _): return (UIImage(systemName: "ellipsis.circle"), .textPrimary)
case (.sent, false), (.skipped, _):
return (UIImage(systemName: "checkmark.circle"), .textPrimary)
case (.sent, true): return (UIImage(systemName: "checkmark.circle.fill"), .textPrimary)
case (.failed, _): return (UIImage(systemName: "exclamationmark.circle"), .danger)
}
}
}
/// The id for the interaction this state belongs to

View File

@ -50,6 +50,7 @@ public struct SessionThreadViewModel: FetchableRecordWithRowId, Decodable, Equat
public static let interactionTimestampMsKey: SQL = SQL(stringLiteral: CodingKeys.interactionTimestampMs.stringValue)
public static let interactionBodyKey: SQL = SQL(stringLiteral: CodingKeys.interactionBody.stringValue)
public static let interactionStateKey: SQL = SQL(stringLiteral: CodingKeys.interactionState.stringValue)
public static let interactionHasAtLeastOneReadReceiptKey: SQL = SQL(stringLiteral: CodingKeys.interactionHasAtLeastOneReadReceipt.stringValue)
public static let interactionIsOpenGroupInvitationKey: SQL = SQL(stringLiteral: CodingKeys.interactionIsOpenGroupInvitation.stringValue)
public static let interactionAttachmentDescriptionInfoKey: SQL = SQL(stringLiteral: CodingKeys.interactionAttachmentDescriptionInfo.stringValue)
public static let interactionAttachmentCountKey: SQL = SQL(stringLiteral: CodingKeys.interactionAttachmentCount.stringValue)
@ -117,6 +118,7 @@ public struct SessionThreadViewModel: FetchableRecordWithRowId, Decodable, Equat
private let interactionTimestampMs: Int64?
public let interactionBody: String?
public let interactionState: RecipientState.State?
public let interactionHasAtLeastOneReadReceipt: Bool?
public let interactionIsOpenGroupInvitation: Bool?
public let interactionAttachmentDescriptionInfo: Attachment.DescriptionInfo?
public let interactionAttachmentCount: Int?
@ -269,6 +271,7 @@ public extension SessionThreadViewModel {
self.interactionTimestampMs = nil
self.interactionBody = nil
self.interactionState = nil
self.interactionHasAtLeastOneReadReceipt = nil
self.interactionIsOpenGroupInvitation = nil
self.interactionAttachmentDescriptionInfo = nil
self.interactionAttachmentCount = nil
@ -323,6 +326,7 @@ public extension SessionThreadViewModel {
interactionTimestampMs: self.interactionTimestampMs,
interactionBody: self.interactionBody,
interactionState: self.interactionState,
interactionHasAtLeastOneReadReceipt: self.interactionHasAtLeastOneReadReceipt,
interactionIsOpenGroupInvitation: self.interactionIsOpenGroupInvitation,
interactionAttachmentDescriptionInfo: self.interactionAttachmentDescriptionInfo,
interactionAttachmentCount: self.interactionAttachmentCount,
@ -366,6 +370,9 @@ public extension SessionThreadViewModel {
let interactionAttachment: TypedTableAlias<InteractionAttachment> = TypedTableAlias()
let profile: TypedTableAlias<Profile> = TypedTableAlias()
let interactionStateInteractionIdColumnLiteral: SQL = SQL(stringLiteral: RecipientState.Columns.interactionId.name)
let readReceiptTableLiteral: SQL = SQL(stringLiteral: "readReceipt")
let readReceiptReadTimestampMsColumnLiteral: SQL = SQL(stringLiteral: RecipientState.Columns.readTimestampMs.name)
let profileIdColumnLiteral: SQL = SQL(stringLiteral: Profile.Columns.id.name)
let profileNicknameColumnLiteral: SQL = SQL(stringLiteral: Profile.Columns.nickname.name)
let profileNameColumnLiteral: SQL = SQL(stringLiteral: Profile.Columns.name.name)
@ -380,7 +387,7 @@ public extension SessionThreadViewModel {
///
/// Explicitly set default values for the fields ignored for search results
let numColumnsBeforeProfiles: Int = 12
let numColumnsBetweenProfilesAndAttachmentInfo: Int = 10 // The attachment info columns will be combined
let numColumnsBetweenProfilesAndAttachmentInfo: Int = 11 // The attachment info columns will be combined
let request: SQLRequest<ViewModel> = """
SELECT
@ -415,6 +422,7 @@ public extension SessionThreadViewModel {
-- Default to 'sending' assuming non-processed interaction when null
IFNULL(MIN(\(recipientState[.state])), \(SQL("\(RecipientState.State.sending)"))) AS \(ViewModel.interactionStateKey),
(\(readReceiptTableLiteral).\(readReceiptReadTimestampMsColumnLiteral) IS NOT NULL) AS \(ViewModel.interactionHasAtLeastOneReadReceiptKey),
(\(linkPreview[.url]) IS NOT NULL) AS \(ViewModel.interactionIsOpenGroupInvitationKey),
-- These 4 properties will be combined into 'Attachment.DescriptionInfo'
@ -456,6 +464,10 @@ public extension SessionThreadViewModel {
\(SQL("\(recipientState[.state]) != \(RecipientState.State.skipped)")) AND
\(recipientState[.interactionId]) = \(Interaction.self).\(ViewModel.interactionIdKey)
)
LEFT JOIN \(RecipientState.self) AS \(readReceiptTableLiteral) ON (
\(readReceiptTableLiteral).\(readReceiptReadTimestampMsColumnLiteral) IS NOT NULL AND
\(Interaction.self).\(ViewModel.interactionIdKey) = \(readReceiptTableLiteral).\(interactionStateInteractionIdColumnLiteral)
)
LEFT JOIN \(LinkPreview.self) ON (
\(linkPreview[.url]) = \(interaction[.linkPreviewUrl]) AND
\(SQL("\(linkPreview[.variant]) = \(LinkPreview.Variant.openGroupInvitation)")) AND

View File

@ -6,7 +6,7 @@ import PromiseKit
import SignalUtilitiesKit
import SessionUIKit
final class ShareVC : UINavigationController, ShareViewDelegate, AppModeManagerDelegate {
final class ShareVC: UINavigationController, ShareViewDelegate, AppModeManagerDelegate {
private var areVersionMigrationsComplete = false
public static var attachmentPrepPromise: Promise<[SignalAttachment]>?
@ -29,6 +29,9 @@ final class ShareVC : UINavigationController, ShareViewDelegate, AppModeManagerD
SetCurrentAppContext(appContext)
AppModeManager.configure(delegate: self)
// Need to manually trigger these since we don't have a "mainWindow" here
ThemeManager.applyNavigationStyling()
ThemeManager.applyWindowStyling()
Logger.info("")
@ -66,6 +69,14 @@ final class ShareVC : UINavigationController, ShareViewDelegate, AppModeManagerD
object: nil
)
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
// Note: The share extension doesn't have a proper window so we need to manually update
// the ThemeManager from here
ThemeManager.traitCollectionDidChange(previousTraitCollection)
}
@objc
func versionMigrationsDidComplete(needsConfigSync: Bool) {

View File

@ -45,32 +45,15 @@ final class ThreadPickerVC: UIViewController, UITableViewDataSource, UITableView
return tableView
}()
private lazy var fadeView: UIView = {
let view = UIView()
let gradient = Gradients.homeVCFade
view.setGradient(gradient)
view.isUserInteractionEnabled = false
return view
}()
// MARK: - Lifecycle
override func viewDidLoad() {
super.viewDidLoad()
setupNavBar()
// Gradient
view.themeBackgroundColor = .backgroundPrimary
// Title
navigationItem.titleView = titleLabel
// Table view
view.themeBackgroundColor = .backgroundPrimary
view.addSubview(tableView)
view.addSubview(fadeView)
setupLayout()
@ -110,22 +93,6 @@ final class ThreadPickerVC: UIViewController, UITableViewDataSource, UITableView
dataChangeObservable?.cancel()
}
private func setupNavBar() {
guard let navigationBar = navigationController?.navigationBar else { return }
if #available(iOS 15.0, *) {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = Colors.navigationBarBackground
navigationBar.standardAppearance = appearance;
navigationBar.scrollEdgeAppearance = navigationBar.standardAppearance
}
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
view.setGradient(Gradients.defaultBackground)
fadeView.setGradient(Gradients.homeVCFade)
}
// MARK: Layout
private func setupLayout() {

View File

@ -13,18 +13,18 @@ enum _001_ThemePreferences: Migration {
static let minExpectedRunDuration: TimeInterval = 0.1
static func migrate(_ db: Database) throws {
// Start by adding the jobs that don't have collections (in the jobs like these
// will be added via migrations)
// Determine if the user was matching the system setting
let isMatchingSystemSetting: Bool = UserDefaults.standard.dictionaryRepresentation()
.keys
.contains("appMode")
// TODO: Test the migration works
// Set the default theme settings sccordingly
db[.themeMatchSystemDayNightCycle] = isMatchingSystemSetting
db[.theme] = (isMatchingSystemSetting ?
Theme.classicDark : (
UserDefaults.standard.integer(forKey: "appMode") == 0 ?
Theme.classicLight :
Theme.classicDark
Theme.classicDark :
(UserDefaults.standard.integer(forKey: "appMode") == 0 ?
Theme.classicLight :
Theme.classicDark
)
)
db[.themePrimaryColor] = Theme.PrimaryColor.green

View File

@ -22,54 +22,6 @@ public extension Setting.BoolKey {
// MARK: - ThemeManager
public enum ThemeManager {
fileprivate class ThemeApplier {
enum InfoKey: String {
case keyPath
case controlState
}
private let applyTheme: (Theme) -> ()
private let info: [AnyHashable]
private var otherAppliers: [ThemeManager.ThemeApplier]?
init(
existingApplier: ThemeManager.ThemeApplier?,
info: [AnyHashable],
applyTheme: @escaping (Theme) -> ()
) {
self.applyTheme = applyTheme
self.info = info
// Store any existing "appliers" (removing their 'otherApplier' references to prevent
// loops and excluding any which match the current "info" as they should be replaced
// by this applier)
self.otherAppliers = [existingApplier]
.appending(contentsOf: existingApplier?.otherAppliers)
.compactMap { $0?.clearingOtherAppliers() }
.filter { $0.info != info }
// Automatically apply the theme immediately
self.apply(theme: ThemeManager.currentTheme)
}
// MARK: - Functions
private func clearingOtherAppliers() -> ThemeManager.ThemeApplier {
self.otherAppliers = nil
return self
}
fileprivate func apply(theme: Theme) {
self.applyTheme(theme)
// If there are otherAppliers stored against this one then trigger those as well
self.otherAppliers?.forEach { applier in
applier.applyTheme(theme)
}
}
}
/// **Note:** Using `weakToStrongObjects` means that the value types will continue to be maintained until the map table resizes
/// itself (ie. until a new UI element is registered to the table)
///
@ -126,13 +78,9 @@ public enum ThemeManager {
db[.themeMatchSystemDayNightCycle] = matchSystemNightModeSetting
}
// If the user enabled the "match system" setting then update the UI if needed
guard
matchSystemNightModeSetting &&
UITraitCollection.current.userInterfaceStyle != ThemeManager.currentTheme.interfaceStyle
else { return }
traitCollectionDidChange(UITraitCollection.current)
// Note: We have to trigger this directly or the 'TraitObservingWindow' won't actually
// trigger the trait change if the app launched with this setting switched off
applyWindowStyling()
}
}
@ -248,9 +196,7 @@ public enum ThemeManager {
public static func applyWindowStyling() {
mainWindow?.overrideUserInterfaceStyle = {
guard !Storage.shared[.themeMatchSystemDayNightCycle] else {
return .unspecified
}
guard !ThemeManager.matchSystemNightModeSetting else { return .unspecified }
switch ThemeManager.currentTheme.interfaceStyle {
case .light: return .light
@ -263,7 +209,7 @@ public enum ThemeManager {
public static func onThemeChange(observer: AnyObject, callback: @escaping (Theme, Theme.PrimaryColor) -> ()) {
ThemeManager.uiRegistry.setObject(
ThemeManager.ThemeApplier(
ThemeApplier(
existingApplier: nil,
info: []
) { theme in callback(theme, ThemeManager.primaryColor) },
@ -280,14 +226,14 @@ public enum ThemeManager {
applyWindowStyling()
}
fileprivate static func set<T: AnyObject>(
internal static func set<T: AnyObject>(
_ view: T,
keyPath: ReferenceWritableKeyPath<T, UIColor?>,
to value: ThemeValue?,
for state: UIControl.State = .normal
) {
ThemeManager.uiRegistry.setObject(
ThemeManager.ThemeApplier(
ThemeApplier(
existingApplier: ThemeManager.get(for: view),
info: [ keyPath ]
) { [weak view] theme in
@ -302,14 +248,14 @@ public enum ThemeManager {
)
}
fileprivate static func set<T: AnyObject>(
internal static func set<T: AnyObject>(
_ view: T,
keyPath: ReferenceWritableKeyPath<T, CGColor?>,
to value: ThemeValue?,
for state: UIControl.State = .normal
) {
ThemeManager.uiRegistry.setObject(
ThemeManager.ThemeApplier(
ThemeApplier(
existingApplier: ThemeManager.get(for: view),
info: [ keyPath ]
) { [weak view] theme in
@ -324,9 +270,9 @@ public enum ThemeManager {
)
}
fileprivate static func set<T: AnyObject>(
internal static func set<T: AnyObject>(
_ view: T,
to applier: ThemeManager.ThemeApplier,
to applier: ThemeApplier,
for state: UIControl.State = .normal
) {
ThemeManager.uiRegistry.setObject(applier, forKey: view)
@ -335,135 +281,62 @@ public enum ThemeManager {
/// Using a `UIColor(dynamicProvider:)` unfortunately doesn't seem to work properly for some controls (eg. UISwitch) so
/// since we are already explicitly updating all UI when changing colours & states we just force-resolve the primary colour to avoid
/// running into these glitches
fileprivate static func resolvedColor(_ color: UIColor?) -> UIColor? {
internal static func resolvedColor(_ color: UIColor?) -> UIColor? {
return color?.resolvedColor(with: UITraitCollection())
}
fileprivate static func get(for view: AnyObject) -> ThemeApplier? {
internal static func get(for view: AnyObject) -> ThemeApplier? {
return ThemeManager.uiRegistry.object(forKey: view)
}
}
// MARK: - View Extensions
// MARK: - ThemeApplier
public extension UIView {
var themeBackgroundColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.backgroundColor, to: newValue) }
get { return nil }
internal class ThemeApplier {
enum InfoKey: String {
case keyPath
case controlState
}
var themeTintColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.tintColor, to: newValue) }
get { return nil }
}
private let applyTheme: (Theme) -> ()
private let info: [AnyHashable]
private var otherAppliers: [ThemeApplier]?
var themeBorderColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.layer.borderColor, to: newValue) }
get { return nil }
}
var themeShadowColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.layer.shadowColor, to: newValue) }
get { return nil }
}
}
public extension UILabel {
var themeTextColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.textColor, to: newValue) }
get { return nil }
}
}
public extension UITextView {
var themeTextColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.textColor, to: newValue) }
get { return nil }
}
}
public extension UITextField {
var themeTextColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.textColor, to: newValue) }
get { return nil }
}
}
public extension UIButton {
func setThemeBackgroundColor(_ value: ThemeValue?, for state: UIControl.State) {
let keyPath: KeyPath<UIButton, UIImage?> = \.imageView?.image
init(
existingApplier: ThemeApplier?,
info: [AnyHashable],
applyTheme: @escaping (Theme) -> ()
) {
self.applyTheme = applyTheme
self.info = info
ThemeManager.set(
self,
to: ThemeManager.ThemeApplier(
existingApplier: ThemeManager.get(for: self),
info: [
keyPath,
state.rawValue
]
) { [weak self] theme in
guard
let value: ThemeValue = value,
let color: UIColor = ThemeManager.resolvedColor(theme.colors[value])
else {
self?.setBackgroundImage(nil, for: state)
return
}
self?.setBackgroundImage(color.toImage(), for: state)
}
)
}
func setThemeTitleColor(_ value: ThemeValue?, for state: UIControl.State) {
let keyPath: KeyPath<UIButton, UIColor?> = \.titleLabel?.textColor
// Store any existing "appliers" (removing their 'otherApplier' references to prevent
// loops and excluding any which match the current "info" as they should be replaced
// by this applier)
self.otherAppliers = [existingApplier]
.appending(contentsOf: existingApplier?.otherAppliers)
.compactMap { $0?.clearingOtherAppliers() }
.filter { $0.info != info }
ThemeManager.set(
self,
to: ThemeManager.ThemeApplier(
existingApplier: ThemeManager.get(for: self),
info: [
keyPath,
state.rawValue
]
) { [weak self] theme in
guard let value: ThemeValue = value else {
self?.setTitleColor(nil, for: state)
return
}
self?.setTitleColor(
ThemeManager.resolvedColor(theme.colors[value]),
for: state
)
}
)
}
}
public extension UISwitch {
var themeOnTintColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.onTintColor, to: newValue) }
get { return nil }
}
}
public extension UIBarButtonItem {
var themeTintColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.tintColor, to: newValue) }
get { return nil }
}
}
public extension CAShapeLayer {
var themeStrokeColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.strokeColor, to: newValue) }
get { return nil }
// Automatically apply the theme immediately
self.apply(theme: ThemeManager.currentTheme)
}
var themeFillColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.fillColor, to: newValue) }
get { return nil }
// MARK: - Functions
private func clearingOtherAppliers() -> ThemeApplier {
self.otherAppliers = nil
return self
}
fileprivate func apply(theme: Theme) {
self.applyTheme(theme)
// If there are otherAppliers stored against this one then trigger those as well
self.otherAppliers?.forEach { applier in
applier.applyTheme(theme)
}
}
}

View File

@ -11,6 +11,7 @@ internal enum Theme_ClassicDark: ThemeColors {
.clear: #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0),
.backgroundPrimary: #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1),
.backgroundSecondary: #colorLiteral(red: 0.1058823529, green: 0.1058823529, blue: 0.1058823529, alpha: 1),
.backgroundTertiary: #colorLiteral(red: 0.1764705882, green: 0.1764705882, blue: 0.1764705882, alpha: 1),
.textPrimary: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
.textSecondary: #colorLiteral(red: 0.631372549, green: 0.6352941176, blue: 0.631372549, alpha: 1),
.borderSeparator: #colorLiteral(red: 0.2549019608, green: 0.2549019608, blue: 0.2549019608, alpha: 1),
@ -28,7 +29,8 @@ internal enum Theme_ClassicDark: ThemeColors {
// MenuButton
.menuButton_background: .primary,
.menuButton_icon: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
.menuButton_shadow: .primary,
.menuButton_outerShadow: .primary,
.menuButton_innerShadow: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
// RadioButton
.radioButton_selectedBackground: .primary,
@ -60,6 +62,12 @@ internal enum Theme_ClassicDark: ThemeColors {
// ConversationButton
.conversationButton_background: #colorLiteral(red: 0.1058823529, green: 0.1058823529, blue: 0.1058823529, alpha: 1),
.conversationButton_highlight: #colorLiteral(red: 0.2549019608, green: 0.2549019608, blue: 0.2549019608, alpha: 1)
.conversationButton_highlight: #colorLiteral(red: 0.2549019608, green: 0.2549019608, blue: 0.2549019608, alpha: 1),
.conversationButton_unreadBackground: #colorLiteral(red: 0.1764705882, green: 0.1764705882, blue: 0.1764705882, alpha: 1),
.conversationButton_unreadHighlight: #colorLiteral(red: 0.2549019608, green: 0.2549019608, blue: 0.2549019608, alpha: 1),
.conversationButton_unreadStripBackground: .primary,
.conversationButton_unreadBubbleBackground: #colorLiteral(red: 0.2549019608, green: 0.2549019608, blue: 0.2549019608, alpha: 1),
.conversationButton_unreadBubbleText: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
.conversationButton_pinBackground: Theme.PrimaryColor.yellow.color
]
}

View File

@ -11,6 +11,7 @@ internal enum Theme_ClassicLight: ThemeColors {
.clear: #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0),
.backgroundPrimary: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
.backgroundSecondary: #colorLiteral(red: 0.9764705882, green: 0.9764705882, blue: 0.9764705882, alpha: 1),
.backgroundTertiary: #colorLiteral(red: 0.9058823529, green: 0.9058823529, blue: 0.9058823529, alpha: 1),
.textPrimary: #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1),
.textSecondary: #colorLiteral(red: 0.4274509804, green: 0.4274509804, blue: 0.4274509804, alpha: 1),
.borderSeparator: #colorLiteral(red: 0.631372549, green: 0.6352941176, blue: 0.631372549, alpha: 1),
@ -28,7 +29,8 @@ internal enum Theme_ClassicLight: ThemeColors {
// MenuButton
.menuButton_background: .primary,
.menuButton_icon: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
.menuButton_shadow: #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1),
.menuButton_outerShadow: #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1),
.menuButton_innerShadow: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
// RadioButton
.radioButton_selectedBackground: .primary,
@ -60,6 +62,12 @@ internal enum Theme_ClassicLight: ThemeColors {
// ConversationButton
.conversationButton_background: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
.conversationButton_highlight: #colorLiteral(red: 0.9411764706, green: 0.9411764706, blue: 0.9411764706, alpha: 1)
.conversationButton_highlight: #colorLiteral(red: 0.9411764706, green: 0.9411764706, blue: 0.9411764706, alpha: 1),
.conversationButton_unreadBackground: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
.conversationButton_unreadHighlight: #colorLiteral(red: 0.9411764706, green: 0.9411764706, blue: 0.9411764706, alpha: 1),
.conversationButton_unreadStripBackground: .primary,
.conversationButton_unreadBubbleBackground: #colorLiteral(red: 0.8745098039, green: 0.8745098039, blue: 0.8745098039, alpha: 1),
.conversationButton_unreadBubbleText: #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1),
.conversationButton_pinBackground: Theme.PrimaryColor.yellow.color
]
}

View File

@ -11,6 +11,7 @@ internal enum Theme_OceanDark: ThemeColors {
.clear: #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0),
.backgroundPrimary: #colorLiteral(red: 0.1450980392, green: 0.1529411765, blue: 0.2078431373, alpha: 1),
.backgroundSecondary: #colorLiteral(red: 0.1019607843, green: 0.1098039216, blue: 0.1568627451, alpha: 1),
.backgroundTertiary: #colorLiteral(red: 0.1725490196, green: 0.1803921569, blue: 0.2274509804, alpha: 1),
.textPrimary: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
.textSecondary: #colorLiteral(red: 0.6509803922, green: 0.662745098, blue: 0.8078431373, alpha: 1),
.borderSeparator: #colorLiteral(red: 0.2392156863, green: 0.2901960784, blue: 0.3647058824, alpha: 1),
@ -28,7 +29,8 @@ internal enum Theme_OceanDark: ThemeColors {
// MenuButton
.menuButton_background: .primary,
.menuButton_icon: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
.menuButton_shadow: .primary,
.menuButton_outerShadow: .primary,
.menuButton_innerShadow: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
// RadioButton
.radioButton_selectedBackground: .primary,
@ -54,12 +56,18 @@ internal enum Theme_OceanDark: ThemeColors {
.settings_tabHighlight: #colorLiteral(red: 0.168627451, green: 0.1764705882, blue: 0.2509803922, alpha: 1),
// Appearance
.appearance_sectionBackground: #colorLiteral(red: 0.1019607843, green: 0.1098039216, blue: 0.1568627451, alpha: 1),
.appearance_buttonBackground: #colorLiteral(red: 0.1019607843, green: 0.1098039216, blue: 0.1568627451, alpha: 1),
.appearance_sectionBackground: #colorLiteral(red: 0.168627451, green: 0.1764705882, blue: 0.2509803922, alpha: 1),
.appearance_buttonBackground: #colorLiteral(red: 0.168627451, green: 0.1764705882, blue: 0.2509803922, alpha: 1),
.appearance_buttonHighlight: #colorLiteral(red: 0.168627451, green: 0.1764705882, blue: 0.2509803922, alpha: 1),
// ConversationButton
.conversationButton_background: #colorLiteral(red: 0.168627451, green: 0.168627451, blue: 0.2509803922, alpha: 1),
.conversationButton_highlight: #colorLiteral(red: 0.168627451, green: 0.1764705882, blue: 0.2509803922, alpha: 1)
.conversationButton_highlight: #colorLiteral(red: 0.168627451, green: 0.1764705882, blue: 0.2509803922, alpha: 1),
.conversationButton_unreadBackground: #colorLiteral(red: 0.1450980392, green: 0.1529411765, blue: 0.2078431373, alpha: 1),
.conversationButton_unreadHighlight: #colorLiteral(red: 0.168627451, green: 0.1764705882, blue: 0.2509803922, alpha: 1),
.conversationButton_unreadStripBackground: .primary,
.conversationButton_unreadBubbleBackground: Theme.PrimaryColor.blue.color,
.conversationButton_unreadBubbleText: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
.conversationButton_pinBackground: Theme.PrimaryColor.yellow.color
]
}

View File

@ -11,6 +11,7 @@ internal enum Theme_OceanLight: ThemeColors {
.clear: #colorLiteral(red: 0, green: 0, blue: 0, alpha: 0),
.backgroundPrimary: #colorLiteral(red: 0.9882352941, green: 1, blue: 1, alpha: 1),
.backgroundSecondary: #colorLiteral(red: 0.9254901961, green: 0.9803921569, blue: 0.9843137255, alpha: 1),
.backgroundTertiary: #colorLiteral(red: 0.8549019608, green: 0.9098039216, blue: 0.9137254902, alpha: 1),
.textPrimary: #colorLiteral(red: 0.09803921569, green: 0.2039215686, blue: 0.3647058824, alpha: 1),
.textSecondary: #colorLiteral(red: 0.4156862745, green: 0.431372549, blue: 0.5647058824, alpha: 1),
.borderSeparator: #colorLiteral(red: 0.3607843137, green: 0.6666666667, blue: 0.8, alpha: 1),
@ -28,7 +29,8 @@ internal enum Theme_OceanLight: ThemeColors {
// MenuButton
.menuButton_background: .primary,
.menuButton_icon: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
.menuButton_shadow: #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1),
.menuButton_outerShadow: #colorLiteral(red: 0, green: 0, blue: 0, alpha: 1),
.menuButton_innerShadow: #colorLiteral(red: 1, green: 1, blue: 1, alpha: 1),
// RadioButton
.radioButton_selectedBackground: .primary,
@ -60,6 +62,12 @@ internal enum Theme_OceanLight: ThemeColors {
// ConversationButton
.conversationButton_background: #colorLiteral(red: 0.9882352941, green: 1, blue: 1, alpha: 1),
.conversationButton_highlight: #colorLiteral(red: 0.9058823529, green: 0.9529411765, blue: 0.9568627451, alpha: 1)
.conversationButton_highlight: #colorLiteral(red: 0.9058823529, green: 0.9529411765, blue: 0.9568627451, alpha: 1),
.conversationButton_unreadBackground: #colorLiteral(red: 0.9254901961, green: 0.9803921569, blue: 0.9843137255, alpha: 1),
.conversationButton_unreadHighlight: #colorLiteral(red: 0.9058823529, green: 0.9529411765, blue: 0.9568627451, alpha: 1),
.conversationButton_unreadStripBackground: .primary,
.conversationButton_unreadBubbleBackground: .primary,
.conversationButton_unreadBubbleText: #colorLiteral(red: 0.09803921569, green: 0.2039215686, blue: 0.3647058824, alpha: 1),
.conversationButton_pinBackground: Theme.PrimaryColor.yellow.color
]
}

View File

@ -62,6 +62,7 @@ public enum ThemeValue {
case clear
case backgroundPrimary
case backgroundSecondary
case backgroundTertiary
case textPrimary
case textSecondary
case borderSeparator
@ -79,7 +80,8 @@ public enum ThemeValue {
// MenuButton
case menuButton_background
case menuButton_icon
case menuButton_shadow
case menuButton_outerShadow
case menuButton_innerShadow
// RadioButton
case radioButton_selectedBackground
@ -112,4 +114,10 @@ public enum ThemeValue {
// ConversationButton
case conversationButton_background
case conversationButton_highlight
case conversationButton_unreadBackground
case conversationButton_unreadHighlight
case conversationButton_unreadStripBackground
case conversationButton_unreadBubbleBackground
case conversationButton_unreadBubbleText
case conversationButton_pinBackground
}

View File

@ -0,0 +1,155 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
public extension UIView {
var themeBackgroundColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.backgroundColor, to: newValue) }
get { return nil }
}
var themeTintColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.tintColor, to: newValue) }
get { return nil }
}
var themeBorderColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.layer.borderColor, to: newValue) }
get { return nil }
}
var themeShadowColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.layer.shadowColor, to: newValue) }
get { return nil }
}
}
public extension UILabel {
var themeTextColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.textColor, to: newValue) }
get { return nil }
}
}
public extension UITextView {
var themeTextColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.textColor, to: newValue) }
get { return nil }
}
}
public extension UITextField {
var themeTextColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.textColor, to: newValue) }
get { return nil }
}
}
public extension UIButton {
func setThemeBackgroundColor(_ value: ThemeValue?, for state: UIControl.State) {
let keyPath: KeyPath<UIButton, UIImage?> = \.imageView?.image
ThemeManager.set(
self,
to: ThemeApplier(
existingApplier: ThemeManager.get(for: self),
info: [
keyPath,
state.rawValue
]
) { [weak self] theme in
guard
let value: ThemeValue = value,
let color: UIColor = ThemeManager.resolvedColor(theme.colors[value])
else {
self?.setBackgroundImage(nil, for: state)
return
}
self?.setBackgroundImage(color.toImage(), for: state)
}
)
}
func setThemeTitleColor(_ value: ThemeValue?, for state: UIControl.State) {
let keyPath: KeyPath<UIButton, UIColor?> = \.titleLabel?.textColor
ThemeManager.set(
self,
to: ThemeApplier(
existingApplier: ThemeManager.get(for: self),
info: [
keyPath,
state.rawValue
]
) { [weak self] theme in
guard let value: ThemeValue = value else {
self?.setTitleColor(nil, for: state)
return
}
self?.setTitleColor(
ThemeManager.resolvedColor(theme.colors[value]),
for: state
)
}
)
}
}
public extension UISwitch {
var themeOnTintColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.onTintColor, to: newValue) }
get { return nil }
}
}
public extension UIBarButtonItem {
var themeTintColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.tintColor, to: newValue) }
get { return nil }
}
}
public extension UIProgressView {
var themeProgressTintColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.progressTintColor, to: newValue) }
get { return nil }
}
var themeTrackTintColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.trackTintColor, to: newValue) }
get { return nil }
}
}
public extension UITableViewRowAction {
var themeBackgroundColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.backgroundColor, to: newValue) }
get { return nil }
}
}
public extension CAShapeLayer {
var themeStrokeColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.strokeColor, to: newValue) }
get { return nil }
}
var themeFillColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.fillColor, to: newValue) }
get { return nil }
}
}
public extension CALayer {
var themeBorderColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.borderColor, to: newValue) }
get { return nil }
}
var themeShadowColor: ThemeValue? {
set { ThemeManager.set(self, keyPath: \.shadowColor, to: newValue) }
get { return nil }
}
}

View File

@ -516,8 +516,14 @@ public class PagedDatabaseObserver<ObservedTable, T>: TransactionObserver where
limit: queryInfo.limit,
offset: queryInfo.offset
)
let newData: [T] = try dataQuery(pageRowIds)
.fetchAll(db)
let newData: [T]
do { newData = try dataQuery(pageRowIds).fetchAll(db) }
catch {
SNLog("PagedDatabaseObserver threw exception: \(error)")
throw error
}
let updatedLimitInfo: PagedData.PageInfo = PagedData.PageInfo(
pageSize: currentPageInfo.pageSize,
pageOffset: queryInfo.updatedCacheOffset,

View File

@ -1,6 +1,7 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import SessionUIKit
import SessionUtilitiesKit
@objc(LKIdenticon)

View File

@ -1,14 +1,14 @@
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
import UIKit
import CryptoSwift
import SessionUIKit
public class PlaceholderIcon {
private let seed: Int
// Colour palette
private var colours: [UIColor] = [
0x5ff8b0,
0x26cdb9,
0xf3c615,
0xfcac5a
].map { UIColor(hex: $0) }
private var colours: [UIColor] = Theme.PrimaryColor.allCases.map { $0.color }
init(seed: Int, colours: [UIColor]? = nil) {
self.seed = seed

View File

@ -19,8 +19,15 @@ public final class ProfilePictureView: UIView {
// MARK: - Components
private lazy var imageView = getImageView()
private lazy var additionalImageView = getImageView()
private lazy var imageView: YYAnimatedImageView = getImageView()
private lazy var additionalImageView: YYAnimatedImageView = {
let result: YYAnimatedImageView = getImageView()
result.themeBackgroundColor = .backgroundTertiary
result.themeBorderColor = .backgroundPrimary
result.layer.borderWidth = Values.separatorThickness
return result
}()
// MARK: - Lifecycle