diff --git a/Gemfile b/Gemfile index 495f5f49..31652b3e 100644 --- a/Gemfile +++ b/Gemfile @@ -1,6 +1,6 @@ source "https://rubygems.org" gem 'arkana' -gem "cocoapods" +gem "cocoapods", git: 'https://github.com/CocoaPods/CocoaPods.git', ref: '53893a2' gem "cocoapods-clean" gem "xcpretty" diff --git a/Gemfile.lock b/Gemfile.lock index 628232d5..792d6a5e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -1,9 +1,33 @@ +GIT + remote: https://github.com/CocoaPods/CocoaPods.git + revision: 53893a2de0d09827fcdaaf089ac25a98d85ed074 + ref: 53893a2 + specs: + cocoapods (1.12.1) + addressable (~> 2.8) + claide (>= 1.0.2, < 2.0) + cocoapods-core (= 1.12.1) + cocoapods-deintegrate (>= 1.0.3, < 2.0) + cocoapods-downloader (>= 1.6.0, < 2.0) + cocoapods-plugins (>= 1.0.0, < 2.0) + cocoapods-search (>= 1.0.0, < 2.0) + cocoapods-trunk (>= 1.6.0, < 2.0) + cocoapods-try (>= 1.1.0, < 2.0) + colored2 (~> 3.1) + escape (~> 0.0.4) + fourflusher (>= 2.3.0, < 3.0) + gh_inspector (~> 1.0) + molinillo (~> 0.8.0) + nap (~> 1.0) + ruby-macho (>= 2.3.0, < 3.0) + xcodeproj (>= 1.21.0, < 2.0) + GEM remote: https://rubygems.org/ specs: CFPropertyList (3.0.6) rexml - activesupport (7.0.7.2) + activesupport (7.0.8) concurrent-ruby (~> 1.0, >= 1.0.2) i18n (>= 1.6, < 2) minitest (>= 5.1) @@ -19,24 +43,6 @@ GEM yaml (~> 0.2) atomos (0.1.3) claide (1.1.0) - cocoapods (1.12.1) - addressable (~> 2.8) - claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.12.1) - cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 1.6.0, < 2.0) - cocoapods-plugins (>= 1.0.0, < 2.0) - cocoapods-search (>= 1.0.0, < 2.0) - cocoapods-trunk (>= 1.6.0, < 2.0) - cocoapods-try (>= 1.1.0, < 2.0) - colored2 (~> 3.1) - escape (~> 0.0.4) - fourflusher (>= 2.3.0, < 3.0) - gh_inspector (~> 1.0) - molinillo (~> 0.8.0) - nap (~> 1.0) - ruby-macho (>= 2.3.0, < 3.0) - xcodeproj (>= 1.21.0, < 2.0) cocoapods-clean (0.0.1) cocoapods-core (1.12.1) activesupport (>= 5.0, < 8) @@ -71,7 +77,7 @@ GEM i18n (1.14.1) concurrent-ruby (~> 1.0) json (2.6.3) - minitest (5.19.0) + minitest (5.20.0) molinillo (0.8.0) nanaimo (0.3.0) nap (1.1.0) @@ -101,7 +107,7 @@ PLATFORMS DEPENDENCIES arkana - cocoapods + cocoapods! cocoapods-clean xcpretty diff --git a/Podfile b/Podfile index a8b1f03e..b242511d 100644 --- a/Podfile +++ b/Podfile @@ -5,6 +5,9 @@ target 'TwidereX' do # Comment the next line if you don't want to use dynamic frameworks use_frameworks! + # Debug + pod 'LookinServer', :subspecs => ['SwiftAndNoHook'], :configurations => ['Debug'] + ## UI pod 'XLPagerTabStrip', '~> 9.0.0' diff --git a/Podfile.lock b/Podfile.lock index f7ddadb7..562d9cdd 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,107 +1,118 @@ PODS: - - Firebase/AnalyticsWithoutAdIdSupport (9.2.0): + - Firebase/AnalyticsWithoutAdIdSupport (10.15.0): - Firebase/CoreOnly - - FirebaseAnalytics/WithoutAdIdSupport (~> 9.2.0) - - Firebase/CoreOnly (9.2.0): - - FirebaseCore (= 9.2.0) - - FirebaseABTesting (9.2.0): - - FirebaseCore (~> 9.0) - - FirebaseAnalytics/WithoutAdIdSupport (9.2.0): - - FirebaseCore (~> 9.0) - - FirebaseInstallations (~> 9.0) - - GoogleAppMeasurement/WithoutAdIdSupport (= 9.2.0) - - GoogleUtilities/AppDelegateSwizzler (~> 7.7) - - GoogleUtilities/MethodSwizzler (~> 7.7) - - GoogleUtilities/Network (~> 7.7) - - "GoogleUtilities/NSData+zlib (~> 7.7)" + - FirebaseAnalytics/WithoutAdIdSupport (~> 10.15.0) + - Firebase/CoreOnly (10.15.0): + - FirebaseCore (= 10.15.0) + - FirebaseABTesting (10.15.0): + - FirebaseCore (~> 10.0) + - FirebaseAnalytics/WithoutAdIdSupport (10.15.0): + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleAppMeasurement/WithoutAdIdSupport (= 10.15.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" - nanopb (< 2.30910.0, >= 2.30908.0) - - FirebaseCore (9.2.0): - - FirebaseCoreDiagnostics (~> 9.0) - - FirebaseCoreInternal (~> 9.0) - - GoogleUtilities/Environment (~> 7.7) - - GoogleUtilities/Logger (~> 7.7) - - FirebaseCoreDiagnostics (9.2.0): - - GoogleDataTransport (< 10.0.0, >= 9.1.4) - - GoogleUtilities/Environment (~> 7.7) - - GoogleUtilities/Logger (~> 7.7) - - nanopb (< 2.30910.0, >= 2.30908.0) - - FirebaseCoreInternal (9.2.0): - - "GoogleUtilities/NSData+zlib (~> 7.7)" - - FirebaseCrashlytics (9.2.0): - - FirebaseCore (~> 9.0) - - FirebaseInstallations (~> 9.0) - - GoogleDataTransport (< 10.0.0, >= 9.1.4) - - GoogleUtilities/Environment (~> 7.7) + - FirebaseCore (10.15.0): + - FirebaseCoreInternal (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/Logger (~> 7.8) + - FirebaseCoreExtension (10.15.0): + - FirebaseCore (~> 10.0) + - FirebaseCoreInternal (10.15.0): + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - FirebaseCrashlytics (10.15.0): + - FirebaseCore (~> 10.5) + - FirebaseInstallations (~> 10.0) + - FirebaseSessions (~> 10.5) + - GoogleDataTransport (~> 9.2) + - GoogleUtilities/Environment (~> 7.8) - nanopb (< 2.30910.0, >= 2.30908.0) - PromisesObjC (~> 2.1) - - FirebaseInstallations (9.2.0): - - FirebaseCore (~> 9.0) - - GoogleUtilities/Environment (~> 7.7) - - GoogleUtilities/UserDefaults (~> 7.7) + - FirebaseInstallations (10.17.0): + - FirebaseCore (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/UserDefaults (~> 7.8) - PromisesObjC (~> 2.1) - - FirebaseMessaging (9.2.0): - - FirebaseCore (~> 9.0) - - FirebaseInstallations (~> 9.0) - - GoogleDataTransport (< 10.0.0, >= 9.1.4) - - GoogleUtilities/AppDelegateSwizzler (~> 7.7) - - GoogleUtilities/Environment (~> 7.7) - - GoogleUtilities/Reachability (~> 7.7) - - GoogleUtilities/UserDefaults (~> 7.7) + - FirebaseMessaging (10.15.0): + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleDataTransport (~> 9.2) + - GoogleUtilities/AppDelegateSwizzler (~> 7.8) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/Reachability (~> 7.8) + - GoogleUtilities/UserDefaults (~> 7.8) - nanopb (< 2.30910.0, >= 2.30908.0) - - FirebasePerformance (9.2.0): - - FirebaseCore (~> 9.0) - - FirebaseInstallations (~> 9.0) - - FirebaseRemoteConfig (~> 9.0) - - GoogleDataTransport (< 10.0.0, >= 9.1.4) - - GoogleUtilities/Environment (~> 7.7) - - GoogleUtilities/ISASwizzler (~> 7.7) - - GoogleUtilities/MethodSwizzler (~> 7.7) + - FirebasePerformance (10.15.0): + - FirebaseCore (~> 10.5) + - FirebaseInstallations (~> 10.0) + - FirebaseRemoteConfig (~> 10.0) + - FirebaseSessions (~> 10.5) + - GoogleDataTransport (~> 9.2) + - GoogleUtilities/Environment (~> 7.8) + - GoogleUtilities/ISASwizzler (~> 7.8) + - GoogleUtilities/MethodSwizzler (~> 7.8) - nanopb (< 2.30910.0, >= 2.30908.0) - - FirebaseRemoteConfig (9.2.0): - - FirebaseABTesting (~> 9.0) - - FirebaseCore (~> 9.0) - - FirebaseInstallations (~> 9.0) - - GoogleUtilities/Environment (~> 7.7) - - "GoogleUtilities/NSData+zlib (~> 7.7)" - - GoogleAppMeasurement/WithoutAdIdSupport (9.2.0): - - GoogleUtilities/AppDelegateSwizzler (~> 7.7) - - GoogleUtilities/MethodSwizzler (~> 7.7) - - GoogleUtilities/Network (~> 7.7) - - "GoogleUtilities/NSData+zlib (~> 7.7)" + - FirebaseRemoteConfig (10.15.0): + - FirebaseABTesting (~> 10.0) + - FirebaseCore (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleUtilities/Environment (~> 7.8) + - "GoogleUtilities/NSData+zlib (~> 7.8)" + - FirebaseSessions (10.15.0): + - FirebaseCore (~> 10.5) + - FirebaseCoreExtension (~> 10.0) + - FirebaseInstallations (~> 10.0) + - GoogleDataTransport (~> 9.2) + - GoogleUtilities/Environment (~> 7.10) + - nanopb (< 2.30910.0, >= 2.30908.0) + - PromisesSwift (~> 2.1) + - GoogleAppMeasurement/WithoutAdIdSupport (10.15.0): + - GoogleUtilities/AppDelegateSwizzler (~> 7.11) + - GoogleUtilities/MethodSwizzler (~> 7.11) + - GoogleUtilities/Network (~> 7.11) + - "GoogleUtilities/NSData+zlib (~> 7.11)" - nanopb (< 2.30910.0, >= 2.30908.0) - - GoogleDataTransport (9.1.4): + - GoogleDataTransport (9.2.5): - GoogleUtilities/Environment (~> 7.7) - nanopb (< 2.30910.0, >= 2.30908.0) - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/AppDelegateSwizzler (7.7.0): + - GoogleUtilities/AppDelegateSwizzler (7.11.5): - GoogleUtilities/Environment - GoogleUtilities/Logger - GoogleUtilities/Network - - GoogleUtilities/Environment (7.7.0): + - GoogleUtilities/Environment (7.11.5): - PromisesObjC (< 3.0, >= 1.2) - - GoogleUtilities/ISASwizzler (7.7.0) - - GoogleUtilities/Logger (7.7.0): + - GoogleUtilities/ISASwizzler (7.11.5) + - GoogleUtilities/Logger (7.11.5): - GoogleUtilities/Environment - - GoogleUtilities/MethodSwizzler (7.7.0): + - GoogleUtilities/MethodSwizzler (7.11.5): - GoogleUtilities/Logger - - GoogleUtilities/Network (7.7.0): + - GoogleUtilities/Network (7.11.5): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" - GoogleUtilities/Reachability - - "GoogleUtilities/NSData+zlib (7.7.0)" - - GoogleUtilities/Reachability (7.7.0): + - "GoogleUtilities/NSData+zlib (7.11.5)" + - GoogleUtilities/Reachability (7.11.5): - GoogleUtilities/Logger - - GoogleUtilities/UserDefaults (7.7.0): + - GoogleUtilities/UserDefaults (7.11.5): - GoogleUtilities/Logger - - nanopb (2.30909.0): - - nanopb/decode (= 2.30909.0) - - nanopb/encode (= 2.30909.0) - - nanopb/decode (2.30909.0) - - nanopb/encode (2.30909.0) - - PromisesObjC (2.1.1) - - Sourcery (1.8.1): - - Sourcery/CLI-Only (= 1.8.1) - - Sourcery/CLI-Only (1.8.1) + - LookinServer/Core (1.2.4) + - LookinServer/SwiftAndNoHook (1.2.4): + - LookinServer/Core + - nanopb (2.30909.1): + - nanopb/decode (= 2.30909.1) + - nanopb/encode (= 2.30909.1) + - nanopb/decode (2.30909.1) + - nanopb/encode (2.30909.1) + - PromisesObjC (2.3.1) + - PromisesSwift (2.3.1): + - PromisesObjC (= 2.3.1) + - Sourcery (1.8.2): + - Sourcery/CLI-Only (= 1.8.2) + - Sourcery/CLI-Only (1.8.2) - SwiftGen (6.6.2) - XLPagerTabStrip (9.0.0) @@ -110,6 +121,7 @@ DEPENDENCIES: - FirebaseCrashlytics - FirebaseMessaging - FirebasePerformance + - LookinServer/SwiftAndNoHook - Sourcery (~> 1.8.1) - SwiftGen (~> 6.6.2) - XLPagerTabStrip (~> 9.0.0) @@ -120,43 +132,49 @@ SPEC REPOS: - FirebaseABTesting - FirebaseAnalytics - FirebaseCore - - FirebaseCoreDiagnostics + - FirebaseCoreExtension - FirebaseCoreInternal - FirebaseCrashlytics - FirebaseInstallations - FirebaseMessaging - FirebasePerformance - FirebaseRemoteConfig + - FirebaseSessions - GoogleAppMeasurement - GoogleDataTransport - GoogleUtilities + - LookinServer - nanopb - PromisesObjC + - PromisesSwift - Sourcery - SwiftGen - XLPagerTabStrip SPEC CHECKSUMS: - Firebase: 4ba896cb8e5105d4b9e247e1c1b6222b548df55a - FirebaseABTesting: cd1ec762a0078b46a7ce91dfe5b7b8991c2dff8f - FirebaseAnalytics: af5a03a8dff7648c7b8486f6a78b1368e0268dd3 - FirebaseCore: 0e27f2a15d8f7b7ef11e7d93e23b1cbab55d748c - FirebaseCoreDiagnostics: ad3f6c68b7c5b63b7cf15b0785d7137f05f32268 - FirebaseCoreInternal: cb966328b6985dbd6f535e1461291063e1c4a00f - FirebaseCrashlytics: 9fff819edb2bfc9d3eff612225b207d41945a935 - FirebaseInstallations: 21186f0ca7849f90f4a3219fa31a5eca2e30f113 - FirebaseMessaging: 4eaf1b8a7464b2c5e619ad66e9b20ee3e3206b24 - FirebasePerformance: 5a8d2a9e645a398dfcc02657853f4b946675d5d4 - FirebaseRemoteConfig: 16e29297f0dd0c7d2415c4506d614fe0b54875d1 - GoogleAppMeasurement: 7a33224321f975d58c166657260526775d9c6b1a - GoogleDataTransport: 5fffe35792f8b96ec8d6775f5eccd83c998d5a3b - GoogleUtilities: e0913149f6b0625b553d70dae12b49fc62914fd1 - nanopb: b552cce312b6c8484180ef47159bc0f65a1f0431 - PromisesObjC: ab77feca74fa2823e7af4249b8326368e61014cb - Sourcery: 4d44d4ea26a682a4a9875ec7c1870a1e7b8e183f + Firebase: 66043bd4579e5b73811f96829c694c7af8d67435 + FirebaseABTesting: 7fa3bca17f79ac433301d20d5cd33401f7738dca + FirebaseAnalytics: 47cef43728f81a839cf1306576bdd77ffa2eac7e + FirebaseCore: 2cec518b43635f96afe7ac3a9c513e47558abd2e + FirebaseCoreExtension: d3f1ea3725fb41f56e8fbfb29eeaff54e7ffb8f6 + FirebaseCoreInternal: 2f4bee5ed00301b5e56da0849268797a2dd31fb4 + FirebaseCrashlytics: a83f26fb922a3fe181eb738fb4dcf0c92bba6455 + FirebaseInstallations: 9387bf15abfc69a714f54e54f74a251264fdb79b + FirebaseMessaging: 0c0ae1eb722ef0c07f7801e5ded8dccd1357d6d4 + FirebasePerformance: b7988bc06c87e9c3b9e6b1ae854cd460b646ebd6 + FirebaseRemoteConfig: 64b6ada098c649304114a817effd7e5f87229b11 + FirebaseSessions: ee59a7811bef4c15f65ef6472f3210faa293f9c8 + GoogleAppMeasurement: 722db6550d1e6d552b08398b69a975ac61039338 + GoogleDataTransport: 54dee9d48d14580407f8f5fbf2f496e92437a2f2 + GoogleUtilities: 13e2c67ede716b8741c7989e26893d151b2b2084 + LookinServer: 00c7588043ed8e7ab64ce55b9fb747e51371ad06 + nanopb: d4d75c12cd1316f4a64e3c6963f879ecd4b5e0d5 + PromisesObjC: c50d2056b5253dadbd6c2bea79b0674bd5a52fa4 + PromisesSwift: 28dca69a9c40779916ac2d6985a0192a5cb4a265 + Sourcery: ad4aba88367fbaf0c1ae6ec4ba3282db1b571624 SwiftGen: 1366a7f71aeef49954ca5a63ba4bef6b0f24138c XLPagerTabStrip: 61c57fd61f611ee5f01ff1495ad6fbee8bf496c5 -PODFILE CHECKSUM: e2c773b0e4d6bfd3166d7794b7f8babe8f9b9b92 +PODFILE CHECKSUM: ef3fd250bf0e66df77fec6a0b89b4c70bc1422b8 COCOAPODS: 1.12.1 diff --git a/TwidereSDK/Package.swift b/TwidereSDK/Package.swift index c0860d7d..9fe5bd60 100644 --- a/TwidereSDK/Package.swift +++ b/TwidereSDK/Package.swift @@ -51,12 +51,11 @@ let package = Package( .package(url: "https://github.com/tid-kijyun/Kanna.git", from: "5.2.7"), .package(url: "https://github.com/JohnSundell/CollectionConcurrencyKit.git", from: "0.2.0"), .package(url: "https://github.com/TwidereProject/TwitterSDK.git", exact: "0.18.0"), + .package(url: "https://github.com/saoudrizwan/Disk.git", from: "0.6.4"), .package(name: "ArkanaKeys", path: "../dependencies/ArkanaKeys"), .package(name: "CoverFlowStackLayout", path: "../CoverFlowStackLayout"), ], targets: [ - // Targets are the basic building blocks of a package. A target can define a module or a test suite. - // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "CoreDataStack", dependencies: [ @@ -110,6 +109,7 @@ let package = Package( .product(name: "Kanna", package: "Kanna"), .product(name: "TwitterSDK", package: "TwitterSDK"), .product(name: "CollectionConcurrencyKit", package: "CollectionConcurrencyKit"), + .product(name: "Disk", package: "Disk"), ] ), .target( diff --git a/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/Contents.json b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/Contents.json new file mode 100644 index 00000000..6e965652 --- /dev/null +++ b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/Contents.json @@ -0,0 +1,9 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "provides-namespace" : true + } +} diff --git a/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/Contents.json b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/Contents.json new file mode 100644 index 00000000..6e965652 --- /dev/null +++ b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/Contents.json @@ -0,0 +1,9 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + }, + "properties" : { + "provides-namespace" : true + } +} diff --git a/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/background.colorset/Contents.json b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/background.colorset/Contents.json new file mode 100644 index 00000000..58970323 --- /dev/null +++ b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/background.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xE2", + "green" : "0xEE", + "red" : "0xF8" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0.886", + "green" : "0.933", + "red" : "0.973" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/bookmark.colorset/Contents.json b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/bookmark.colorset/Contents.json new file mode 100644 index 00000000..a15174c5 --- /dev/null +++ b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/bookmark.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x9B", + "green" : "0x76", + "red" : "0xF4" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x9B", + "green" : "0x76", + "red" : "0xF4" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/comment.colorset/Contents.json b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/comment.colorset/Contents.json new file mode 100644 index 00000000..b3fbb526 --- /dev/null +++ b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/comment.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x6F", + "green" : "0x7A", + "red" : "0xBE" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x6F", + "green" : "0x7A", + "red" : "0xBE" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/comment.disabled.colorset/Contents.json b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/comment.disabled.colorset/Contents.json new file mode 100644 index 00000000..cf6f55ef --- /dev/null +++ b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/comment.disabled.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xC1", + "green" : "0xAE", + "red" : "0xA6" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xC1", + "green" : "0xAE", + "red" : "0xA6" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/foreground.colorset/Contents.json b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/foreground.colorset/Contents.json new file mode 100644 index 00000000..47faaad6 --- /dev/null +++ b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/foreground.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x4F", + "green" : "0x3E", + "red" : "0x6A" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x4F", + "green" : "0x3E", + "red" : "0x6A" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/highlight.colorset/Contents.json b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/highlight.colorset/Contents.json new file mode 100644 index 00000000..a15174c5 --- /dev/null +++ b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/highlight.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x9B", + "green" : "0x76", + "red" : "0xF4" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0x9B", + "green" : "0x76", + "red" : "0xF4" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/like.colorset/Contents.json b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/like.colorset/Contents.json new file mode 100644 index 00000000..edda8abb --- /dev/null +++ b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/like.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF2", + "green" : "0x9F", + "red" : "0x87" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF2", + "green" : "0x9F", + "red" : "0x87" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/line.colorset/Contents.json b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/line.colorset/Contents.json new file mode 100644 index 00000000..834fd36e --- /dev/null +++ b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/line.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xC6", + "green" : "0xD3", + "red" : "0xDE" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xC6", + "green" : "0xD3", + "red" : "0xDE" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/repost.colorset/Contents.json b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/repost.colorset/Contents.json new file mode 100644 index 00000000..edda8abb --- /dev/null +++ b/TwidereSDK/Sources/TwidereAsset/Assets.xcassets/Theme/GrandBudapestHotel/repost.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF2", + "green" : "0x9F", + "red" : "0x87" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.000", + "blue" : "0xF2", + "green" : "0x9F", + "red" : "0x87" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/TwidereSDK/Sources/TwidereAsset/Generated/Assets.swift b/TwidereSDK/Sources/TwidereAsset/Generated/Assets.swift index 1730b999..f64a19d8 100644 --- a/TwidereSDK/Sources/TwidereAsset/Generated/Assets.swift +++ b/TwidereSDK/Sources/TwidereAsset/Generated/Assets.swift @@ -223,6 +223,19 @@ public enum Asset { public static let textQuote = ImageAsset(name: "TextFormatting/text.quote") public static let textQuoteMini = ImageAsset(name: "TextFormatting/text.quote.mini") } + public enum Theme { + public enum GrandBudapestHotel { + public static let background = ColorAsset(name: "Theme/GrandBudapestHotel/background") + public static let bookmark = ColorAsset(name: "Theme/GrandBudapestHotel/bookmark") + public static let comment = ColorAsset(name: "Theme/GrandBudapestHotel/comment") + public static let commentDisabled = ColorAsset(name: "Theme/GrandBudapestHotel/comment.disabled") + public static let foreground = ColorAsset(name: "Theme/GrandBudapestHotel/foreground") + public static let highlight = ColorAsset(name: "Theme/GrandBudapestHotel/highlight") + public static let like = ColorAsset(name: "Theme/GrandBudapestHotel/like") + public static let line = ColorAsset(name: "Theme/GrandBudapestHotel/line") + public static let repost = ColorAsset(name: "Theme/GrandBudapestHotel/repost") + } + } public enum Transportation { public static let paperAirplane = ImageAsset(name: "Transportation/paper.airplane") } diff --git a/TwidereSDK/Sources/TwidereCommon/Preference/Preference+Theme.swift b/TwidereSDK/Sources/TwidereCommon/Preference/Preference+Theme.swift deleted file mode 100644 index 1c04733f..00000000 --- a/TwidereSDK/Sources/TwidereCommon/Preference/Preference+Theme.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// Preference+Theme.swift -// -// -// Created by Cirno MainasuK on 2021-11-3. -// - -import UIKit - -extension UserDefaults { - - @objc dynamic public var theme: Theme { - get { - guard let rawValue: Int = self[#function] else { - return .daylight - } - return Theme(rawValue: rawValue) ?? .daylight - } - set { - self[#function] = newValue.rawValue - } - } -} - -// Keep rawValue reserved for API compatibility -@objc public enum Theme: Int, CaseIterable { - case daylight = 0 - case maskBlue = 1 - case violet = 2 - case grandBudapest = 3 - case vulcan = 4 - case goldenSpirit = 5 - case lime = 6 - case seafoam = 7 -} diff --git a/TwidereSDK/Sources/TwidereCore/Protocol/TextStyleConfigurable.swift b/TwidereSDK/Sources/TwidereCore/Protocol/TextStyleConfigurable.swift index e250ac4d..5cbf10a4 100644 --- a/TwidereSDK/Sources/TwidereCore/Protocol/TextStyleConfigurable.swift +++ b/TwidereSDK/Sources/TwidereCore/Protocol/TextStyleConfigurable.swift @@ -263,9 +263,14 @@ extension MetaLabel: TextStyleConfigurable { linkAttributes = [ .font: font, - .foregroundColor: ThemeService.shared.theme.value.accentColor + .foregroundColor: Asset.Colors.Theme.daylight.color ] } + + public func setupAttributes(foregroundColor: UIColor) { + textAttributes[.foregroundColor] = foregroundColor + + } } public class PlainLabel: UILabel, TextStyleConfigurable { diff --git a/TwidereSDK/Sources/TwidereCore/Service/ThemeService.swift b/TwidereSDK/Sources/TwidereCore/Service/ThemeService.swift deleted file mode 100644 index 74ece2a1..00000000 --- a/TwidereSDK/Sources/TwidereCore/Service/ThemeService.swift +++ /dev/null @@ -1,78 +0,0 @@ -// -// ThemeService.swift -// ThemeService -// -// Created by Cirno MainasuK on 2021-8-12. -// Copyright © 2021 Twidere. All rights reserved. -// - -import UIKit -import Combine -import TwidereCommon -import TwidereAsset - -@MainActor -public final class ThemeService { - public static let shared = ThemeService() - - public let theme: CurrentValueSubject - - private init() { - theme = CurrentValueSubject(UserDefaults.shared.theme) - } - - public func set(theme: Theme) { - UserDefaults.shared.theme = theme - self.theme.value = theme - apply(theme: theme) - } - - public func apply(theme: Theme) { - // set navigation bar appearance - let appearance = UINavigationBarAppearance() - appearance.configureWithDefaultBackground() - UINavigationBar.appearance().standardAppearance = appearance - UINavigationBar.appearance().compactAppearance = appearance - UINavigationBar.appearance().scrollEdgeAppearance = appearance - UINavigationBar.appearance().compactScrollEdgeAppearance = appearance - - // set tab bar appearance - let tabBarAppearance = ThemeService.setupTabBarAppearance() - UITabBar.appearance().standardAppearance = tabBarAppearance - UITabBar.appearance().scrollEdgeAppearance = tabBarAppearance - } - -} - -extension Theme { - public var accentColor: UIColor { - switch self { - case .daylight: return Asset.Colors.Theme.daylight.color - case .maskBlue: return Asset.Colors.Theme.maskBlue.color - case .violet: return Asset.Colors.Theme.violet.color - case .grandBudapest: return Asset.Colors.Theme.grandBudapest.color - case .vulcan: return Asset.Colors.Theme.vulcan.color - case .goldenSpirit: return Asset.Colors.Theme.goldenSpirit.color - case .lime: return Asset.Colors.Theme.lime.color - case .seafoam: return Asset.Colors.Theme.seafoam.color - } - } -} - -extension ThemeService { - public static func setupTabBarAppearance() -> UITabBarAppearance { - let tabBarAppearance = UITabBarAppearance() - tabBarAppearance.configureWithDefaultBackground() - tabBarAppearance.stackedLayoutAppearance = { - let tabBarItemAppearance = UITabBarItemAppearance() - if !UserDefaults.shared.preferredTabBarLabelDisplay { - tabBarItemAppearance.selected.titleTextAttributes = [.foregroundColor: UIColor.clear] - tabBarItemAppearance.focused.titleTextAttributes = [.foregroundColor: UIColor.clear] - tabBarItemAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.clear] - tabBarItemAppearance.disabled.titleTextAttributes = [.foregroundColor: UIColor.clear] - } - return tabBarItemAppearance - }() - return tabBarAppearance - } -} diff --git a/TwidereSDK/Sources/TwidereCore/Service/ThemeService/Theme.swift b/TwidereSDK/Sources/TwidereCore/Service/ThemeService/Theme.swift new file mode 100644 index 00000000..a3d2d5da --- /dev/null +++ b/TwidereSDK/Sources/TwidereCore/Service/ThemeService/Theme.swift @@ -0,0 +1,77 @@ +// +// Theme.swift +// +// +// Created by MainasuK on 2023-09-19. +// + +import UIKit +import TwidereAsset +import Disk + +public struct Theme: Hashable { + public let identifier: Identifier + public let interfaceStyle: UIUserInterfaceStyle + public let background: UIColor + public let foreground: UIColor + public let comment: UIColor + public let commentDisabled: UIColor + public let highlight: UIColor + public let like: UIColor + public let repost: UIColor + public let bookmark: UIColor + public let line: UIColor +} + +extension Theme { + public var barBackgroundColor: UIColor? { + switch identifier { + case .system: return nil + default: return background.withAlphaComponent(0.8) + } + } +} + +extension Theme { + public enum Identifier: Hashable { + case system + case grandBudapestHotel + case custom(id: String) + } +} + +extension Theme { + static var system: Theme { + Theme( + identifier: .system, + interfaceStyle: .unspecified, + background: .systemBackground, + foreground: .label, + comment: .secondaryLabel, + commentDisabled: .systemGray, + highlight: .tintColor, + like: .systemRed, + repost: .systemBlue, + bookmark: .systemYellow, + line: .separator + ) + } + + static var grandBudapestHotel: Theme { + Theme( + identifier: .grandBudapestHotel, + interfaceStyle: .unspecified, + background: Asset.Theme.GrandBudapestHotel.background.color, + foreground: Asset.Theme.GrandBudapestHotel.foreground.color, + comment: Asset.Theme.GrandBudapestHotel.comment.color, + commentDisabled: Asset.Theme.GrandBudapestHotel.commentDisabled.color, + highlight: Asset.Theme.GrandBudapestHotel.highlight.color, + like: Asset.Theme.GrandBudapestHotel.like.color, + repost: Asset.Theme.GrandBudapestHotel.repost.color, + bookmark: Asset.Theme.GrandBudapestHotel.bookmark.color, + line: Asset.Theme.GrandBudapestHotel.line.color + ) + } +} + +extension UIUserInterfaceStyle: Codable { } diff --git a/TwidereSDK/Sources/TwidereCore/Service/ThemeService/ThemeService.swift b/TwidereSDK/Sources/TwidereCore/Service/ThemeService/ThemeService.swift new file mode 100644 index 00000000..5886d74c --- /dev/null +++ b/TwidereSDK/Sources/TwidereCore/Service/ThemeService/ThemeService.swift @@ -0,0 +1,39 @@ +// +// ThemeService.swift +// ThemeService +// +// Created by Cirno MainasuK on 2021-8-12. +// Copyright © 2021 Twidere. All rights reserved. +// + +import UIKit +import Combine +import TwidereCommon +import TwidereAsset + +public final class ThemeService: ObservableObject { + public static let shared = ThemeService() + + @Published public var theme: Theme + + private init() { + self.theme = .grandBudapestHotel + } + +} + +//extension Theme { +// public var accentColor: UIColor { +// switch self { +// case .daylight: return Asset.Colors.Theme.daylight.color +// case .maskBlue: return Asset.Colors.Theme.maskBlue.color +// case .violet: return Asset.Colors.Theme.violet.color +// case .grandBudapest: return Asset.Colors.Theme.grandBudapest.color +// case .vulcan: return Asset.Colors.Theme.vulcan.color +// case .goldenSpirit: return Asset.Colors.Theme.goldenSpirit.color +// case .lime: return Asset.Colors.Theme.lime.color +// case .seafoam: return Asset.Colors.Theme.seafoam.color +// } +// } +//} + diff --git a/TwidereSDK/Sources/TwidereCore/State/AppContext.swift b/TwidereSDK/Sources/TwidereCore/State/AppContext.swift index e00f3e62..6955ecf1 100644 --- a/TwidereSDK/Sources/TwidereCore/State/AppContext.swift +++ b/TwidereSDK/Sources/TwidereCore/State/AppContext.swift @@ -33,6 +33,8 @@ public class AppContext: ObservableObject { public let playerService = PlayerService() public let notificationService: NotificationService + + public let themeService = ThemeService.shared public init(appSecret: AppSecret) { let _coreDataStack = CoreDataStack() diff --git a/TwidereSDK/Sources/TwidereUI/Content/PollOptionView.swift b/TwidereSDK/Sources/TwidereUI/Content/PollOptionView.swift index d3af2b19..bf8ccf82 100644 --- a/TwidereSDK/Sources/TwidereUI/Content/PollOptionView.swift +++ b/TwidereSDK/Sources/TwidereUI/Content/PollOptionView.swift @@ -15,6 +15,8 @@ import CoreDataStack public struct PollOptionView: View { @ObservedObject public var viewModel: ViewModel + @ObservedObject public var themeService = ThemeService.shared + public let selectAction: (ViewModel) -> Void var bodyFont: UIFont { TextStyle.pollOptionTitle.font } @@ -27,7 +29,7 @@ public struct PollOptionView: View { var markView: some View { GeometryReader { proxy in - let tintColor = viewModel.canSelect ? Asset.Colors.hightLight.color : .systemBackground + let tintColor = viewModel.canSelect ? themeService.theme.highlight : themeService.theme.background let dimension = proxy.size.width CheckmarkView( tintColor: tintColor, @@ -61,6 +63,7 @@ public struct PollOptionView: View { metaContent: viewModel.content, textStyle: .pollOptionTitle, setupLabel: { label in + label.setupAttributes(foregroundColor: themeService.theme.foreground.withAlphaComponent(0.6)) label.setContentHuggingPriority(.required, for: .horizontal) label.setContentCompressionResistancePriority(.required, for: .horizontal) } @@ -72,7 +75,7 @@ public struct PollOptionView: View { // TODO: https://developer.apple.com/documentation/swiftui/view/scrollbouncebehavior(_:axes:)?changes=latest_minor Text(viewModel.percentageText) .font(Font(bodyFont)) - .foregroundColor(.secondary) + .foregroundColor(Color(uiColor: themeService.theme.foreground.withAlphaComponent(0.6))) .monospacedDigit() .padding(.horizontal, 6) .opacity(viewModel.isResultReveal ? 1 : 0) @@ -81,13 +84,13 @@ public struct PollOptionView: View { .background( GeometryReader { proxy in ZStack(alignment: .leading) { - Color(uiColor: Asset.Colors.hightLight.color.withAlphaComponent(0.15)) + Color(uiColor: themeService.theme.highlight.withAlphaComponent(0.15)) // note: // Use offset method to keep the perfect circle shape on edges. // So the edge of the bar with percenage likes 0.1 will display as circle // but not rounded square let alpha = viewModel.isOptionVoted ? 0.75 : 0.25 - let color = Asset.Colors.hightLight.color.withAlphaComponent(alpha) + let color = themeService.theme.highlight.withAlphaComponent(alpha) let offsetX = proxy.size.width * (1 - viewModel.percentage) Color(uiColor: color) .cornerRadius(rowCornerRadius) @@ -217,251 +220,3 @@ extension PollOptionView { } // end init } // end class } - - -//public protocol PollOptionViewDelegate: AnyObject { -// func pollOptionView(_ pollOptionView: PollOptionView, deleteBackwardResponseTextField textField: DeleteBackwardResponseTextField, textBeforeDelete: String?) -//} -// -//public final class PollOptionView: UIView { -// -// static let height: CGFloat = 36 -// -// public weak var delegate: PollOptionViewDelegate? -// private(set) var style: Style? -// -// var disposeBag = Set() -// public private(set) lazy var viewModel: ViewModel = { -// let viewModel = ViewModel() -// viewModel.bind(view: self) -// return viewModel -// }() -// -// let containerView = UIView() -// -// let stripProgressView = StripProgressView() -// -// let selectionImageView: UIImageView = { -// let imageView = UIImageView() -// return imageView -// }() -// -// public let titleMetaLabel = MetaLabel(style: .pollOptionTitle) -// -// public let percentageMetaLabel = MetaLabel(style: .pollOptionPercentage) -// -// // TODO: MetaTextField? -// public let textField: DeleteBackwardResponseTextField = { -// let textField = DeleteBackwardResponseTextField() -// textField.font = .systemFont(ofSize: 16, weight: .regular) -// textField.textColor = .label -// textField.text = "Choice" -// textField.textAlignment = UIApplication.shared.userInterfaceLayoutDirection == .leftToRight ? .left : .right -// return textField -// }() -// -// public func prepareForReuse() { -// viewModel.objects.removeAll() -// viewModel.percentage = nil -// stripProgressView.setProgress(0, animated: false) -// } -// -// public override init(frame: CGRect) { -// super.init(frame: frame) -// _init() -// } -// -// public required init?(coder: NSCoder) { -// super.init(coder: coder) -// _init() -// } -// -//} -// -//extension PollOptionView { -// -// private func _init() { -// textField.deleteBackwardDelegate = self -// -// // Accessibility -// // hint: Poll option -// accessibilityHint = L10n.Accessibility.Common.Status.pollOptionOrdinalPrefix -// } -// -// public override func layoutSubviews() { -// super.layoutSubviews() -// -// setupCorner() -// } -// -// func setupCorner() { -// switch viewModel.corner { -// case .none: -// containerView.layer.masksToBounds = false -// stripProgressView.cornerRadius = 0 -// case .radius(let radius): -// containerView.layer.masksToBounds = true -// guard radius < bounds.height / 2 else { -// fallthrough -// } -// containerView.layer.cornerCurve = .continuous -// containerView.layer.cornerRadius = radius -// stripProgressView.cornerRadius = radius -// case .circle: -// let radius = bounds.height / 2 -// containerView.layer.masksToBounds = true -// containerView.layer.cornerCurve = .circular -// containerView.layer.cornerRadius = radius -// stripProgressView.cornerRadius = radius -// } -// } -// -// public func setup(style: Style) { -// guard self.style == nil else { -// assertionFailure("Should only setup once") -// return -// } -// self.style = style -// self.viewModel.style = style -// style.layout(view: self) -// } -// -// public override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { -// super.traitCollectionDidChange(previousTraitCollection) -// -// if traitCollection.hasDifferentColorAppearance(comparedTo: previousTraitCollection) { -// textField.layer.borderColor = UIColor.secondaryLabel.cgColor -// } -// } -// -//} -// -//extension PollOptionView { -// public enum Style { -// case plain -// case edit -// -// func layout(view: PollOptionView) { -// switch self { -// case .plain: layoutPlain(view: view) -// case .edit: layoutEdit(view: view) -// } -// } -// } -//} -// -//extension PollOptionView.Style { -// private func layoutPlain(view: PollOptionView) { -// view.containerView.translatesAutoresizingMaskIntoConstraints = false -// view.addSubview(view.containerView) -// NSLayoutConstraint.activate([ -// view.containerView.topAnchor.constraint(equalTo: view.topAnchor), -// view.containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor), -// view.containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor), -// view.containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor), -// ]) -// view.containerView.backgroundColor = Asset.Colors.hightLight.color.withAlphaComponent(0.08) -// -// view.stripProgressView.translatesAutoresizingMaskIntoConstraints = false -// view.containerView.addSubview(view.stripProgressView) -// NSLayoutConstraint.activate([ -// view.stripProgressView.topAnchor.constraint(equalTo: view.containerView.topAnchor), -// view.stripProgressView.leadingAnchor.constraint(equalTo: view.containerView.leadingAnchor), -// view.stripProgressView.trailingAnchor.constraint(equalTo: view.containerView.trailingAnchor), -// view.stripProgressView.bottomAnchor.constraint(equalTo: view.containerView.bottomAnchor), -// ]) -// -// view.selectionImageView.translatesAutoresizingMaskIntoConstraints = false -// view.containerView.addSubview(view.selectionImageView) -// NSLayoutConstraint.activate([ -// view.selectionImageView.topAnchor.constraint(equalTo: view.containerView.topAnchor, constant: 6), -// view.selectionImageView.leadingAnchor.constraint(equalTo: view.containerView.leadingAnchor, constant: 6), -// view.containerView.bottomAnchor.constraint(equalTo: view.selectionImageView.bottomAnchor, constant: 6), -// view.selectionImageView.widthAnchor.constraint(equalToConstant: 24).priority(.required - 1), -// view.selectionImageView.heightAnchor.constraint(equalToConstant: 24).priority(.required - 1), -// ]) -// -// view.titleMetaLabel.translatesAutoresizingMaskIntoConstraints = false -// view.containerView.addSubview(view.titleMetaLabel) -// NSLayoutConstraint.activate([ -// view.titleMetaLabel.leadingAnchor.constraint(equalTo: view.selectionImageView.trailingAnchor, constant: 4), -// view.titleMetaLabel.centerYAnchor.constraint(equalTo: view.containerView.centerYAnchor), -// ]) -// view.titleMetaLabel.setContentHuggingPriority(.defaultLow - 10, for: .horizontal) -// -// view.percentageMetaLabel.translatesAutoresizingMaskIntoConstraints = false -// view.containerView.addSubview(view.percentageMetaLabel) -// NSLayoutConstraint.activate([ -// view.percentageMetaLabel.leadingAnchor.constraint(equalTo: view.titleMetaLabel.trailingAnchor, constant: 4), -// view.containerView.trailingAnchor.constraint(equalTo: view.percentageMetaLabel.trailingAnchor, constant: 8), -// view.percentageMetaLabel.centerYAnchor.constraint(equalTo: view.containerView.centerYAnchor), -// ]) -// view.percentageMetaLabel.setContentHuggingPriority(.required - 10, for: .horizontal) -// view.percentageMetaLabel.setContentCompressionResistancePriority(.required - 2, for: .horizontal) -// -// view.titleMetaLabel.isUserInteractionEnabled = false -// view.percentageMetaLabel.isUserInteractionEnabled = false -// } -// -// private func layoutEdit(view: PollOptionView) { -// view.containerView.translatesAutoresizingMaskIntoConstraints = false -// view.addSubview(view.containerView) -// NSLayoutConstraint.activate([ -// view.containerView.topAnchor.constraint(equalTo: view.topAnchor), -// view.containerView.leadingAnchor.constraint(equalTo: view.leadingAnchor), -// view.containerView.trailingAnchor.constraint(equalTo: view.trailingAnchor), -// view.containerView.bottomAnchor.constraint(equalTo: view.bottomAnchor), -// ]) -// -// view.textField.translatesAutoresizingMaskIntoConstraints = false -// view.containerView.addSubview(view.textField) -// NSLayoutConstraint.activate([ -// view.textField.topAnchor.constraint(equalTo: view.containerView.topAnchor), -// view.textField.leadingAnchor.constraint(equalTo: view.containerView.leadingAnchor), -// view.textField.trailingAnchor.constraint(equalTo: view.containerView.trailingAnchor), -// view.textField.bottomAnchor.constraint(equalTo: view.containerView.bottomAnchor), -// ]) -// -// view.containerView.layer.masksToBounds = true -// view.containerView.layer.cornerRadius = 6 -// view.containerView.layer.cornerCurve = .continuous -// view.containerView.layer.borderColor = UIColor.secondaryLabel.cgColor -// view.containerView.layer.borderWidth = UIView.separatorLineHeight(of: view) -// } -// -//} -// -//// MARK; - DeleteBackwardResponseTextFieldDelegate -//extension PollOptionView: DeleteBackwardResponseTextFieldDelegate { -// public func deleteBackwardResponseTextField(_ textField: DeleteBackwardResponseTextField, textBeforeDelete: String?) { -// delegate?.pollOptionView(self, deleteBackwardResponseTextField: textField, textBeforeDelete: textBeforeDelete) -// } -//} -// -//#if DEBUG -//import SwiftUI -//struct PollOptionView_Preview: PreviewProvider { -// static var previews: some View { -// Group { -// UIViewPreview(width: 400, height: 36) { -// let pollOptionView = PollOptionView() -// pollOptionView.setup(style: .edit) -// return pollOptionView -// } -// .frame(width: 400, height: 36) -// .padding(10) -// .previewLayout(.sizeThatFits) -// .previewDisplayName("Edit") -// UIViewPreview(width: 400, height: 36) { -// let pollOptionView = PollOptionView() -// pollOptionView.setup(style: .plain) -// return pollOptionView -// } -// .frame(width: 400, height: 36) -// .padding(10) -// .previewLayout(.sizeThatFits) -// .previewDisplayName("Plain") -// } -// } -//} -//#endif diff --git a/TwidereSDK/Sources/TwidereUI/Content/PollView.swift b/TwidereSDK/Sources/TwidereUI/Content/PollView.swift index 4675d57c..af3efb32 100644 --- a/TwidereSDK/Sources/TwidereUI/Content/PollView.swift +++ b/TwidereSDK/Sources/TwidereUI/Content/PollView.swift @@ -18,6 +18,8 @@ public struct PollView: View { var logger: Logger { PollView.logger } @ObservedObject public var viewModel: ViewModel + @ObservedObject public var themeService = ThemeService.shared + public let selectAction: (PollOptionView.ViewModel) -> Void public let voteAction: (ViewModel) -> Void @@ -28,54 +30,6 @@ public struct PollView: View { logger.log(level: .debug, "\((#file as NSString).lastPathComponent, privacy: .public)[\(#line, privacy: .public)], \(#function, privacy: .public): \(optionViewModel.index)") selectAction(optionViewModel) } -// VStack { -// HStack { -// Text(option.content) -// .font(.system(size: 16, weight: .regular)) -// .foregroundColor(Color(uiColor: Asset.Color.M3.Sys.onSurface.color)) -// Spacer() -// } -// HStack(alignment: .center) { -// GeometryReader { proxy in -// RoundedRectangle(cornerRadius: proxy.size.height / 2) -// .frame(width: proxy.size.width) -// .foregroundColor(Color(uiColor: Asset.Color.M3.Sys.surfaceVariant.color)) -// .overlay( -// HStack { -// let gradient = Gradient(stops: [ -// .init(color: Color(uiColor: UIColor(hex: 0xFF7575)), location: 0.0), -// .init(color: Color(uiColor: UIColor(hex: 0x8B54FF)), location: 1.0), -// ]) -// LinearGradient(gradient: gradient, startPoint: .leading, endPoint: .trailing) -// .foregroundColor(Color(uiColor: Asset.Color.Sys.primary.color)) -// .mask(alignment: .leading) { -// RoundedRectangle(cornerRadius: proxy.size.height / 2) -// .frame(width: proxy.size.width * (option.percentage ?? 0)) -// } -// } -// .frame(alignment: .leading) -// ) -// .clipShape( -// RoundedRectangle(cornerRadius: proxy.size.height / 2) -// ) -// } -// .frame(height: 12) -// Text("99.99%") // fixed width size -// .lineLimit(1) -// .font(.system(size: 14, weight: .regular)) -// .foregroundColor(.clear) -// .overlay( -// HStack(spacing: .zero) { -// Spacer() -// Text(option.percentageText) -// .lineLimit(1) -// .font(.system(size: 14, weight: .regular)) -// .foregroundColor(Color(uiColor: Asset.Color.secondary.color)) -// .fixedSize(horizontal: true, vertical: false) -// } -// ) -// } -// } } // end ForEach HStack { Text(verbatim: viewModel.pollDescription) @@ -89,7 +43,7 @@ public struct PollView: View { guard !viewModel.isVoting else { return } voteAction(viewModel) } label: { - let textColor = viewModel.isVoteButtonEnabled ? TextStyle.pollVoteButton.textColor : .secondaryLabel + let textColor = viewModel.isVoteButtonEnabled ? themeService.theme.highlight : themeService.theme.commentDisabled Text(L10n.Common.Controls.Status.Actions.vote) .font(Font(TextStyle.pollVoteButton.font)) .lineLimit(TextStyle.pollVoteButton.numberOfLines) diff --git a/TwidereSDK/Sources/TwidereUI/Content/StatusHeaderView.swift b/TwidereSDK/Sources/TwidereUI/Content/StatusHeaderView.swift index da5a30f0..bb6b7586 100644 --- a/TwidereSDK/Sources/TwidereUI/Content/StatusHeaderView.swift +++ b/TwidereSDK/Sources/TwidereUI/Content/StatusHeaderView.swift @@ -20,6 +20,7 @@ public struct StatusHeaderView: View { static var iconImageTrailingSpacing: CGFloat { 4.0 } @ObservedObject public var viewModel: ViewModel + @ObservedObject public var themeService = ThemeService.shared @ScaledMetric(relativeTo: .footnote) private var iconImageDimension: CGFloat = 16 @@ -34,21 +35,24 @@ public struct StatusHeaderView: View { .frame(width: max(.leastNonzeroMagnitude, width)) } // end if HStack(spacing: StatusHeaderView.iconImageTrailingSpacing) { - VectorImageView(image: viewModel.image) - .frame(width: iconImageDimension, height: iconImageDimension) - .offset(y: -1) + VectorImageView( + image: viewModel.image, + tintColor: themeService.theme.comment + ) + .frame(width: iconImageDimension, height: iconImageDimension) + .offset(y: -1) if viewModel.isLabelContainsMeta { LabelRepresentable( metaContent: viewModel.label, textStyle: .statusHeader, setupLabel: { label in - // do nothing + label.setupAttributes(foregroundColor: themeService.theme.comment) } ) } else { Text(viewModel.label.string) .font(Font(TextStyle.statusHeader.font)) - .foregroundColor(Color(uiColor: TextStyle.statusHeader.textColor)) + .foregroundColor(Color(uiColor: themeService.theme.comment)) .lineLimit(1) } Spacer() diff --git a/TwidereSDK/Sources/TwidereUI/Content/StatusToolbarView.swift b/TwidereSDK/Sources/TwidereUI/Content/StatusToolbarView.swift index 2398004c..7e4c9217 100644 --- a/TwidereSDK/Sources/TwidereUI/Content/StatusToolbarView.swift +++ b/TwidereSDK/Sources/TwidereUI/Content/StatusToolbarView.swift @@ -15,6 +15,8 @@ public struct StatusToolbarView: View { var logger: Logger { StatusView.logger } @ObservedObject public var viewModel: ViewModel + @ObservedObject public var themeService = ThemeService.shared + public var menuActions: [Action] public let handler: (Action) -> Void @@ -67,7 +69,7 @@ extension StatusToolbarView { action: .reply, image: viewModel.replyButtonImage, count: isMetricCountDisplay ? viewModel.replyCount : nil, - tintColor: nil + tintColor: themeService.theme.comment ) } @@ -114,7 +116,7 @@ extension StatusToolbarView { return viewModel.repostButtonImage(kind: kind) }(), count: isMetricCountDisplay ? viewModel.repostCount : nil, - tintColor: viewModel.isReposted ? Asset.Scene.Status.Toolbar.repost.color : nil + tintColor: viewModel.isReposted ? themeService.theme.repost : themeService.theme.comment ) .opacity(viewModel.isRepostable ? 1 : 0.5) } @@ -161,7 +163,7 @@ extension StatusToolbarView { action: .like, image: viewModel.isLiked ? viewModel.likeOnButtonImage : viewModel.likeOffButtonImage, count: isMetricCountDisplay ? viewModel.likeCount : nil, - tintColor: viewModel.isLiked ? Asset.Scene.Status.Toolbar.like.color : nil + tintColor: viewModel.isLiked ? themeService.theme.like : themeService.theme.comment ) } @@ -182,7 +184,7 @@ extension StatusToolbarView { } label: { HStack { Image(uiImage: viewModel.moreButtonImage) - .foregroundColor(.secondary) + .foregroundColor(Color(uiColor: themeService.theme.comment)) } } .buttonStyle(.borderless) diff --git a/TwidereSDK/Sources/TwidereUI/Content/StatusView+ViewModel.swift b/TwidereSDK/Sources/TwidereUI/Content/StatusView+ViewModel.swift index fc049e64..f4ac7a52 100644 --- a/TwidereSDK/Sources/TwidereUI/Content/StatusView+ViewModel.swift +++ b/TwidereSDK/Sources/TwidereUI/Content/StatusView+ViewModel.swift @@ -670,7 +670,8 @@ extension StatusView.ViewModel { let content = MastodonContent(content: spoilerText, emojis: status.emojisTransient.asDictionary) let metaContent = try MastodonMetaContent.convert(document: content, useParagraphMark: true) self.spoilerContent = metaContent - self.spoilerContentAttributedString = metaContent.attributedString(accentColor: .tintColor) + let accentColor = ThemeService.shared.theme.highlight + self.spoilerContentAttributedString = metaContent.attributedString(accentColor: accentColor) self.isSpoilerContentContainsMeta = !status.emojisTransient.isEmpty } catch { assertionFailure(error.localizedDescription) @@ -684,7 +685,8 @@ extension StatusView.ViewModel { let content = MastodonContent(content: status.content, emojis: status.emojisTransient.asDictionary) let metaContent = try MastodonMetaContent.convert(document: content, useParagraphMark: true) self.content = metaContent - self.contentAttributedString = metaContent.attributedString(accentColor: .tintColor) + let accentColor = ThemeService.shared.theme.highlight + self.contentAttributedString = metaContent.attributedString(accentColor: accentColor) self.isContentContainsMeta = !status.emojisTransient.isEmpty } catch { assertionFailure(error.localizedDescription) diff --git a/TwidereSDK/Sources/TwidereUI/Content/StatusView.swift b/TwidereSDK/Sources/TwidereUI/Content/StatusView.swift index cdad37a6..9c254d7f 100644 --- a/TwidereSDK/Sources/TwidereUI/Content/StatusView.swift +++ b/TwidereSDK/Sources/TwidereUI/Content/StatusView.swift @@ -65,6 +65,7 @@ public struct StatusView: View { static var hangingAvatarButtonTrailingSpacing: CGFloat { 10.0 } @ObservedObject public private(set) var viewModel: ViewModel + @ObservedObject public private(set) var themeService = ThemeService.shared @Environment(\.displayScale) var displayScale @Environment(\.dynamicTypeSize) var dynamicTypeSize @@ -136,7 +137,8 @@ public struct StatusView: View { } label: { HStack { Image(uiImage: Asset.Editing.ellipsisLarge.image.withRenderingMode(.alwaysTemplate)) - .background(Color(uiColor: .tertiarySystemFill)) + .foregroundStyle(Color(uiColor: themeService.theme.highlight)) + .background(Color(uiColor: themeService.theme.comment).opacity(0.5)) .clipShape(Capsule()) Spacer() } @@ -327,7 +329,7 @@ extension StatusView { if viewModel.protected { VectorImageView( image: Asset.ObjectTools.lockMini.image.withRenderingMode(.alwaysTemplate), - tintColor: .secondaryLabel + tintColor: themeService.theme.comment ) .frame(width: lockImageDimension, height: lockImageDimension) } @@ -340,7 +342,7 @@ extension StatusView { // username Text(verbatim: "@\(viewModel.authorUsernme)") .font(Font(TextStyle.statusAuthorUsername.font)) - .foregroundColor(Color(uiColor: TextStyle.statusAuthorUsername.textColor)) + .foregroundColor(Color(uiColor: themeService.theme.comment)) .lineLimit(1) Spacer() if !isAdaptiveLayout { @@ -364,6 +366,7 @@ extension StatusView { metaContent: viewModel.authorName, textStyle: .statusAuthorName, setupLabel: { label in + label.setupAttributes(foregroundColor: themeService.theme.foreground) label.setContentHuggingPriority(.defaultHigh, for: .horizontal) label.setContentHuggingPriority(.defaultHigh, for: .vertical) label.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) @@ -373,7 +376,7 @@ extension StatusView { } else { Text(verbatim: viewModel.authorName.string) .font(Font(TextStyle.statusAuthorName.font)) - .foregroundColor(Color(uiColor: TextStyle.statusAuthorName.textColor)) + .foregroundColor(Color(uiColor: themeService.theme.foreground)) .lineLimit(1) } } @@ -389,8 +392,11 @@ extension StatusView { var mastodonVisibilityIconView: some View { if let visibilityIconImage = viewModel.visibilityIconImage { let dimension = visibilityIconImageDimension - VectorImageView(image: visibilityIconImage, tintColor: TextStyle.statusTimestamp.textColor) - .frame(width: dimension, height: dimension) + VectorImageView( + image: visibilityIconImage, + tintColor: themeService.theme.commentDisabled + ) + .frame(width: dimension, height: dimension) } } @@ -440,6 +446,8 @@ extension StatusView { TextViewRepresentable( metaContent: viewModel.spoilerContent ?? PlaintextMetaContent(string: ""), textStyle: .statusContent, + textColor: themeService.theme.foreground, + tintColor: themeService.theme.highlight, isSelectable: viewModel.kind == .conversationRoot, handler: { meta in viewModel.delegate?.statusView(viewModel, textViewDidSelectMeta: meta) @@ -454,7 +462,7 @@ extension StatusView { Text(metaContent) .multilineTextAlignment(.leading) .font(Font(TextStyle.statusContent.font)) - .foregroundColor(Color(uiColor: TextStyle.statusContent.textColor)) + .foregroundColor(Color(uiColor: themeService.theme.foreground)) .frame(width: viewModel.contentWidth, alignment: .leading) } } @@ -465,6 +473,8 @@ extension StatusView { TextViewRepresentable( metaContent: viewModel.content, textStyle: .statusContent, + textColor: themeService.theme.foreground, + tintColor: themeService.theme.highlight, isSelectable: viewModel.kind == .conversationRoot, handler: { meta in viewModel.delegate?.statusView(viewModel, textViewDidSelectMeta: meta) @@ -478,7 +488,7 @@ extension StatusView { Text(viewModel.contentAttributedString) .multilineTextAlignment(.leading) .font(Font(TextStyle.statusContent.font)) - .foregroundColor(Color(uiColor: TextStyle.statusContent.textColor)) + .foregroundColor(Color(uiColor: themeService.theme.foreground)) .frame(width: viewModel.contentWidth, alignment: .leading) } } @@ -497,6 +507,7 @@ extension StatusView { } } + @ViewBuilder var toolbarView: some View { StatusToolbarView( viewModel: viewModel.toolbarViewModel, diff --git a/TwidereSDK/Sources/TwidereUI/Content/TimestampLabelView.swift b/TwidereSDK/Sources/TwidereUI/Content/TimestampLabelView.swift index b1b895d4..cce32439 100644 --- a/TwidereSDK/Sources/TwidereUI/Content/TimestampLabelView.swift +++ b/TwidereSDK/Sources/TwidereUI/Content/TimestampLabelView.swift @@ -14,6 +14,7 @@ import DateToolsSwift public struct TimestampLabelView: View { @ObservedObject public var viewModel: ViewModel + @ObservedObject public var themeService = ThemeService.shared public init(viewModel: TimestampLabelView.ViewModel) { self.viewModel = viewModel @@ -24,7 +25,7 @@ public struct TimestampLabelView: View { let timeAgo = viewModel.timeAgo(now: timeline.date) Text("\(timeAgo)") .font(Font(TextStyle.statusTimestamp.font).monospacedDigit()) - .foregroundColor(Color(uiColor: TextStyle.statusTimestamp.textColor)) + .foregroundColor(Color(uiColor: themeService.theme.commentDisabled)) } } } diff --git a/TwidereSDK/Sources/TwidereUI/Extension/UITabBarAppearance.swift b/TwidereSDK/Sources/TwidereUI/Extension/UITabBarAppearance.swift new file mode 100644 index 00000000..2a04c345 --- /dev/null +++ b/TwidereSDK/Sources/TwidereUI/Extension/UITabBarAppearance.swift @@ -0,0 +1,42 @@ +// +// UITabBarItemAppearance.swift +// +// +// Created by MainasuK on 2023-09-19. +// + +import UIKit + +extension UITabBarAppearance { + public static var defaultAppearance: UITabBarAppearance { + let theme = ThemeService.shared.theme + + let tabBarAppearance = UITabBarAppearance() + tabBarAppearance.configureWithDefaultBackground() + if let barBackgroundColor = theme.barBackgroundColor { + tabBarAppearance.backgroundColor = barBackgroundColor + } + tabBarAppearance.stackedLayoutAppearance = { + let tabBarItemAppearance = UITabBarItemAppearance() + tabBarItemAppearance.selected.iconColor = theme.highlight + tabBarItemAppearance.focused.iconColor = theme.highlight + tabBarItemAppearance.normal.iconColor = theme.comment + tabBarItemAppearance.disabled.iconColor = theme.commentDisabled + if !UserDefaults.shared.preferredTabBarLabelDisplay { + tabBarItemAppearance.selected.titleTextAttributes = [.foregroundColor: UIColor.clear] + tabBarItemAppearance.focused.titleTextAttributes = [.foregroundColor: UIColor.clear] + tabBarItemAppearance.normal.titleTextAttributes = [.foregroundColor: UIColor.clear] + tabBarItemAppearance.disabled.titleTextAttributes = [.foregroundColor: UIColor.clear] + } else { + tabBarItemAppearance.selected.titleTextAttributes = [.foregroundColor: theme.highlight] + tabBarItemAppearance.focused.titleTextAttributes = [.foregroundColor: theme.highlight] + tabBarItemAppearance.normal.titleTextAttributes = [.foregroundColor: theme.comment] + tabBarItemAppearance.disabled.titleTextAttributes = [.foregroundColor: theme.commentDisabled] + } + return tabBarItemAppearance + }() + + return tabBarAppearance + } +} + diff --git a/TwidereSDK/Sources/TwidereUI/Scene/ComposeContent/ComposeContentViewController.swift b/TwidereSDK/Sources/TwidereUI/Scene/ComposeContent/ComposeContentViewController.swift index 0867b372..45cd543c 100644 --- a/TwidereSDK/Sources/TwidereUI/Scene/ComposeContent/ComposeContentViewController.swift +++ b/TwidereSDK/Sources/TwidereUI/Scene/ComposeContent/ComposeContentViewController.swift @@ -57,7 +57,11 @@ extension ComposeContentViewController { public override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = .systemBackground + ThemeService.shared.$theme + .map { $0.background } + .assign(to: \.backgroundColor, on: view) + .store(in: &disposeBag) + viewModel.viewLayoutFrame.update(view: view) customEmojiPickerInputView.delegate = self @@ -80,6 +84,11 @@ extension ComposeContentViewController { ]) hostingViewController.didMove(toParent: self) + ThemeService.shared.$theme + .map { $0.background } + .assign(to: \.backgroundColor, on: hostingViewController.view) + .store(in: &disposeBag) + // mention - pick action viewModel.mentionPickPublisher .receive(on: DispatchQueue.main) diff --git a/TwidereSDK/Sources/TwidereUI/TableViewCell/Common/TableViewPlainCell.swift b/TwidereSDK/Sources/TwidereUI/TableViewCell/Common/TableViewPlainCell.swift index 736640df..497a67f3 100644 --- a/TwidereSDK/Sources/TwidereUI/TableViewCell/Common/TableViewPlainCell.swift +++ b/TwidereSDK/Sources/TwidereUI/TableViewCell/Common/TableViewPlainCell.swift @@ -7,11 +7,13 @@ // import UIKit +import Combine import MetaTextKit import MetaLabel public class TableViewPlainCell: UITableViewCell { + private var _disposeBag = Set() public var observations = Set() public let iconImageView: UIImageView = { @@ -99,6 +101,20 @@ public class TableViewPlainCell: UITableViewCell { accessoryImageView.isHidden = true primaryTextLabel.isUserInteractionEnabled = false + + // theme + ThemeService.shared.$theme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.setup(theme: theme) + } + .store(in: &_disposeBag) + } + + public func setup(theme: Theme) { + backgroundColor = theme.background + contentView.backgroundColor = theme.foreground.withAlphaComponent(0.04) } } diff --git a/TwidereSDK/Sources/TwidereUI/TableViewCell/Hashtag/HashtagTableViewCell.swift b/TwidereSDK/Sources/TwidereUI/TableViewCell/Hashtag/HashtagTableViewCell.swift index 508e4847..53ddb5ab 100644 --- a/TwidereSDK/Sources/TwidereUI/TableViewCell/Hashtag/HashtagTableViewCell.swift +++ b/TwidereSDK/Sources/TwidereUI/TableViewCell/Hashtag/HashtagTableViewCell.swift @@ -7,12 +7,15 @@ // import UIKit +import Combine import TwidereCore import MetaTextKit import MetaLabel final public class HashtagTableViewCell: UITableViewCell { - + + private var _disposeBag = Set() + let primaryLabel = MetaLabel(style: .hashtagTitle) let secondaryLabel = MetaLabel(style: .hashtagDescription) @@ -64,6 +67,11 @@ extension HashtagTableViewCell { primaryLabel.isUserInteractionEnabled = false secondaryLabel.isUserInteractionEnabled = false + + ThemeService.shared.$theme + .map { $0.background } + .assign(to: \.backgroundColor, on: self) + .store(in: &_disposeBag) } } diff --git a/TwidereSDK/Sources/TwidereUI/TableViewCell/Loader/TimelineBottomLoaderTableViewCell.swift b/TwidereSDK/Sources/TwidereUI/TableViewCell/Loader/TimelineBottomLoaderTableViewCell.swift index e394fdcd..03f720c9 100644 --- a/TwidereSDK/Sources/TwidereUI/TableViewCell/Loader/TimelineBottomLoaderTableViewCell.swift +++ b/TwidereSDK/Sources/TwidereUI/TableViewCell/Loader/TimelineBottomLoaderTableViewCell.swift @@ -19,6 +19,8 @@ public final class TimelineBottomLoaderTableViewCell: TimelineLoaderTableViewCel override func _init() { super._init() + backgroundColor = .clear + activityIndicatorView.isHidden = false activityIndicatorView.startAnimating() } diff --git a/TwidereSDK/Sources/TwidereUI/TableViewCell/Loader/TimelineMiddleLoaderTableViewCell.swift b/TwidereSDK/Sources/TwidereUI/TableViewCell/Loader/TimelineMiddleLoaderTableViewCell.swift index b1d49955..30c1b1c2 100644 --- a/TwidereSDK/Sources/TwidereUI/TableViewCell/Loader/TimelineMiddleLoaderTableViewCell.swift +++ b/TwidereSDK/Sources/TwidereUI/TableViewCell/Loader/TimelineMiddleLoaderTableViewCell.swift @@ -27,7 +27,7 @@ public final class TimelineMiddleLoaderTableViewCell: TimelineLoaderTableViewCel override func _init() { super._init() - backgroundColor = .secondarySystemBackground + backgroundColor = .clear let separatorLine = SeparatorLineView() separatorLine.translatesAutoresizingMaskIntoConstraints = false diff --git a/TwidereSDK/Sources/TwidereUI/TableViewCell/Notification/NotificationTableViewCell.swift b/TwidereSDK/Sources/TwidereUI/TableViewCell/Notification/NotificationTableViewCell.swift index d63abe9c..6069faf4 100644 --- a/TwidereSDK/Sources/TwidereUI/TableViewCell/Notification/NotificationTableViewCell.swift +++ b/TwidereSDK/Sources/TwidereUI/TableViewCell/Notification/NotificationTableViewCell.swift @@ -7,9 +7,12 @@ import os.log import UIKit +import Combine public final class NotificationTableViewCell: UITableViewCell { + var disposeBag = Set() + let logger = Logger(subsystem: "StatusTableViewCell", category: "View") public weak var statusViewTableViewCellDelegate: StatusViewTableViewCellDelegate? @@ -19,7 +22,6 @@ public final class NotificationTableViewCell: UITableViewCell { public override func prepareForReuse() { super.prepareForReuse() - contentConfiguration = nil statusViewTableViewCellDelegate = nil userViewTableViewCellDelegate = nil } @@ -40,6 +42,11 @@ extension NotificationTableViewCell { private func _init() { selectionStyle = .none + + ThemeService.shared.$theme + .map { $0.background } + .assign(to: \.backgroundColor, on: self) + .store(in: &disposeBag) } } diff --git a/TwidereSDK/Sources/TwidereUI/TableViewCell/Status/StatusTableViewCell.swift b/TwidereSDK/Sources/TwidereUI/TableViewCell/Status/StatusTableViewCell.swift index 04e19251..e95324d4 100644 --- a/TwidereSDK/Sources/TwidereUI/TableViewCell/Status/StatusTableViewCell.swift +++ b/TwidereSDK/Sources/TwidereUI/TableViewCell/Status/StatusTableViewCell.swift @@ -12,6 +12,8 @@ import Combine public class StatusTableViewCell: UITableViewCell { + var disposeBag = Set() + let logger = Logger(subsystem: "StatusTableViewCell", category: "View") public weak var statusViewTableViewCellDelegate: StatusViewTableViewCellDelegate? @@ -39,6 +41,11 @@ extension StatusTableViewCell { private func _init() { selectionStyle = .none + + ThemeService.shared.$theme + .map { $0.background } + .assign(to: \.backgroundColor, on: self) + .store(in: &disposeBag) } } diff --git a/TwidereSDK/Sources/TwidereUI/TableViewCell/User/UserTableViewCell.swift b/TwidereSDK/Sources/TwidereUI/TableViewCell/User/UserTableViewCell.swift index 83aeff8e..92680a05 100644 --- a/TwidereSDK/Sources/TwidereUI/TableViewCell/User/UserTableViewCell.swift +++ b/TwidereSDK/Sources/TwidereUI/TableViewCell/User/UserTableViewCell.swift @@ -9,10 +9,13 @@ import os.log import UIKit import Combine +import TwidereCore public class UserTableViewCell: UITableViewCell { let logger = Logger(subsystem: "UserTableViewCell", category: "View") + + private var _disposeBag = Set() public weak var userViewTableViewCellDelegate: UserViewTableViewCellDelegate? @@ -34,7 +37,10 @@ public class UserTableViewCell: UITableViewCell { } func _init() { - // selectionStyle = .none + ThemeService.shared.$theme + .map { $0.background } + .assign(to: \.backgroundColor, on: self) + .store(in: &_disposeBag) } } diff --git a/TwidereSDK/Sources/TwidereUI/UIViewRepresentable/TextViewRepresentable.swift b/TwidereSDK/Sources/TwidereUI/UIViewRepresentable/TextViewRepresentable.swift index 43d46029..bc4214ca 100644 --- a/TwidereSDK/Sources/TwidereUI/UIViewRepresentable/TextViewRepresentable.swift +++ b/TwidereSDK/Sources/TwidereUI/UIViewRepresentable/TextViewRepresentable.swift @@ -19,6 +19,8 @@ public struct TextViewRepresentable: UIViewRepresentable { // input let metaContent: MetaContent let textStyle: TextStyle + let textColor: UIColor + let tintColor: UIColor let isSelectable: Bool let handler: (Meta?) -> Void @@ -28,22 +30,26 @@ public struct TextViewRepresentable: UIViewRepresentable { public init( metaContent: MetaContent, textStyle: TextStyle, + textColor: UIColor, + tintColor: UIColor, isSelectable: Bool, handler: @escaping (Meta?) -> Void ) { self.metaContent = metaContent self.textStyle = textStyle + self.textColor = textColor + self.tintColor = tintColor self.isSelectable = isSelectable self.handler = handler self.attributedString = { let attributedString = NSMutableAttributedString(string: metaContent.string) let textAttributes: [NSAttributedString.Key: Any] = [ .font: textStyle.font, - .foregroundColor: textStyle.textColor, + .foregroundColor: textColor, ] let linkAttributes: [NSAttributedString.Key: Any] = [ .font: textStyle.font, - .foregroundColor: UIColor.tintColor, + .foregroundColor: tintColor, ] let paragraphStyle: NSMutableParagraphStyle = { let style = NSMutableParagraphStyle() diff --git a/TwidereX/Diffable/Misc/Notification/NotificationSection.swift b/TwidereX/Diffable/Misc/Notification/NotificationSection.swift index 5f628f26..a0454ec6 100644 --- a/TwidereX/Diffable/Misc/Notification/NotificationSection.swift +++ b/TwidereX/Diffable/Misc/Notification/NotificationSection.swift @@ -60,58 +60,16 @@ extension NotificationSection { } return cell - default: - return UITableViewCell() + case .feedLoader: + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineMiddleLoaderTableViewCell.self), for: indexPath) as! TimelineMiddleLoaderTableViewCell + cell.viewModel.isFetching = true + return cell + + case .bottomLoader: + let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell + cell.activityIndicatorView.startAnimating() + return cell } // end switch -// switch feed.objectContent { -// case .status: -// let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: StatusTableViewCell.self), for: indexPath) as! StatusTableViewCell -// StatusSection.setupStatusPollDataSource( -// context: context, -// statusView: cell.statusView, -// configurationContext: configuration.statusViewConfigurationContext -// ) -// configure( -// tableView: tableView, -// cell: cell, -// viewModel: StatusTableViewCell.ViewModel(value: .feed(feed)), -// configuration: configuration -// ) -// return cell -// case .notification(let object): -// switch object { -// case .mastodon(let notification): -// let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: UserNotificationStyleTableViewCell.self), for: indexPath) as! UserNotificationStyleTableViewCell -// let authenticationContext = configuration.statusViewConfigurationContext.authContext.authenticationContext -// let me = authenticationContext.user(in: context.managedObjectContext) -// let user: UserObject = .mastodon(object: notification.account) -// configure( -// cell: cell, -// viewModel: UserTableViewCell.ViewModel( -// user: user, -// me: me, -// notification: .mastodon(object: notification) -// ), -// configuration: configuration -// ) -// return cell -// } -// case .none: -// assertionFailure() -// return UITableViewCell() -// } -// } // end return context.managedObjectContext.performAndWait - -// case .feedLoader: -// let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineMiddleLoaderTableViewCell.self), for: indexPath) as! TimelineMiddleLoaderTableViewCell -// cell.viewModel.isFetching = true -// return cell -// -// case .bottomLoader: -// let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell -// cell.activityIndicatorView.startAnimating() -// return cell -// } // end switch } // end return } // end func diff --git a/TwidereX/Diffable/Misc/Search/SearchSection.swift b/TwidereX/Diffable/Misc/Search/SearchSection.swift index 315934d9..1b2eb166 100644 --- a/TwidereX/Diffable/Misc/Search/SearchSection.swift +++ b/TwidereX/Diffable/Misc/Search/SearchSection.swift @@ -42,6 +42,7 @@ extension SearchSection { guard let object = record.object(in: context.managedObjectContext) else { return } configure(cell: cell, object: object) } + cell.setup(theme: ThemeService.shared.theme) return cell case .trend(let object): let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TrendTableViewCell.self), for: indexPath) as! TrendTableViewCell @@ -52,6 +53,7 @@ extension SearchSection { cell.contentConfiguration = UIHostingConfiguration { TrendView(viewModel: trendViewModel) } + cell.setup(theme: ThemeService.shared.theme) return cell case .loader: let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self), for: indexPath) as! TimelineBottomLoaderTableViewCell @@ -93,35 +95,4 @@ extension SearchSection { cell.primaryTextLabel.configure(content: metaContent) } } - -// private static func configure( -// cell: TrendTableViewCell, -// object: TrendObject -// ) { -// switch object { -// case .twitter(let trend): -// let metaContent = Meta.convert(document: .plaintext(string: trend.name)) -// cell.primaryLabel.configure(content: metaContent) -// cell.accessoryType = .disclosureIndicator -// case .mastodon(let tag): -// let metaContent = Meta.convert(document: .plaintext(string: "#" + tag.name)) -// -// cell.primaryLabel.configure(content: metaContent) -// cell.secondaryLabel.text = L10n.Scene.Trends.accounts(tag.talkingPeopleCount ?? 0) -// cell.setSecondaryLabelDisplay() -// -// cell.supplementaryLabel.text = tag.history?.first?.uses ?? " " -// cell.setSupplementaryLabelDisplay() -// -// cell.lineChartView.data = (tag.history ?? []) -// .sorted(by: { $0.day < $1.day }) // latest last -// .map { entry in -// guard let point = Int(entry.accounts) else { -// return .zero -// } -// return CGFloat(point) -// } -// cell.setLineChartViewDisplay() -// } -// } } diff --git a/TwidereX/Generated/AutoGenerateTableViewDelegate.generated.swift b/TwidereX/Generated/AutoGenerateTableViewDelegate.generated.swift index 30985739..96bf487c 100644 --- a/TwidereX/Generated/AutoGenerateTableViewDelegate.generated.swift +++ b/TwidereX/Generated/AutoGenerateTableViewDelegate.generated.swift @@ -1,4 +1,4 @@ -// Generated using Sourcery 1.8.1 — https://github.com/krzysztofzablocki/Sourcery +// Generated using Sourcery 1.8.2 — https://github.com/krzysztofzablocki/Sourcery // DO NOT EDIT // sourcery:inline:FederatedTimelineViewController.AutoGenerateTableViewDelegate diff --git a/TwidereX/Scene/Account/List/AccountListViewController.swift b/TwidereX/Scene/Account/List/AccountListViewController.swift index b0e30dc4..3bb9588f 100644 --- a/TwidereX/Scene/Account/List/AccountListViewController.swift +++ b/TwidereX/Scene/Account/List/AccountListViewController.swift @@ -52,6 +52,11 @@ extension AccountListViewController { navigationItem.leftBarButtonItem = closeBarButtonItem navigationItem.rightBarButtonItem = addBarButtonItem + ThemeService.shared.$theme + .map { $0.background } + .assign(to: \.backgroundColor, on: tableView) + .store(in: &disposeBag) + tableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableView) NSLayoutConstraint.activate([ @@ -69,17 +74,6 @@ extension AccountListViewController { addBarButtonItem.target = self addBarButtonItem.action = #selector(AccountListViewController.addBarButtonItemPressed(_:)) - - ThemeService.shared.theme - .sink { [weak self] theme in - guard let self = self else { return } - self.update(theme: theme) - } - .store(in: &disposeBag) - } - - private func update(theme: Theme) { - addBarButtonItem.tintColor = theme.accentColor } } diff --git a/TwidereX/Scene/Compose/ComposeViewController.swift b/TwidereX/Scene/Compose/ComposeViewController.swift index c2be3a7f..44c0d780 100644 --- a/TwidereX/Scene/Compose/ComposeViewController.swift +++ b/TwidereX/Scene/Compose/ComposeViewController.swift @@ -43,7 +43,11 @@ extension ComposeViewController { override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = .systemBackground + ThemeService.shared.$theme + .map { $0.background } + .assign(to: \.backgroundColor, on: view) + .store(in: &disposeBag) + navigationItem.leftBarButtonItem = UIBarButtonItem(barButtonSystemItem: .close, target: self, action: #selector(ComposeViewController.closeBarButtonItemPressed(_:))) navigationItem.rightBarButtonItem = sendBarButtonItem diff --git a/TwidereX/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift b/TwidereX/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift index 4b58dc47..1cf88432 100644 --- a/TwidereX/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift +++ b/TwidereX/Scene/Notification/NotificationTimeline/NotificationTimelineViewController.swift @@ -83,6 +83,12 @@ extension NotificationTimelineViewController { self.viewModel.loadOldestStateMachine.enter(NotificationTimelineViewModel.LoadOldestState.Loading.self) } .store(in: &disposeBag) + + context.themeService.$theme + .map { $0.background } + .receive(on: DispatchQueue.main) + .assign(to: \.backgroundColor, on: tableView) + .store(in: &disposeBag) } override func viewWillAppear(_ animated: Bool) { diff --git a/TwidereX/Scene/Profile/Header/ProfileHeaderViewController.swift b/TwidereX/Scene/Profile/Header/ProfileHeaderViewController.swift index 9acad42e..a196a2e7 100644 --- a/TwidereX/Scene/Profile/Header/ProfileHeaderViewController.swift +++ b/TwidereX/Scene/Profile/Header/ProfileHeaderViewController.swift @@ -50,7 +50,10 @@ extension ProfileHeaderViewController { override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = .systemBackground + ThemeService.shared.$theme + .map { $0.background } + .assign(to: \.backgroundColor, on: view) + .store(in: &disposeBag) headerView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(headerView) diff --git a/TwidereX/Scene/Profile/Header/View/ProfileFieldContentView.swift b/TwidereX/Scene/Profile/Header/View/ProfileFieldContentView.swift index 4f503afe..7bc884f7 100644 --- a/TwidereX/Scene/Profile/Header/View/ProfileFieldContentView.swift +++ b/TwidereX/Scene/Profile/Header/View/ProfileFieldContentView.swift @@ -63,6 +63,8 @@ final class ProfileFieldContentView: UIView, UIContentView { extension ProfileFieldContentView { private func _init() { + backgroundColor = .clear + container.translatesAutoresizingMaskIntoConstraints = false addSubview(container) NSLayoutConstraint.activate([ diff --git a/TwidereX/Scene/Profile/Header/View/ProfileFieldListView.swift b/TwidereX/Scene/Profile/Header/View/ProfileFieldListView.swift index 0bbf2852..4c764557 100644 --- a/TwidereX/Scene/Profile/Header/View/ProfileFieldListView.swift +++ b/TwidereX/Scene/Profile/Header/View/ProfileFieldListView.swift @@ -8,6 +8,7 @@ import os.log import UIKit +import Combine import MetaTextKit import MetaLabel import Meta @@ -21,12 +22,15 @@ final class ProfileFieldListView: UIView { let logger = Logger(subsystem: "ProfileFieldListView", category: "View") weak var delegate: ProfileFieldListViewDelegate? + + private var disposeBag = Set() var collectionViewHeightLayoutConstraint: NSLayoutConstraint! var collectionViewHeightObservation: NSKeyValueObservation? let collectionView: UICollectionView = { var configuration = UICollectionLayoutListConfiguration(appearance: .plain) configuration.showsSeparators = false + configuration.backgroundColor = .clear let collectionViewLayout = UICollectionViewCompositionalLayout.list(using: configuration) let frame = CGRect(x: 0, y: 0, width: 100, height: 100) // required for AutoLayout let collectionView = UICollectionView(frame: frame, collectionViewLayout: collectionViewLayout) @@ -112,6 +116,11 @@ extension ProfileFieldListView { cell.delegate = self return cell } + + ThemeService.shared.$theme + .map { $0.background } + .assign(to: \.backgroundColor, on: collectionView) + .store(in: &disposeBag) } } diff --git a/TwidereX/Scene/Profile/Header/View/ProfileHeaderView.swift b/TwidereX/Scene/Profile/Header/View/ProfileHeaderView.swift index 19db8e54..0812cf64 100644 --- a/TwidereX/Scene/Profile/Header/View/ProfileHeaderView.swift +++ b/TwidereX/Scene/Profile/Header/View/ProfileHeaderView.swift @@ -111,6 +111,11 @@ final class ProfileHeaderView: UIView { extension ProfileHeaderView { private func _init() { + ThemeService.shared.$theme + .map { $0.background } + .assign(to: \.backgroundColor, on: self) + .store(in: &disposeBag) + bannerContainer.translatesAutoresizingMaskIntoConstraints = false addSubview(bannerContainer) NSLayoutConstraint.activate([ diff --git a/TwidereX/Scene/Profile/ProfileViewController.swift b/TwidereX/Scene/Profile/ProfileViewController.swift index 381c674a..831b032e 100644 --- a/TwidereX/Scene/Profile/ProfileViewController.swift +++ b/TwidereX/Scene/Profile/ProfileViewController.swift @@ -66,7 +66,7 @@ final class ProfileViewController: UIViewController, NeedsDependency, DrawerSide private lazy var floatyButton: Floaty = { let button = Floaty() button.plusColor = .white - button.buttonColor = ThemeService.shared.theme.value.accentColor + button.buttonColor = Asset.Colors.Theme.daylight.color button.buttonImage = Asset.Arrows.arrowshapeTurnUpLeftFill.image.withTintColor(.white) button.handleFirstItemDirectly = true @@ -97,7 +97,15 @@ extension ProfileViewController { drawerSidebarTransitionController = DrawerSidebarTransitionController(hostViewController: self) - view.backgroundColor = .systemBackground + ThemeService.shared.$theme + .map { $0.background } + .assign(to: \.backgroundColor, on: view) + .store(in: &disposeBag) + + ThemeService.shared.$theme + .map { $0.highlight } + .assign(to: \.buttonColor, on: floatyButton) + .store(in: &disposeBag) if navigationController?.viewControllers.first == self { coordinator.$needsSetupAvatarBarButtonItem diff --git a/TwidereX/Scene/Profile/Segmented/Paging/ProfilePagingViewController.swift b/TwidereX/Scene/Profile/Segmented/Paging/ProfilePagingViewController.swift index dcf12fd9..3adf8018 100644 --- a/TwidereX/Scene/Profile/Segmented/Paging/ProfilePagingViewController.swift +++ b/TwidereX/Scene/Profile/Segmented/Paging/ProfilePagingViewController.swift @@ -62,11 +62,11 @@ extension ProfilePagingViewController { override func viewDidLoad() { // configure style before viewDidLoad - settings.style.buttonBarBackgroundColor = .systemBackground - settings.style.buttonBarItemBackgroundColor = .systemBackground + settings.style.buttonBarBackgroundColor = .clear + settings.style.buttonBarItemBackgroundColor = .clear settings.style.buttonBarItemsShouldFillAvailableWidth = true settings.style.selectedBarHeight = 3 - settings.style.selectedBarBackgroundColor = Asset.Colors.hightLight.color + settings.style.selectedBarBackgroundColor = .red changeCurrentIndexProgressive = { [weak self] (oldCell: ButtonBarViewCell?, newCell: ButtonBarViewCell?, progressPercentage: CGFloat, changeCurrentIndex: Bool, animated: Bool) -> Void in guard let _ = self else { return } guard changeCurrentIndex == true else { return } @@ -74,10 +74,25 @@ extension ProfilePagingViewController { newCell?.imageView.contentMode = .center oldCell?.imageView.tintColor = .secondaryLabel - newCell?.imageView.tintColor = Asset.Colors.hightLight.color + newCell?.imageView.tintColor = ThemeService.shared.theme.highlight } super.viewDidLoad() + + ThemeService.shared.$theme + .map { $0.highlight } + .assign(to: \.settings.style.selectedBarBackgroundColor, on: self) + .store(in: &disposeBag) + + let separatorLine = SeparatorLineView() + separatorLine.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(separatorLine) + NSLayoutConstraint.activate([ + separatorLine.leadingAnchor.constraint(equalTo: buttonBarView.frameLayoutGuide.leadingAnchor), + separatorLine.trailingAnchor.constraint(equalTo: buttonBarView.frameLayoutGuide.trailingAnchor), + separatorLine.bottomAnchor.constraint(equalTo: buttonBarView.frameLayoutGuide.bottomAnchor), + separatorLine.heightAnchor.constraint(equalToConstant: UIView.separatorLineHeight(of: buttonBarView)).priority(.required - 1), + ]) } } diff --git a/TwidereX/Scene/Root/Drawer/DrawerSidebarViewController.swift b/TwidereX/Scene/Root/Drawer/DrawerSidebarViewController.swift index e4712687..6a4d1f93 100644 --- a/TwidereX/Scene/Root/Drawer/DrawerSidebarViewController.swift +++ b/TwidereX/Scene/Root/Drawer/DrawerSidebarViewController.swift @@ -55,7 +55,10 @@ extension DrawerSidebarViewController { override func viewDidLoad() { super.viewDidLoad() - view.backgroundColor = .systemBackground + ThemeService.shared.$theme + .map { $0.background } + .assign(to: \.backgroundColor, on: view) + .store(in: &disposeBag) headerView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(headerView) diff --git a/TwidereX/Scene/Root/Drawer/DrawerSidebarViewModel+Diffable.swift b/TwidereX/Scene/Root/Drawer/DrawerSidebarViewModel+Diffable.swift index 2735ec1a..65038d1c 100644 --- a/TwidereX/Scene/Root/Drawer/DrawerSidebarViewModel+Diffable.swift +++ b/TwidereX/Scene/Root/Drawer/DrawerSidebarViewModel+Diffable.swift @@ -83,7 +83,7 @@ extension DrawerSidebarViewModel { return .clear } if state.isSelected || state.isHighlighted { - return Asset.Colors.hightLight.color + return ThemeService.shared.theme.highlight } else { return tintColor } @@ -117,7 +117,7 @@ extension DrawerSidebarViewModel { return .clear } if state.isSelected || state.isHighlighted { - return Asset.Scene.Sidebar.entryCellHighlightedBackground.color + return ThemeService.shared.theme.highlight.withAlphaComponent(0.2) } else { return .clear } diff --git a/TwidereX/Scene/Root/Drawer/View/DrawerSidebarHeaderView.swift b/TwidereX/Scene/Root/Drawer/View/DrawerSidebarHeaderView.swift index cc29906d..21125d23 100644 --- a/TwidereX/Scene/Root/Drawer/View/DrawerSidebarHeaderView.swift +++ b/TwidereX/Scene/Root/Drawer/View/DrawerSidebarHeaderView.swift @@ -66,7 +66,7 @@ final class DrawerSidebarHeaderView: UIView { let menuButton: UIButton = { let button = UIButton() button.setImage(UIImage(systemName: "ellipsis.circle"), for: .normal) - button.tintColor = Asset.Colors.hightLight.color + button.tintColor = ThemeService.shared.theme.highlight return button }() diff --git a/TwidereX/Scene/Root/MainTab/MainTabBarController.swift b/TwidereX/Scene/Root/MainTab/MainTabBarController.swift index ef878254..76533b98 100644 --- a/TwidereX/Scene/Root/MainTab/MainTabBarController.swift +++ b/TwidereX/Scene/Root/MainTab/MainTabBarController.swift @@ -106,13 +106,16 @@ extension MainTabBarController { // TabBarItem appearance configureTabBarItemAppearance() - UserDefaults.shared.publisher(for: \.preferredTabBarLabelDisplay) - .receive(on: DispatchQueue.main) - .sink { [weak self] preferredTabBarLabelDisplay in - guard let self = self else { return } - self.configureTabBarItemAppearance() - } - .store(in: &disposeBag) + Publishers.CombineLatest( + UserDefaults.shared.publisher(for: \.preferredTabBarLabelDisplay), + ThemeService.shared.$theme + ) + .receive(on: DispatchQueue.main) + .sink { [weak self] _, _ in + guard let self = self else { return } + self.configureTabBarItemAppearance() + } + .store(in: &disposeBag) // TabBar tap gesture doubleTapGestureRecognizer.addTarget(self, action: #selector(MainTabBarController.doubleTapGestureRecognizerHandler(_:))) @@ -228,7 +231,7 @@ extension MainTabBarController { item.imageInsets = preferredTabBarLabelDisplay ? .zero : UIEdgeInsets(top: 6, left: 0, bottom: -6, right: 0) } - let tabBarAppearance = ThemeService.setupTabBarAppearance() + let tabBarAppearance: UITabBarAppearance = .defaultAppearance tabBar.standardAppearance = tabBarAppearance tabBar.scrollEdgeAppearance = tabBarAppearance } diff --git a/TwidereX/Scene/Search/Search/Cell/TrendTableViewCell.swift b/TwidereX/Scene/Search/Search/Cell/TrendTableViewCell.swift index 988919cb..3a625b4c 100644 --- a/TwidereX/Scene/Search/Search/Cell/TrendTableViewCell.swift +++ b/TwidereX/Scene/Search/Search/Cell/TrendTableViewCell.swift @@ -7,42 +7,16 @@ // import UIKit -import MetaTextKit -import MetaLabel -import TwidereCore +import Combine final class TrendTableViewCell: UITableViewCell { -// let container: UIStackView = { -// let stackView = UIStackView() -// stackView.axis = .horizontal -// stackView.spacing = 16 -// return stackView -// }() -// -// let infoContainer: UIStackView = { -// let stackView = UIStackView() -// stackView.axis = .vertical -// return stackView -// }() -// -// let lineChartContainer: UIStackView = { -// let stackView = UIStackView() -// stackView.axis = .vertical -// return stackView -// }() -// -// let primaryLabel = MetaLabel(style: .searchTrendTitle) -// let secondaryLabel = PlainLabel(style: .searchTrendSubtitle) -// let supplementaryLabel = PlainLabel(style: .searchTrendCount) -// let lineChartView = LineChartView() + private var _disposeBag = Set() override func prepareForReuse() { super.prepareForReuse() contentConfiguration = nil -// accessoryType = .none -// resetDisplay() } override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { @@ -60,72 +34,19 @@ final class TrendTableViewCell: UITableViewCell { extension TrendTableViewCell { private func _init() { -// container.translatesAutoresizingMaskIntoConstraints = false -// contentView.addSubview(container) -// NSLayoutConstraint.activate([ -// container.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 11), -// container.leadingAnchor.constraint(equalTo: contentView.readableContentGuide.leadingAnchor), -// container.trailingAnchor.constraint(equalTo: contentView.readableContentGuide.trailingAnchor), -// contentView.bottomAnchor.constraint(equalTo: container.bottomAnchor, constant: 11), -// ]) -// -// // container: H - [ info container | padding | supplementary | line chart container ] -// container.addArrangedSubview(infoContainer) -// -// // info container: V - [ primary | secondary ] -// infoContainer.addArrangedSubview(primaryLabel) -// infoContainer.addArrangedSubview(secondaryLabel) -// -// // padding -// let padding = UIView() -// container.addArrangedSubview(padding) -// -// // supplementary -// container.addArrangedSubview(supplementaryLabel) -// supplementaryLabel.setContentHuggingPriority(.required - 1, for: .horizontal) -// -// // line chart -// container.addArrangedSubview(lineChartContainer) -// -// let lineChartViewTopPadding = UIView() -// let lineChartViewBottomPadding = UIView() -// lineChartViewTopPadding.translatesAutoresizingMaskIntoConstraints = false -// lineChartViewBottomPadding.translatesAutoresizingMaskIntoConstraints = false -// lineChartView.translatesAutoresizingMaskIntoConstraints = false -// lineChartContainer.addArrangedSubview(lineChartViewTopPadding) -// lineChartContainer.addArrangedSubview(lineChartView) -// lineChartContainer.addArrangedSubview(lineChartViewBottomPadding) -// NSLayoutConstraint.activate([ -// lineChartView.widthAnchor.constraint(equalToConstant: 66), -// lineChartView.heightAnchor.constraint(equalToConstant: 27), -// lineChartViewTopPadding.heightAnchor.constraint(equalTo: lineChartViewBottomPadding.heightAnchor), -// ]) -// -// primaryLabel.isUserInteractionEnabled = false -// -// resetDisplay() + // theme + ThemeService.shared.$theme + .receive(on: DispatchQueue.main) + .sink { [weak self] theme in + guard let self = self else { return } + self.setup(theme: theme) + } + .store(in: &_disposeBag) + } + + func setup(theme: Theme) { + backgroundColor = theme.background + contentView.backgroundColor = theme.foreground.withAlphaComponent(0.04) } } - -//extension TrendTableViewCell { -// -// func resetDisplay() { -// secondaryLabel.isHidden = true -// supplementaryLabel.isHidden = true -// lineChartContainer.isHidden = true -// } -// -// func setSecondaryLabelDisplay() { -// secondaryLabel.isHidden = false -// } -// -// func setSupplementaryLabelDisplay() { -// supplementaryLabel.isHidden = false -// } -// -// func setLineChartViewDisplay() { -// lineChartContainer.isHidden = false -// } -// -//} diff --git a/TwidereX/Scene/Search/Search/SearchViewController.swift b/TwidereX/Scene/Search/Search/SearchViewController.swift index 30c52b4a..4508e9b7 100644 --- a/TwidereX/Scene/Search/Search/SearchViewController.swift +++ b/TwidereX/Scene/Search/Search/SearchViewController.swift @@ -114,6 +114,12 @@ extension SearchViewController { tableView: tableView ) + context.themeService.$theme + .map { $0.background } + .receive(on: DispatchQueue.main) + .assign(to: \.backgroundColor, on: tableView) + .store(in: &disposeBag) + // bind trend section titile viewModel.trendViewModel.$trendPlaceName .receive(on: DispatchQueue.main) diff --git a/TwidereX/Scene/Search/SearchResult/Hashtag/SearchHashtagViewController.swift b/TwidereX/Scene/Search/SearchResult/Hashtag/SearchHashtagViewController.swift index 6ced7f76..8c798781 100644 --- a/TwidereX/Scene/Search/SearchResult/Hashtag/SearchHashtagViewController.swift +++ b/TwidereX/Scene/Search/SearchResult/Hashtag/SearchHashtagViewController.swift @@ -39,6 +39,12 @@ extension SearchHashtagViewController { view.backgroundColor = .systemBackground + context.themeService.$theme + .map { $0.background } + .receive(on: DispatchQueue.main) + .assign(to: \.backgroundColor, on: tableView) + .store(in: &disposeBag) + tableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableView) NSLayoutConstraint.activate([ diff --git a/TwidereX/Scene/Search/SearchResult/User/SearchUserViewController.swift b/TwidereX/Scene/Search/SearchResult/User/SearchUserViewController.swift index 995d0530..b9474ac3 100644 --- a/TwidereX/Scene/Search/SearchResult/User/SearchUserViewController.swift +++ b/TwidereX/Scene/Search/SearchResult/User/SearchUserViewController.swift @@ -26,8 +26,6 @@ final class SearchUserViewController: UIViewController, NeedsDependency { lazy var tableView: UITableView = { let tableView = UITableView() -// tableView.register(UserRelationshipStyleTableViewCell.self, forCellReuseIdentifier: String(describing: UserRelationshipStyleTableViewCell.self)) -// tableView.register(TimelineBottomLoaderTableViewCell.self, forCellReuseIdentifier: String(describing: TimelineBottomLoaderTableViewCell.self)) tableView.rowHeight = UITableView.automaticDimension tableView.separatorStyle = .none return tableView @@ -43,6 +41,12 @@ extension SearchUserViewController { override func viewDidLoad() { super.viewDidLoad() + + context.themeService.$theme + .map { $0.background } + .receive(on: DispatchQueue.main) + .assign(to: \.backgroundColor, on: tableView) + .store(in: &disposeBag) tableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableView) diff --git a/TwidereX/Scene/Share/View/CollectionViewCell/ActivityIndicatorCollectionViewCell.swift b/TwidereX/Scene/Share/View/CollectionViewCell/ActivityIndicatorCollectionViewCell.swift index 1fc22693..6fa0c49d 100644 --- a/TwidereX/Scene/Share/View/CollectionViewCell/ActivityIndicatorCollectionViewCell.swift +++ b/TwidereX/Scene/Share/View/CollectionViewCell/ActivityIndicatorCollectionViewCell.swift @@ -27,6 +27,8 @@ final class ActivityIndicatorCollectionViewCell: UICollectionViewCell { extension ActivityIndicatorCollectionViewCell { private func _init() { + backgroundColor = .clear + activityIndicatorView.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(activityIndicatorView) NSLayoutConstraint.activate([ diff --git a/TwidereX/Scene/Share/View/CollectionViewCell/StatusMediaGalleryCollectionCell.swift b/TwidereX/Scene/Share/View/CollectionViewCell/StatusMediaGalleryCollectionCell.swift index cee5be77..0231a6b6 100644 --- a/TwidereX/Scene/Share/View/CollectionViewCell/StatusMediaGalleryCollectionCell.swift +++ b/TwidereX/Scene/Share/View/CollectionViewCell/StatusMediaGalleryCollectionCell.swift @@ -13,12 +13,13 @@ import CoverFlowStackCollectionViewLayout protocol StatusMediaGalleryCollectionCellDelegate: AnyObject { func statusMediaGalleryCollectionCell(_ cell: StatusMediaGalleryCollectionCell, mediaStackContainerViewModel: MediaStackContainerView.ViewModel, didSelectMediaView mediaViewModel: MediaView.ViewModel) - // func statusMediaGalleryCollectionCell(_ cell: StatusMediaGalleryCollectionCell, toggleContentWarningOverlayViewDisplay contentWarningOverlayView: ContentWarningOverlayView) } final class StatusMediaGalleryCollectionCell: UICollectionViewCell { let logger = Logger(subsystem: "StatusMediaGalleryCollectionCell", category: "Cell") + + private var _disposeBag = Set() weak var delegate: StatusMediaGalleryCollectionCellDelegate? @@ -43,8 +44,11 @@ final class StatusMediaGalleryCollectionCell: UICollectionViewCell { extension StatusMediaGalleryCollectionCell { - private func _init() { - // nothing + private func _init() { + ThemeService.shared.$theme + .map { $0.background } + .assign(to: \.backgroundColor, on: self) + .store(in: &_disposeBag) } } diff --git a/TwidereX/Scene/Share/View/TableViewCell/ButtonTableViewCell.swift b/TwidereX/Scene/Share/View/TableViewCell/ButtonTableViewCell.swift index 483b5dc9..f583eb89 100644 --- a/TwidereX/Scene/Share/View/TableViewCell/ButtonTableViewCell.swift +++ b/TwidereX/Scene/Share/View/TableViewCell/ButtonTableViewCell.swift @@ -29,6 +29,8 @@ final class ButtonTableViewCell: UITableViewCell { extension ButtonTableViewCell { private func _init() { + backgroundColor = .clear + button.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(button) NSLayoutConstraint.activate([ diff --git a/TwidereX/Scene/Share/View/TableViewCell/CenterFootnoteLabelTableViewCell.swift b/TwidereX/Scene/Share/View/TableViewCell/CenterFootnoteLabelTableViewCell.swift index b88df070..81072308 100644 --- a/TwidereX/Scene/Share/View/TableViewCell/CenterFootnoteLabelTableViewCell.swift +++ b/TwidereX/Scene/Share/View/TableViewCell/CenterFootnoteLabelTableViewCell.swift @@ -34,6 +34,8 @@ final class CenterFootnoteLabelTableViewCell: UITableViewCell { extension CenterFootnoteLabelTableViewCell { private func _init() { + backgroundColor = .clear + label.translatesAutoresizingMaskIntoConstraints = false contentView.addSubview(label) NSLayoutConstraint.activate([ diff --git a/TwidereX/Scene/StatusThread/StatusThreadViewController.swift b/TwidereX/Scene/StatusThread/StatusThreadViewController.swift index f09dfa88..0939339f 100644 --- a/TwidereX/Scene/StatusThread/StatusThreadViewController.swift +++ b/TwidereX/Scene/StatusThread/StatusThreadViewController.swift @@ -48,6 +48,12 @@ extension StatusThreadViewController { view.backgroundColor = .systemBackground viewModel.viewLayoutFrame.update(view: view) + context.themeService.$theme + .map { $0.background } + .receive(on: DispatchQueue.main) + .assign(to: \.backgroundColor, on: tableView) + .store(in: &disposeBag) + tableView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(tableView) NSLayoutConstraint.activate([ diff --git a/TwidereX/Scene/Timeline/Base/Common/TimelineViewController.swift b/TwidereX/Scene/Timeline/Base/Common/TimelineViewController.swift index c903f944..01fc4aad 100644 --- a/TwidereX/Scene/Timeline/Base/Common/TimelineViewController.swift +++ b/TwidereX/Scene/Timeline/Base/Common/TimelineViewController.swift @@ -48,7 +48,7 @@ class TimelineViewController: UIViewController, NeedsDependency, DrawerSidebarTr private lazy var floatyButton: Floaty = { let button = Floaty() button.plusColor = .white - button.buttonColor = ThemeService.shared.theme.value.accentColor + button.buttonColor = ThemeService.shared.theme.highlight button.buttonImage = Asset.Editing.featherPen.image button.handleFirstItemDirectly = true @@ -80,6 +80,11 @@ extension TimelineViewController { drawerSidebarTransitionController = DrawerSidebarTransitionController(hostViewController: self) view.backgroundColor = .systemBackground + + ThemeService.shared.$theme + .map { $0.highlight } + .assign(to: \.buttonColor, on: floatyButton) + .store(in: &disposeBag) // setup avatarBarButtonItem if navigationController?.viewControllers.first == self { diff --git a/TwidereX/Scene/Timeline/Base/Grid/GridTimelineViewController.swift b/TwidereX/Scene/Timeline/Base/Grid/GridTimelineViewController.swift index ac78564c..c087a293 100644 --- a/TwidereX/Scene/Timeline/Base/Grid/GridTimelineViewController.swift +++ b/TwidereX/Scene/Timeline/Base/Grid/GridTimelineViewController.swift @@ -84,6 +84,12 @@ extension GridTimelineViewController { override func viewDidLoad() { super.viewDidLoad() + context.themeService.$theme + .map { $0.background } + .receive(on: DispatchQueue.main) + .assign(to: \.backgroundColor, on: collectionView) + .store(in: &disposeBag) + collectionView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(collectionView) NSLayoutConstraint.activate([ diff --git a/TwidereX/Scene/Timeline/Base/List/ListTimelineViewController.swift b/TwidereX/Scene/Timeline/Base/List/ListTimelineViewController.swift index 248ce72e..4af9abba 100644 --- a/TwidereX/Scene/Timeline/Base/List/ListTimelineViewController.swift +++ b/TwidereX/Scene/Timeline/Base/List/ListTimelineViewController.swift @@ -60,6 +60,12 @@ extension ListTimelineViewController { ]) tableView.delegate = self + context.themeService.$theme + .map { $0.background } + .receive(on: DispatchQueue.main) + .assign(to: \.backgroundColor, on: tableView) + .store(in: &disposeBag) + // setup refresh control viewModel.$isRefreshControlEnabled .receive(on: DispatchQueue.main) diff --git a/TwidereX/Supporting Files/AppDelegate.swift b/TwidereX/Supporting Files/AppDelegate.swift index 22aa3428..d4c6e646 100644 --- a/TwidereX/Supporting Files/AppDelegate.swift +++ b/TwidereX/Supporting Files/AppDelegate.swift @@ -59,8 +59,15 @@ class AppDelegate: UIResponder, UIApplicationDelegate { Floaty.global.rtlMode = UIApplication.shared.userInterfaceLayoutDirection == .rightToLeft // configure appearance - ThemeService.shared.apply(theme: ThemeService.shared.theme.value) - + setupAppearance(theme: ThemeService.shared.theme) + ThemeService.shared.$theme + .dropFirst() + .sink { [weak self] theme in + guard let self = self else { return } + self.setupAppearance(theme: theme) + } + .store(in: &disposeBag) + return true } @@ -96,6 +103,27 @@ extension AppDelegate { } } + +extension AppDelegate { + private func setupAppearance(theme: Theme) { + // set navigation bar appearance + let appearance = UINavigationBarAppearance() + appearance.configureWithDefaultBackground() + if let barBackgroundColor = theme.barBackgroundColor { + appearance.backgroundColor = barBackgroundColor + } + UINavigationBar.appearance().standardAppearance = appearance + UINavigationBar.appearance().compactAppearance = appearance + UINavigationBar.appearance().scrollEdgeAppearance = appearance + UINavigationBar.appearance().compactScrollEdgeAppearance = appearance + + // set tab bar appearance + let tabBarAppearance: UITabBarAppearance = .defaultAppearance + UITabBar.appearance().standardAppearance = tabBarAppearance + UITabBar.appearance().scrollEdgeAppearance = tabBarAppearance + } +} + // MARK: - UNUserNotificationCenterDelegate extension AppDelegate: UNUserNotificationCenterDelegate { diff --git a/TwidereX/Supporting Files/SceneDelegate.swift b/TwidereX/Supporting Files/SceneDelegate.swift index e39aa675..8b6df86f 100644 --- a/TwidereX/Supporting Files/SceneDelegate.swift +++ b/TwidereX/Supporting Files/SceneDelegate.swift @@ -40,22 +40,8 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { #endif // set tint color - window.tintColor = ThemeService.shared.theme.value.accentColor - - ThemeService.shared.theme - .receive(on: DispatchQueue.main) - .dropFirst() - .sink { [weak self] theme in - guard let self = self else { return } - guard let window = self.window else { return } - window.tintColor = theme.accentColor - window.subviews.forEach { view in - view.removeFromSuperview() - window.addSubview(view) - } - } - .store(in: &disposeBag) - + window.tintColor = Asset.Colors.Theme.daylight.color + let sceneCoordinator = SceneCoordinator(scene: scene, sceneDelegate: self, context: AppContext.shared) self.coordinator = sceneCoordinator