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:
parent
d56cee8234
commit
ea32e407a9
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
@ -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 ]
|
||||
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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),
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
Binary file not shown.
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "CircleDotDotDot.pdf"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "FilledCircleCheckDarkMode.pdf"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -1,12 +0,0 @@
|
|||
{
|
||||
"images" : [
|
||||
{
|
||||
"idiom" : "universal",
|
||||
"filename" : "FilledCircleCheckLightMode.pdf"
|
||||
}
|
||||
],
|
||||
"info" : {
|
||||
"version" : 1,
|
||||
"author" : "xcode"
|
||||
}
|
||||
}
|
Binary file not shown.
|
@ -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 |
|
@ -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: %@";
|
||||
|
|
|
@ -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: %@";
|
||||
|
|
|
@ -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: %@";
|
||||
|
|
|
@ -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: %@";
|
||||
|
|
|
@ -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: %@";
|
||||
|
|
|
@ -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: %@";
|
||||
|
|
|
@ -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: %@";
|
||||
|
|
|
@ -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: %@";
|
||||
|
|
|
@ -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: %@";
|
||||
|
|
|
@ -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: %@";
|
||||
|
|
|
@ -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: %@";
|
||||
|
|
|
@ -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: %@";
|
||||
|
|
|
@ -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: %@";
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -25,8 +25,6 @@ final class DisplayNameVC: BaseVC {
|
|||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
setUpGradientBackground()
|
||||
setUpNavBarStyle()
|
||||
setUpNavBarSessionIcon()
|
||||
|
||||
// Set up title label
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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))
|
||||
|
|
|
@ -50,8 +50,6 @@ final class RegisterVC : BaseVC {
|
|||
// MARK: Lifecycle
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
setUpGradientBackground()
|
||||
setUpNavBarStyle()
|
||||
setUpNavBarSessionIcon()
|
||||
|
||||
// Set up title label
|
||||
|
|
|
@ -47,8 +47,6 @@ final class RestoreVC: BaseVC {
|
|||
|
||||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
setUpGradientBackground()
|
||||
setUpNavBarStyle()
|
||||
setUpNavBarSessionIcon()
|
||||
|
||||
// Set up title label
|
||||
|
|
|
@ -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 ])
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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())
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -127,8 +127,6 @@ final class SettingsVC: BaseVC, AvatarViewHelperDelegate {
|
|||
override func viewDidLoad() {
|
||||
super.viewDidLoad()
|
||||
|
||||
setUpGradientBackground()
|
||||
setUpNavBarStyle()
|
||||
setNavBarTitle("vc_settings_title".localized())
|
||||
|
||||
// Navigation bar buttons
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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!
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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
|
||||
]
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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 }
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
// Copyright © 2022 Rangeproof Pty Ltd. All rights reserved.
|
||||
|
||||
import UIKit
|
||||
import SessionUIKit
|
||||
import SessionUtilitiesKit
|
||||
|
||||
@objc(LKIdenticon)
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
Loading…
Reference in New Issue