feat: add theme

This commit is contained in:
CMK 2021-07-05 16:07:17 +08:00
parent cdc3bc344a
commit d03d39a14d
99 changed files with 1683 additions and 162 deletions

View File

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="18154" systemVersion="20E241" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="18154" systemVersion="20F71" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
<entity name="Application" representedClassName=".Application" syncable="YES">
<attribute name="identifier" optional="YES" attributeType="UUID" usesScalarValueType="NO"/>
<attribute name="name" attributeType="String"/>
@ -189,6 +189,7 @@
<attribute name="appearanceRaw" attributeType="String"/>
<attribute name="createdAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="domain" attributeType="String"/>
<attribute name="preferredTrueBlackDarkMode" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
<attribute name="updatedAt" attributeType="Date" usesScalarValueType="NO"/>
<attribute name="userID" attributeType="String"/>
<relationship name="subscriptions" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="Subscription" inverseName="setting" inverseEntity="Subscription"/>
@ -280,7 +281,7 @@
<element name="PollOption" positionX="0" positionY="0" width="128" height="134"/>
<element name="PrivateNote" positionX="0" positionY="0" width="128" height="89"/>
<element name="SearchHistory" positionX="0" positionY="0" width="128" height="104"/>
<element name="Setting" positionX="72" positionY="162" width="128" height="119"/>
<element name="Setting" positionX="72" positionY="162" width="128" height="134"/>
<element name="Status" positionX="0" positionY="0" width="128" height="599"/>
<element name="Subscription" positionX="81" positionY="171" width="128" height="179"/>
<element name="SubscriptionAlerts" positionX="72" positionY="162" width="128" height="14"/>

View File

@ -11,6 +11,7 @@ import Foundation
public final class Setting: NSManagedObject {
@NSManaged public var appearanceRaw: String
@NSManaged public var preferredTrueBlackDarkMode: Bool
@NSManaged public var domain: String
@NSManaged public var userID: String
@ -47,6 +48,12 @@ extension Setting {
self.appearanceRaw = appearanceRaw
didUpdate(at: Date())
}
public func update(preferredTrueBlackDarkMode: Bool) {
guard preferredTrueBlackDarkMode != self.preferredTrueBlackDarkMode else { return }
self.preferredTrueBlackDarkMode = preferredTrueBlackDarkMode
didUpdate(at: Date())
}
public func didUpdate(at networkDate: Date) {
self.updatedAt = networkDate

View File

@ -518,6 +518,11 @@
"light": "Always Light",
"dark": "Always Dark"
},
"appearance_settings": {
"dark_mode": {
"title": "True black Dark Mode"
}
},
"notifications": {
"title": "Notifications",
"favorites": "Favorites my post",

View File

@ -487,6 +487,12 @@
DBCC3B9526157E6E0045B23D /* APIService+Relationship.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCC3B9426157E6E0045B23D /* APIService+Relationship.swift */; };
DBCC3B9B261584A00045B23D /* PrivateNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCC3B9A2615849F0045B23D /* PrivateNote.swift */; };
DBCCC71E25F73297007E1AB6 /* APIService+Reblog.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBCCC71D25F73297007E1AB6 /* APIService+Reblog.swift */; };
DBD376A72692EA00007FEC24 /* ThemeService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD376A62692EA00007FEC24 /* ThemeService.swift */; };
DBD376AA2692EA4F007FEC24 /* Theme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD376A92692EA4F007FEC24 /* Theme.swift */; };
DBD376AC2692ECDB007FEC24 /* ThemePreference.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD376AB2692ECDB007FEC24 /* ThemePreference.swift */; };
DBD376AE2692EE0A007FEC24 /* MastodonTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD376AD2692EE0A007FEC24 /* MastodonTheme.swift */; };
DBD376B02692F20F007FEC24 /* SystemTheme.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD376AF2692F20F007FEC24 /* SystemTheme.swift */; };
DBD376B2269302A4007FEC24 /* UITableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD376B1269302A4007FEC24 /* UITableViewCell.swift */; };
DBD9149025DF6D8D00903DFD /* APIService+Onboarding.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBD9148F25DF6D8D00903DFD /* APIService+Onboarding.swift */; };
DBE0821525CD382600FD6BBD /* MastodonRegisterViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE0821425CD382600FD6BBD /* MastodonRegisterViewController.swift */; };
DBE0822425CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DBE0822325CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift */; };
@ -1102,6 +1108,12 @@
DBCC3B9426157E6E0045B23D /* APIService+Relationship.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Relationship.swift"; sourceTree = "<group>"; };
DBCC3B9A2615849F0045B23D /* PrivateNote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivateNote.swift; sourceTree = "<group>"; };
DBCCC71D25F73297007E1AB6 /* APIService+Reblog.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Reblog.swift"; sourceTree = "<group>"; };
DBD376A62692EA00007FEC24 /* ThemeService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeService.swift; sourceTree = "<group>"; };
DBD376A92692EA4F007FEC24 /* Theme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Theme.swift; sourceTree = "<group>"; };
DBD376AB2692ECDB007FEC24 /* ThemePreference.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemePreference.swift; sourceTree = "<group>"; };
DBD376AD2692EE0A007FEC24 /* MastodonTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonTheme.swift; sourceTree = "<group>"; };
DBD376AF2692F20F007FEC24 /* SystemTheme.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SystemTheme.swift; sourceTree = "<group>"; };
DBD376B1269302A4007FEC24 /* UITableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UITableViewCell.swift; sourceTree = "<group>"; };
DBD9148F25DF6D8D00903DFD /* APIService+Onboarding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "APIService+Onboarding.swift"; sourceTree = "<group>"; };
DBE0821425CD382600FD6BBD /* MastodonRegisterViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterViewController.swift; sourceTree = "<group>"; };
DBE0822325CD3F1E00FD6BBD /* MastodonRegisterViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonRegisterViewModel.swift; sourceTree = "<group>"; };
@ -1453,6 +1465,7 @@
children = (
DB45FB0425CA87B4005A8AC7 /* APIService */,
DB49A61925FF327D00B98345 /* EmojiService */,
DBD376A82692EA3F007FEC24 /* ThemeService */,
DB9A489B26036E19008B817C /* MastodonAttachmentService */,
DB45FB0E25CA87D0005A8AC7 /* AuthenticationService.swift */,
DB4563BC25E11A24004DA0B9 /* KeyboardResponderService.swift */,
@ -1969,6 +1982,7 @@
DBE54AC52636C89F004E7C0B /* NotificationPreference.swift */,
DB1D842F26566512000346B3 /* KeyboardPreference.swift */,
DBCBCC0C2680B908000F5B51 /* HomeTimelinePreference.swift */,
DBD376AB2692ECDB007FEC24 /* ThemePreference.swift */,
);
path = Preference;
sourceTree = "<group>";
@ -2284,6 +2298,7 @@
2D42FF8E25C8228A004A627A /* UIButton.swift */,
DB45FAD625CA6C76005A8AC7 /* UIBarButtonItem.swift */,
DB4481B825EE289600BEFB67 /* UITableView.swift */,
DBD376B1269302A4007FEC24 /* UITableViewCell.swift */,
0FAA101B25E10E760017CCDE /* UIFont.swift */,
2D939AB425EDD8A90076FA61 /* String.swift */,
2D206B7F25F5F45E00143C56 /* UIImage.swift */,
@ -2593,6 +2608,17 @@
path = FetchedResultsController;
sourceTree = "<group>";
};
DBD376A82692EA3F007FEC24 /* ThemeService */ = {
isa = PBXGroup;
children = (
DBD376A62692EA00007FEC24 /* ThemeService.swift */,
DBD376A92692EA4F007FEC24 /* Theme.swift */,
DBD376AD2692EE0A007FEC24 /* MastodonTheme.swift */,
DBD376AF2692F20F007FEC24 /* SystemTheme.swift */,
);
path = ThemeService;
sourceTree = "<group>";
};
DBE0821A25CD382900FD6BBD /* Register */ = {
isa = PBXGroup;
children = (
@ -3170,6 +3196,7 @@
DB1FD45A25F27898004CFCFC /* CategoryPickerItem.swift in Sources */,
DB6180F626391D580018D199 /* MediaPreviewableViewController.swift in Sources */,
2D571B2F26004EC000540450 /* NavigationBarProgressView.swift in Sources */,
DBD376AA2692EA4F007FEC24 /* Theme.swift in Sources */,
0FAA101225E105390017CCDE /* PrimaryActionButton.swift in Sources */,
DB8AF53025C13561002E6C99 /* AppContext.swift in Sources */,
DB92CF7225E7BB98002C1017 /* PollOptionTableViewCell.swift in Sources */,
@ -3430,6 +3457,7 @@
DB447691260B406600B66B82 /* CustomEmojiPickerItemCollectionViewCell.swift in Sources */,
DB9282B225F3222800823B15 /* PickServerEmptyStateView.swift in Sources */,
DB1FD45025F26FA1004CFCFC /* MastodonPickServerViewModel+Diffable.swift in Sources */,
DBD376AC2692ECDB007FEC24 /* ThemePreference.swift in Sources */,
DB2B3AE925E38850007045F9 /* UIViewPreview.swift in Sources */,
DB68046C2636DC9E00430867 /* MastodonNotification.swift in Sources */,
DBAE3F9E2616E308004B8251 /* APIService+Mute.swift in Sources */,
@ -3475,6 +3503,7 @@
5DFC35DF262068D20045711D /* SearchViewController+Follow.swift in Sources */,
DB8AF52E25C13561002E6C99 /* ViewStateStore.swift in Sources */,
2DA7D04A25CA52CB00804E11 /* TimelineBottomLoaderTableViewCell.swift in Sources */,
DBD376B2269302A4007FEC24 /* UITableViewCell.swift in Sources */,
DBAC6499267DF2C4007FE9FD /* TimelineBottomLoaderNode.swift in Sources */,
2D76318325C14E8F00929FB9 /* PublicTimelineViewModel+Diffable.swift in Sources */,
DBBF1DBF2652401B00E5B703 /* AutoCompleteViewModel.swift in Sources */,
@ -3510,9 +3539,12 @@
DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */,
0FB3D30825E524C600AAD544 /* PickServerCategoriesCell.swift in Sources */,
2D4AD8A226316CD200613EFC /* SelectedAccountSection.swift in Sources */,
DBD376A72692EA00007FEC24 /* ThemeService.swift in Sources */,
DBD376AE2692EE0A007FEC24 /* MastodonTheme.swift in Sources */,
DB789A1225F9F2CC0071ACA0 /* ComposeViewModel.swift in Sources */,
DBB525362611ECEB002F1F29 /* UserTimelineViewController.swift in Sources */,
DB6D1B3D2636857500ACB481 /* AppearancePreference.swift in Sources */,
DBD376B02692F20F007FEC24 /* SystemTheme.swift in Sources */,
DB938F3326243D6200E5B6C1 /* TimelineTopLoaderTableViewCell.swift in Sources */,
DB3667A4268AE2370027D07F /* ComposeStatusPollTableViewCell.swift in Sources */,
DBBF1DC226524D2900E5B703 /* AutoCompleteTableViewCell.swift in Sources */,

View File

@ -12,7 +12,7 @@
<key>CoreDataStack.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>19</integer>
<integer>27</integer>
</dict>
<key>Mastodon - ASDK.xcscheme_^#shared#^_</key>
<dict>
@ -37,7 +37,7 @@
<key>NotificationService.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>18</integer>
<integer>26</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>

View File

@ -280,6 +280,7 @@ private extension SceneCoordinator {
return nil
}
let _viewController = SFSafariViewController(url: url)
_viewController.preferredBarTintColor = ThemeService.shared.currentTheme.value.navigationBarBackgroundColor
_viewController.preferredControlTintColor = Asset.Colors.brandBlue.color
viewController = _viewController

View File

@ -10,7 +10,7 @@ import CoreData
/// Note: update Equatable when change case
enum PollItem {
case opion(objectID: NSManagedObjectID, attribute: Attribute)
case option(objectID: NSManagedObjectID, attribute: Attribute)
}
@ -51,7 +51,7 @@ extension PollItem {
extension PollItem: Equatable {
static func == (lhs: PollItem, rhs: PollItem) -> Bool {
switch (lhs, rhs) {
case (.opion(let objectIDLeft, _), .opion(let objectIDRight, _)):
case (.option(let objectIDLeft, _), .option(let objectIDRight, _)):
return objectIDLeft == objectIDRight
}
}
@ -61,7 +61,7 @@ extension PollItem: Equatable {
extension PollItem: Hashable {
func hash(into hasher: inout Hasher) {
switch self {
case .opion(let objectID, _):
case .option(let objectID, _):
hasher.combine(objectID)
}
}

View File

@ -10,6 +10,7 @@ import CoreData
enum SettingsItem: Hashable {
case appearance(settingObjectID: NSManagedObjectID)
case appearanceDarkMode(settingObjectID: NSManagedObjectID)
case notification(settingObjectID: NSManagedObjectID, switchMode: NotificationSwitchMode)
case boringZone(item: Link)
case spicyZone(item: Link)

View File

@ -32,7 +32,7 @@ extension PollSection {
) -> UITableViewDiffableDataSource<PollSection, PollItem> {
return UITableViewDiffableDataSource<PollSection, PollItem>(tableView: tableView) { tableView, indexPath, item -> UITableViewCell? in
switch item {
case .opion(let objectID, let attribute):
case .option(let objectID, let attribute):
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: PollOptionTableViewCell.self), for: indexPath) as! PollOptionTableViewCell
managedObjectContext.performAndWait {
let option = managedObjectContext.object(with: objectID) as! PollOption
@ -67,13 +67,25 @@ extension PollSection {
cell.pollOptionView.checkmarkBackgroundView.isHidden = true
cell.pollOptionView.checkmarkImageView.isHidden = true
case .off:
cell.pollOptionView.checkmarkBackgroundView.backgroundColor = Asset.Colors.Background.tertiarySystemBackground.color
cell.pollOptionView.checkmarkBackgroundView.layer.borderColor = Asset.Colors.Background.Cell.highlight.color.withAlphaComponent(0.3).cgColor
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak cell] theme in
guard let cell = cell else { return }
cell.pollOptionView.checkmarkBackgroundView.backgroundColor = theme.tertiarySystemBackgroundColor
cell.pollOptionView.checkmarkBackgroundView.layer.borderColor = theme.tableViewCellSelectionBackgroundColor.withAlphaComponent(0.3).cgColor
}
.store(in: &cell.disposeBag)
cell.pollOptionView.checkmarkBackgroundView.layer.borderWidth = 1
cell.pollOptionView.checkmarkBackgroundView.isHidden = false
cell.pollOptionView.checkmarkImageView.isHidden = true
case .on:
cell.pollOptionView.checkmarkBackgroundView.backgroundColor = Asset.Colors.Background.tertiarySystemBackground.color
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak cell] theme in
guard let cell = cell else { return }
cell.pollOptionView.checkmarkBackgroundView.backgroundColor = theme.tertiarySystemBackgroundColor
}
.store(in: &cell.disposeBag)
cell.pollOptionView.checkmarkBackgroundView.layer.borderColor = UIColor.clear.cgColor
cell.pollOptionView.checkmarkBackgroundView.layer.borderWidth = 0
cell.pollOptionView.checkmarkBackgroundView.isHidden = false

View File

@ -9,16 +9,18 @@ import Foundation
enum SettingsSection: Hashable {
case appearance
case appearanceSettings
case notifications
case boringZone
case spicyZone
var title: String {
switch self {
case .appearance: return L10n.Scene.Settings.Section.Appearance.title
case .notifications: return L10n.Scene.Settings.Section.Notifications.title
case .boringZone: return L10n.Scene.Settings.Section.Boringzone.title
case .spicyZone: return L10n.Scene.Settings.Section.Spicyzone.title
case .appearance: return L10n.Scene.Settings.Section.Appearance.title
case .appearanceSettings: return ""
case .notifications: return L10n.Scene.Settings.Section.Notifications.title
case .boringZone: return L10n.Scene.Settings.Section.Boringzone.title
case .spicyZone: return L10n.Scene.Settings.Section.Spicyzone.title
}
}
}

View File

@ -913,7 +913,7 @@ extension StatusSection {
}()
return PollItem.Attribute(selectState: selectState, voteState: voteState)
}()
let option = PollItem.opion(objectID: option.objectID, attribute: attribute)
let option = PollItem.option(objectID: option.objectID, attribute: attribute)
return option
}
snapshot.appendItems(pollItems, toSection: .main)

View File

@ -0,0 +1,22 @@
//
// UITableViewCell.swift
// Mastodon
//
// Created by MainasuK Cirno on 2021-7-5.
//
import UIKit
extension UITableViewCell {
/// The color of the cell when it is selected.
@objc dynamic var selectionColor: UIColor? {
get { return selectedBackgroundView?.backgroundColor }
set {
guard selectionStyle != .none else { return }
let view = UIView()
view.backgroundColor = newValue
selectedBackgroundView = view
}
}
}

View File

@ -14,7 +14,7 @@ extension UIView {
UIColor(dynamicProvider: { collection in
switch collection.userInterfaceStyle {
case .dark:
return Asset.Colors.Background.Cell.separator.color
return ThemeService.shared.currentTheme.value.separator
default:
return .separator
}

View File

@ -32,15 +32,10 @@ internal enum Asset {
}
internal enum Colors {
internal enum Background {
internal enum Cell {
internal static let highlight = ColorAsset(name: "Colors/Background/Cell/highlight")
internal static let separator = ColorAsset(name: "Colors/Background/Cell/separator")
}
internal enum Poll {
internal static let disabled = ColorAsset(name: "Colors/Background/Poll/disabled")
}
internal static let alertYellow = ColorAsset(name: "Colors/Background/alert.yellow")
internal static let bar = ColorAsset(name: "Colors/Background/bar")
internal static let dangerBorder = ColorAsset(name: "Colors/Background/danger.border")
internal static let danger = ColorAsset(name: "Colors/Background/danger")
internal static let mediaTypeIndicotor = ColorAsset(name: "Colors/Background/media.type.indicotor")
@ -64,9 +59,6 @@ internal enum Asset {
internal static let disabled = ColorAsset(name: "Colors/Button/disabled")
internal static let inactive = ColorAsset(name: "Colors/Button/inactive")
}
internal enum ContentWarningOverlay {
internal static let background = ColorAsset(name: "Colors/ContentWarningOverlay/background")
}
internal enum Icon {
internal static let plus = ColorAsset(name: "Colors/Icon/plus")
}
@ -141,6 +133,42 @@ internal enum Asset {
internal static let appearanceDark = ImageAsset(name: "Settings/appearance.dark")
internal static let appearanceLight = ImageAsset(name: "Settings/appearance.light")
}
internal enum Theme {
internal enum Mastodon {
internal static let contentWarningOverlayBackground = ColorAsset(name: "Theme/Mastodon/content.warning.overlay.background")
internal static let navigationBarBackground = ColorAsset(name: "Theme/Mastodon/navigation.bar.background")
internal static let profileFieldCollectionViewBackground = ColorAsset(name: "Theme/Mastodon/profile.field.collection.view.background")
internal static let secondaryGroupedSystemBackground = ColorAsset(name: "Theme/Mastodon/secondary.grouped.system.background")
internal static let secondarySystemBackground = ColorAsset(name: "Theme/Mastodon/secondary.system.background")
internal static let systemBackground = ColorAsset(name: "Theme/Mastodon/system.background")
internal static let systemElevatedBackground = ColorAsset(name: "Theme/Mastodon/system.elevated.background")
internal static let systemGroupedBackground = ColorAsset(name: "Theme/Mastodon/system.grouped.background")
internal static let tabBarBackground = ColorAsset(name: "Theme/Mastodon/tab.bar.background")
internal static let tableViewCellBackground = ColorAsset(name: "Theme/Mastodon/table.view.cell.background")
internal static let tableViewCellSelectionBackground = ColorAsset(name: "Theme/Mastodon/table.view.cell.selection.background")
internal static let tertiarySystemBackground = ColorAsset(name: "Theme/Mastodon/tertiary.system.background")
internal static let tertiarySystemGroupedBackground = ColorAsset(name: "Theme/Mastodon/tertiary.system.grouped.background")
internal static let separator = ColorAsset(name: "Theme/Mastodon/separator")
internal static let tabBarItemInactiveIconColor = ColorAsset(name: "Theme/Mastodon/tab.bar.item.inactive.icon.color")
}
internal enum System {
internal static let contentWarningOverlayBackground = ColorAsset(name: "Theme/System/content.warning.overlay.background")
internal static let navigationBarBackground = ColorAsset(name: "Theme/System/navigation.bar.background")
internal static let profileFieldCollectionViewBackground = ColorAsset(name: "Theme/System/profile.field.collection.view.background")
internal static let secondaryGroupedSystemBackground = ColorAsset(name: "Theme/System/secondary.grouped.system.background")
internal static let secondarySystemBackground = ColorAsset(name: "Theme/System/secondary.system.background")
internal static let systemBackground = ColorAsset(name: "Theme/System/system.background")
internal static let systemElevatedBackground = ColorAsset(name: "Theme/System/system.elevated.background")
internal static let systemGroupedBackground = ColorAsset(name: "Theme/System/system.grouped.background")
internal static let tabBarBackground = ColorAsset(name: "Theme/System/tab.bar.background")
internal static let tableViewCellBackground = ColorAsset(name: "Theme/System/table.view.cell.background")
internal static let tableViewCellSelectionBackground = ColorAsset(name: "Theme/System/table.view.cell.selection.background")
internal static let tertiarySystemBackground = ColorAsset(name: "Theme/System/tertiary.system.background")
internal static let tertiarySystemGroupedBackground = ColorAsset(name: "Theme/System/tertiary.system.grouped.background")
internal static let separator = ColorAsset(name: "Theme/System/separator")
internal static let tabBarItemInactiveIconColor = ColorAsset(name: "Theme/System/tab.bar.item.inactive.icon.color")
}
}
}
// swiftlint:enable identifier_name line_length nesting type_body_length type_name

View File

@ -965,6 +965,12 @@ internal enum L10n {
/// Appearance
internal static let title = L10n.tr("Localizable", "Scene.Settings.Section.Appearance.Title")
}
internal enum AppearanceSettings {
internal enum DarkMode {
/// True black Dark Mode
internal static let title = L10n.tr("Localizable", "Scene.Settings.Section.AppearanceSettings.DarkMode.Title")
}
}
internal enum Boringzone {
/// Privacy Policy
internal static let privacy = L10n.tr("Localizable", "Scene.Settings.Section.Boringzone.Privacy")

View File

@ -0,0 +1,20 @@
//
// ThemePreference.swift
// Mastodon
//
// Created by MainasuK Cirno on 2021-7-5.
//
import UIKit
extension UserDefaults {
@objc dynamic var currentThemeNameRawValue: String {
get {
register(defaults: [#function: ThemeName.mastodon.rawValue])
return string(forKey: #function) ?? ThemeName.mastodon.rawValue
}
set { self[#function] = newValue }
}
}

View File

@ -137,7 +137,7 @@ extension StatusTableViewCellDelegate where Self: StatusProvider {
guard let diffableDataSource = cell.statusView.pollTableViewDataSource else { return }
let item = diffableDataSource.itemIdentifier(for: indexPath)
guard case let .opion(objectID, _) = item else { return }
guard case let .option(objectID, _) = item else { return }
guard let option = managedObjectContext.object(with: objectID) as? PollOption else { return }
let poll = option.poll

View File

@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "0.300",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
"blue" : "60",
"green" : "60",
"red" : "60"
}
},
"idiom" : "universal"

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.922",
"green" : "0.898",
"red" : "0.867"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.263",
"green" : "0.208",
"red" : "0.192"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.940",
"blue" : "0.976",
"green" : "0.976",
"red" : "0.976"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "67",
"green" : "53",
"red" : "49"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.996",
"green" : "1.000",
"red" : "0.996"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.263",
"green" : "0.208",
"red" : "0.192"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.910",
"green" : "0.882",
"red" : "0.851"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.133",
"green" : "0.106",
"red" : "0.098"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.996",
"green" : "1.000",
"red" : "0.996"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.216",
"green" : "0.173",
"red" : "0.157"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "235",
"green" : "229",
"red" : "221"
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
@ -23,9 +23,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0x43",
"green" : "0x35",
"red" : "0x31"
"blue" : "55",
"green" : "44",
"red" : "40"
}
},
"idiom" : "universal"

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.910",
"green" : "0.882",
"red" : "0.851"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.133",
"green" : "0.106",
"red" : "0.098"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "0.940",
"blue" : "249",
"green" : "249",
"red" : "249"
"blue" : "0.976",
"green" : "0.976",
"red" : "0.976"
}
},
"idiom" : "universal"

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.263",
"green" : "0.208",
"red" : "0.192"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -5,9 +5,9 @@
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "214",
"green" : "209",
"red" : "209"
"blue" : "235",
"green" : "229",
"red" : "221"
}
},
"idiom" : "universal"

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.996",
"green" : "1.000",
"red" : "0.996"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.216",
"green" : "0.173",
"red" : "0.157"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.910",
"green" : "0.882",
"red" : "0.851"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.263",
"green" : "0.208",
"red" : "0.192"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.549",
"green" : "0.510",
"red" : "0.431"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "200",
"green" : "174",
"red" : "155"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.922",
"green" : "0.898",
"red" : "0.867"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.263",
"green" : "0.208",
"red" : "0.192"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.940",
"blue" : "249",
"green" : "249",
"red" : "249"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.940",
"blue" : "29",
"green" : "29",
"red" : "29"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "30",
"green" : "28",
"red" : "28"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.996",
"green" : "1.000",
"red" : "0.996"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "46",
"green" : "44",
"red" : "44"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.910",
"green" : "0.882",
"red" : "0.851"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "46",
"green" : "44",
"red" : "44"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.996",
"green" : "1.000",
"red" : "0.996"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.000",
"green" : "0.000",
"red" : "0.000"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.118",
"green" : "0.110",
"red" : "0.110"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.910",
"green" : "0.882",
"red" : "0.851"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.000",
"green" : "0.000",
"red" : "0.000"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.940",
"blue" : "0.976",
"green" : "0.976",
"red" : "0.976"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.940",
"blue" : "0.114",
"green" : "0.114",
"red" : "0.114"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "1.000",
"green" : "1.000",
"red" : "1.000"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0",
"green" : "0",
"red" : "0"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.922",
"green" : "0.898",
"red" : "0.867"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "60",
"green" : "58",
"red" : "58"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.996",
"green" : "1.000",
"red" : "0.996"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "60",
"green" : "58",
"red" : "58"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.910",
"green" : "0.882",
"red" : "0.851"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "60",
"green" : "58",
"red" : "58"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,9 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.290",
"blue" : "0x43",
"green" : "0x3C",
"red" : "0x3C"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "0.650",
"blue" : "0x58",
"green" : "0x54",
"red" : "0x54"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.549",
"green" : "0.510",
"red" : "0.431"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "140",
"green" : "130",
"red" : "110"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -324,6 +324,7 @@ any server.";
"Scene.Settings.Section.Appearance.Dark" = "Always Dark";
"Scene.Settings.Section.Appearance.Light" = "Always Light";
"Scene.Settings.Section.Appearance.Title" = "Appearance";
"Scene.Settings.Section.AppearanceSettings.DarkMode.Title" = "True black Dark Mode";
"Scene.Settings.Section.Boringzone.Privacy" = "Privacy Policy";
"Scene.Settings.Section.Boringzone.Terms" = "Terms of Service";
"Scene.Settings.Section.Boringzone.Title" = "The Boring zone";

View File

@ -324,6 +324,7 @@ any server.";
"Scene.Settings.Section.Appearance.Dark" = "Always Dark";
"Scene.Settings.Section.Appearance.Light" = "Always Light";
"Scene.Settings.Section.Appearance.Title" = "Appearance";
"Scene.Settings.Section.AppearanceSettings.DarkMode.Title" = "True black Dark Mode";
"Scene.Settings.Section.Boringzone.Privacy" = "Privacy Policy";
"Scene.Settings.Section.Boringzone.Terms" = "Terms of Service";
"Scene.Settings.Section.Boringzone.Title" = "The Boring zone";

View File

@ -25,7 +25,7 @@ final class AutoCompleteViewController: UIViewController {
let chevronView = AutoCompleteTopChevronView()
let containerBackgroundView: UIView = {
let view = UIView()
view.backgroundColor = Asset.Colors.Background.systemBackground.color
view.backgroundColor = ThemeService.shared.currentTheme.value.systemBackgroundColor
return view
}()

View File

@ -73,13 +73,6 @@ final class AutoCompleteTableViewCell: UITableViewCell {
extension AutoCompleteTableViewCell {
private func _init() {
backgroundColor = .clear
selectedBackgroundView = {
let view = UIView()
view.backgroundColor = Asset.Colors.Background.Cell.highlight.color
return view
}()
let topPaddingView = UIView()
let bottomPaddingView = UIView()

View File

@ -86,10 +86,10 @@ extension ComposeStatusAttachmentCollectionViewCell {
removeButton.widthAnchor.constraint(equalToConstant: ComposeStatusAttachmentCollectionViewCell.removeButtonSize.width).priority(.defaultHigh),
removeButton.heightAnchor.constraint(equalToConstant: ComposeStatusAttachmentCollectionViewCell.removeButtonSize.height).priority(.defaultHigh),
])
removeButton.addTarget(self, action: #selector(ComposeStatusAttachmentCollectionViewCell.removeButtonDidPressed(_:)), for: .touchUpInside)
}
}

View File

@ -29,7 +29,7 @@ final class ComposeStatusPollOptionAppendEntryCollectionViewCell: UICollectionVi
override var isHighlighted: Bool {
didSet {
pollOptionView.roundedBackgroundView.backgroundColor = isHighlighted ? Asset.Colors.Background.tertiarySystemBackground.color : Asset.Colors.Background.secondarySystemBackground.color
pollOptionView.roundedBackgroundView.backgroundColor = isHighlighted ? ThemeService.shared.currentTheme.value.tertiarySystemGroupedBackgroundColor.withAlphaComponent(0.6) : ThemeService.shared.currentTheme.value.tertiarySystemGroupedBackgroundColor
pollOptionView.plusCircleImageView.tintColor = isHighlighted ? Asset.Colors.brandBlue.color.withAlphaComponent(0.5) : Asset.Colors.brandBlue.color
}
}
@ -82,7 +82,7 @@ extension ComposeStatusPollOptionAppendEntryCollectionViewCell {
pollOptionView.optionTextField.isHidden = true
pollOptionView.plusCircleImageView.isHidden = false
pollOptionView.roundedBackgroundView.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
pollOptionView.roundedBackgroundView.backgroundColor = ThemeService.shared.currentTheme.value.tertiarySystemGroupedBackgroundColor
setupBorderColor()
pollOptionView.addGestureRecognizer(singleTagGestureRecognizer)
@ -93,7 +93,7 @@ extension ComposeStatusPollOptionAppendEntryCollectionViewCell {
private func setupBorderColor() {
pollOptionView.roundedBackgroundView.layer.borderWidth = 1
pollOptionView.roundedBackgroundView.layer.borderColor = Asset.Colors.Background.secondarySystemBackground.color.cgColor
pollOptionView.roundedBackgroundView.layer.borderColor = ThemeService.shared.currentTheme.value.tableViewCellSelectionBackgroundColor.withAlphaComponent(0.3).cgColor
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {

View File

@ -83,9 +83,11 @@ extension ComposeStatusPollOptionCollectionViewCell {
pollOptionView.checkmarkImageView.isHidden = true
pollOptionView.optionPercentageLabel.isHidden = true
pollOptionView.optionTextField.text = nil
pollOptionView.roundedBackgroundView.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
pollOptionView.checkmarkBackgroundView.backgroundColor = Asset.Colors.Background.tertiarySystemBackground.color
pollOptionView.roundedBackgroundView.backgroundColor = ThemeService.shared.currentTheme.value.tertiarySystemGroupedBackgroundColor
pollOptionView.checkmarkBackgroundView.backgroundColor = UIColor(dynamicProvider: { traitCollection in
return traitCollection.userInterfaceStyle == .light ? .white : ThemeService.shared.currentTheme.value.tableViewCellSelectionBackgroundColor
})
setupBorderColor()
pollOptionView.addGestureRecognizer(singleTagGestureRecognizer)
@ -103,7 +105,10 @@ extension ComposeStatusPollOptionCollectionViewCell {
}
private func setupBorderColor() {
pollOptionView.checkmarkBackgroundView.layer.borderColor = UIColor.systemGray3.cgColor
pollOptionView.roundedBackgroundView.layer.borderWidth = 1
pollOptionView.roundedBackgroundView.layer.borderColor = ThemeService.shared.currentTheme.value.tableViewCellSelectionBackgroundColor.withAlphaComponent(0.3).cgColor
pollOptionView.checkmarkBackgroundView.layer.borderColor = ThemeService.shared.currentTheme.value.tableViewCellSelectionBackgroundColor.withAlphaComponent(0.3).cgColor
pollOptionView.checkmarkBackgroundView.layer.borderWidth = 1
}

View File

@ -53,7 +53,6 @@ final class ComposeViewController: UIViewController, NeedsDependency {
tableView.register(ComposeRepliedToStatusContentTableViewCell.self, forCellReuseIdentifier: String(describing: ComposeRepliedToStatusContentTableViewCell.self))
tableView.register(ComposeStatusContentTableViewCell.self, forCellReuseIdentifier: String(describing: ComposeStatusContentTableViewCell.self))
tableView.register(ComposeStatusAttachmentTableViewCell.self, forCellReuseIdentifier: String(describing: ComposeStatusAttachmentTableViewCell.self))
tableView.backgroundColor = Asset.Scene.Compose.background.color
tableView.alwaysBounceVertical = true
tableView.separatorStyle = .none
tableView.tableFooterView = UIView()
@ -145,7 +144,15 @@ extension ComposeViewController {
self.title = title
}
.store(in: &disposeBag)
view.backgroundColor = Asset.Scene.Compose.background.color
view.backgroundColor = ThemeService.shared.currentTheme.value.systemElevatedBackgroundColor
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.view.backgroundColor = theme.systemElevatedBackgroundColor
self.tableView.backgroundColor = theme.systemElevatedBackgroundColor
}
.store(in: &disposeBag)
navigationItem.leftBarButtonItem = cancelBarButtonItem
navigationItem.rightBarButtonItem = publishBarButtonItem
publishButton.addTarget(self, action: #selector(ComposeViewController.publishBarButtonItemPressed(_:)), for: .touchUpInside)
@ -903,7 +910,7 @@ extension ComposeViewController: UICollectionViewDelegate {
extension ComposeViewController: UIAdaptivePresentationControllerDelegate {
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle {
return .fullScreen
return traitCollection.userInterfaceIdiom == .pad ? .formSheet : .automatic
}
func presentationControllerShouldDismiss(_ presentationController: UIPresentationController) -> Bool {

View File

@ -30,7 +30,7 @@ final class ComposeStatusAttachmentTableViewCell: UITableViewCell {
let collectionViewLayout = ComposeStatusAttachmentTableViewCell.createLayout()
let collectionView = UICollectionView(frame: .zero, collectionViewLayout: collectionViewLayout)
collectionView.register(ComposeStatusAttachmentCollectionViewCell.self, forCellWithReuseIdentifier: String(describing: ComposeStatusAttachmentCollectionViewCell.self))
collectionView.backgroundColor = Asset.Scene.Compose.background.color
collectionView.backgroundColor = .clear
collectionView.alwaysBounceVertical = true
collectionView.isScrollEnabled = false
return collectionView
@ -51,6 +51,9 @@ final class ComposeStatusAttachmentTableViewCell: UITableViewCell {
extension ComposeStatusAttachmentTableViewCell {
private func _init() {
backgroundColor = .clear
contentView.backgroundColor = .clear
collectionView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(collectionView)
collectionViewHeightLayoutConstraint = collectionView.heightAnchor.constraint(equalToConstant: 200).priority(.defaultHigh)

View File

@ -40,7 +40,7 @@ final class ComposeStatusPollTableViewCell: UITableViewCell {
collectionView.register(ComposeStatusPollOptionCollectionViewCell.self, forCellWithReuseIdentifier: String(describing: ComposeStatusPollOptionCollectionViewCell.self))
collectionView.register(ComposeStatusPollOptionAppendEntryCollectionViewCell.self, forCellWithReuseIdentifier: String(describing: ComposeStatusPollOptionAppendEntryCollectionViewCell.self))
collectionView.register(ComposeStatusPollExpiresOptionCollectionViewCell.self, forCellWithReuseIdentifier: String(describing: ComposeStatusPollExpiresOptionCollectionViewCell.self))
collectionView.backgroundColor = Asset.Scene.Compose.background.color
collectionView.backgroundColor = .clear
collectionView.alwaysBounceVertical = true
collectionView.isScrollEnabled = false
return collectionView
@ -61,6 +61,9 @@ final class ComposeStatusPollTableViewCell: UITableViewCell {
extension ComposeStatusPollTableViewCell {
private func _init() {
backgroundColor = .clear
contentView.backgroundColor = .clear
collectionView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(collectionView)
collectionViewHeightLayoutConstraint = collectionView.heightAnchor.constraint(equalToConstant: 300).priority(.defaultHigh)

View File

@ -52,7 +52,7 @@ extension AttachmentContainerView.EmptyStateView {
layer.masksToBounds = true
layer.cornerRadius = AttachmentContainerView.containerViewCornerRadius
layer.cornerCurve = .continuous
backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
backgroundColor = ThemeService.shared.currentTheme.value.systemGroupedBackgroundColor
let stackView = UIStackView()
stackView.axis = .vertical

View File

@ -14,7 +14,11 @@ final class AttachmentContainerView: UIView {
var descriptionBackgroundViewFrameObservation: NSKeyValueObservation?
let activityIndicatorView = UIActivityIndicatorView(style: .large)
let activityIndicatorView: UIActivityIndicatorView = {
let activityIndicatorView = UIActivityIndicatorView(style: .large)
activityIndicatorView.color = UIColor.white.withAlphaComponent(0.8)
return activityIndicatorView
}()
let previewImageView: UIImageView = {
let imageView = UIImageView()
@ -119,15 +123,32 @@ extension AttachmentContainerView {
activityIndicatorView.centerYAnchor.constraint(equalTo: previewImageView.centerYAnchor),
])
setupBroader()
emptyStateView.isHidden = true
activityIndicatorView.hidesWhenStopped = true
activityIndicatorView.startAnimating()
descriptionTextView.delegate = self
}
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
super.traitCollectionDidChange(previousTraitCollection)
setupBroader()
}
}
extension AttachmentContainerView {
private func setupBroader() {
emptyStateView.layer.borderWidth = 1
emptyStateView.layer.borderColor = traitCollection.userInterfaceStyle == .dark ? ThemeService.shared.currentTheme.value.tableViewCellSelectionBackgroundColor.cgColor : nil
}
}
// MARK: - UITextViewDelegate
extension AttachmentContainerView: UITextViewDelegate {
func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {

View File

@ -59,7 +59,13 @@ extension HashtagTimelineViewController {
titleView.update(title: viewModel.hashtag, subtitle: nil, emojiDict: [:])
navigationItem.titleView = titleView
view.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.view.backgroundColor = theme.secondarySystemBackgroundColor
}
.store(in: &disposeBag)
navigationItem.rightBarButtonItem = composeBarButtonItem

View File

@ -79,9 +79,16 @@ extension HomeTimelineViewController {
override func viewDidLoad() {
super.viewDidLoad()
title = L10n.Scene.HomeTimeline.title
view.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.view.backgroundColor = theme.secondarySystemBackgroundColor
}
.store(in: &disposeBag)
navigationItem.leftBarButtonItem = settingBarButtonItem
navigationItem.titleView = titleView
titleView.delegate = self

View File

@ -100,8 +100,16 @@ extension MainTabBarController {
delegate = self
view.backgroundColor = Asset.Colors.Background.systemBackground.color
view.backgroundColor = ThemeService.shared.currentTheme.value.systemBackgroundColor
// ThemeService.shared.currentTheme
// .receive(on: RunLoop.main)
// .sink { [weak self] theme in
// guard let self = self else { return }
// // fix tab bar not update color issue
// self.tabBar.backgroundColor = theme.tabBarBackgroundColor
// }
// .store(in: &disposeBag)
let tabs = Tab.allCases
let viewControllers: [UIViewController] = tabs.map { tab in
let viewController = tab.viewController(context: context, coordinator: coordinator)

View File

@ -48,7 +48,13 @@ extension NotificationViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.view.backgroundColor = theme.secondarySystemBackgroundColor
}
.store(in: &disposeBag)
segmentControl.translatesAutoresizingMaskIntoConstraints = false
navigationItem.titleView = segmentControl
NSLayoutConstraint.activate([

View File

@ -137,13 +137,6 @@ final class NotificationStatusTableViewCell: UITableViewCell, StatusCell {
extension NotificationStatusTableViewCell {
func configure() {
backgroundColor = Asset.Colors.Background.systemBackground.color
selectedBackgroundView = {
let view = UIView()
view.backgroundColor = Asset.Colors.Background.Cell.highlight.color
return view
}()
containerStackView.axis = .horizontal
containerStackView.alignment = .top
containerStackView.distribution = .fill
@ -225,14 +218,16 @@ extension NotificationStatusTableViewCell {
statusView.trailingAnchor.constraint(equalTo: statusContainerView.layoutMarginsGuide.trailingAnchor),
statusView.bottomAnchor.constraint(equalTo: statusContainerView.layoutMarginsGuide.bottomAnchor),
])
statusContainerView.backgroundColor = UIColor(dynamicProvider: { collection in
switch collection.userInterfaceStyle {
case .dark:
return Asset.Colors.Background.tertiarySystemGroupedBackground.color
default:
return .clear
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.statusContainerView.backgroundColor = UIColor(dynamicProvider: { traitCollection in
return traitCollection.userInterfaceStyle == .light ? theme.systemBackgroundColor : theme.tertiarySystemGroupedBackgroundColor
})
}
})
.store(in: &disposeBag)
// remove item don't display
statusView.actionToolbarContainer.removeFromStackView()
// it affect stackView's height, need remove

View File

@ -47,7 +47,15 @@ extension FavoriteViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.view.backgroundColor = theme.secondarySystemBackgroundColor
}
.store(in: &disposeBag)
navigationItem.titleView = titleView
titleView.update(title: L10n.Scene.Favorite.title, subtitle: nil, emojiDict: [:])

View File

@ -87,8 +87,14 @@ extension ProfileHeaderViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.view.backgroundColor = theme.systemGroupedBackgroundColor
}
.store(in: &disposeBag)
profileHeaderView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(profileHeaderView)
@ -105,6 +111,7 @@ extension ProfileHeaderViewController {
profileFieldCollectionViewCellDelegate: self,
profileFieldAddEntryCollectionViewCellDelegate: self
)
let longPressReorderGesture = UILongPressGestureRecognizer(target: self, action: #selector(ProfileHeaderViewController.longPressReorderGestureHandler(_:)))
profileHeaderView.fieldCollectionView.addGestureRecognizer(longPressReorderGesture)

View File

@ -7,6 +7,7 @@
import os.log
import UIKit
import Combine
import ActiveLabel
import TwitterTextEditor
import FLAnimatedImage
@ -36,6 +37,7 @@ final class ProfileHeaderView: UIView {
static let bannerImageViewOverlayViewBackgroundEditingColor = UIColor.black.withAlphaComponent(0.8)
weak var delegate: ProfileHeaderViewDelegate?
var disposeBag = Set<AnyCancellable>()
var state: State?
@ -213,7 +215,6 @@ final class ProfileHeaderView: UIView {
collectionView.register(ProfileFieldAddEntryCollectionViewCell.self, forCellWithReuseIdentifier: String(describing: ProfileFieldAddEntryCollectionViewCell.self))
collectionView.register(ProfileFieldCollectionViewHeaderFooterView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: ProfileFieldCollectionViewHeaderFooterView.headerReuseIdentifer)
collectionView.register(ProfileFieldCollectionViewHeaderFooterView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: ProfileFieldCollectionViewHeaderFooterView.footerReuseIdentifer)
collectionView.backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
collectionView.isScrollEnabled = false
return collectionView
}()
@ -238,7 +239,14 @@ final class ProfileHeaderView: UIView {
extension ProfileHeaderView {
private func _init() {
backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.backgroundColor = theme.systemGroupedBackgroundColor
self.fieldCollectionView.backgroundColor = theme.profileFieldCollectionViewBackgroundColor
}
.store(in: &disposeBag)
// banner
bannerContainerView.translatesAutoresizingMaskIntoConstraints = false

View File

@ -142,7 +142,13 @@ extension ProfileViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.view.backgroundColor = theme.secondarySystemBackgroundColor
}
.store(in: &disposeBag)
let barAppearance = UINavigationBarAppearance()
barAppearance.configureWithTransparentBackground()

View File

@ -47,7 +47,14 @@ extension UserTimelineViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.view.backgroundColor = theme.secondarySystemBackgroundColor
}
.store(in: &disposeBag)
tableView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(tableView)

View File

@ -45,8 +45,7 @@ extension PublicTimelineViewController {
super.viewDidLoad()
title = "Public"
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
tableView.refreshControl = refreshControl
refreshControl.addTarget(self, action: #selector(PublicTimelineViewController.refreshControlValueChanged(_:)), for: .valueChanged)
// bind refresh control

View File

@ -53,8 +53,8 @@ final class ReportFooterView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = Asset.Colors.Background.systemElevatedBackground.color
self.backgroundColor = ThemeService.shared.currentTheme.value.systemElevatedBackgroundColor
stackview.addArrangedSubview(nextStepButton)
stackview.addArrangedSubview(skipButton)
addSubview(stackview)

View File

@ -65,7 +65,7 @@ final class ReportHeaderView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
self.backgroundColor = Asset.Colors.Background.systemElevatedBackground.color
self.backgroundColor = ThemeService.shared.currentTheme.value.systemElevatedBackgroundColor
stackview.addArrangedSubview(titleLabel)
stackview.addArrangedSubview(contentLabel)
addSubview(stackview)

View File

@ -47,7 +47,7 @@ class ReportViewController: UIViewController, NeedsDependency {
let view = UIView()
view.translatesAutoresizingMaskIntoConstraints = false
view.setContentHuggingPriority(.defaultLow, for: .vertical)
view.backgroundColor = Asset.Colors.Background.systemElevatedBackground.color
view.backgroundColor = ThemeService.shared.currentTheme.value.systemElevatedBackgroundColor
return view
}()
@ -109,7 +109,15 @@ class ReportViewController: UIViewController, NeedsDependency {
// MAKR: - Private methods
private func setupView() {
view.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
view.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.view.backgroundColor = theme.secondarySystemBackgroundColor
}
.store(in: &disposeBag)
setupNavigation()
stackview.addArrangedSubview(header)

View File

@ -89,7 +89,14 @@ final class ReportedStatusTableViewCell: UITableViewCell, StatusCell {
extension ReportedStatusTableViewCell {
private func _init() {
backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemGroupedBackgroundColor
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemGroupedBackgroundColor
}
.store(in: &disposeBag)
checkbox.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(checkbox)

View File

@ -39,20 +39,17 @@ final class SearchViewController: UIViewController, NeedsDependency {
let statusBar: UIView = {
let view = UIView()
view.backgroundColor = Asset.Colors.Background.bar.color
return view
}()
let searchBar: UISearchBar = {
let searchBar = UISearchBar()
searchBar.placeholder = L10n.Scene.Search.Searchbar.placeholder
searchBar.tintColor = Asset.Colors.brandBlue.color
searchBar.translatesAutoresizingMaskIntoConstraints = false
// let micImage = UIImage(systemName: "mic.fill")
// searchBar.setImage(micImage, for: .bookmark, state: .normal)
// searchBar.showsBookmarkButton = true
searchBar.scopeButtonTitles = [L10n.Scene.Search.Searching.Segment.all, L10n.Scene.Search.Searching.Segment.people, L10n.Scene.Search.Searching.Segment.hashtags]
searchBar.barTintColor = Asset.Colors.Background.bar.color
return searchBar
}()
@ -99,7 +96,6 @@ final class SearchViewController: UIViewController, NeedsDependency {
// searching
let searchingTableView: UITableView = {
let tableView = UITableView()
tableView.backgroundColor = Asset.Colors.Background.systemBackground.color
tableView.rowHeight = UITableView.automaticDimension
tableView.separatorStyle = .singleLine
tableView.separatorInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
@ -109,7 +105,6 @@ final class SearchViewController: UIViewController, NeedsDependency {
lazy var searchHeader: UIView = {
let view = UIView()
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
view.frame = CGRect(origin: .zero, size: CGSize(width: searchingTableView.frame.width, height: 56))
return view
}()
@ -133,12 +128,24 @@ final class SearchViewController: UIViewController, NeedsDependency {
extension SearchViewController {
override func viewDidLoad() {
super.viewDidLoad()
let barAppearance = UINavigationBarAppearance()
barAppearance.configureWithTransparentBackground()
navigationItem.standardAppearance = barAppearance
navigationItem.compactAppearance = barAppearance
navigationItem.scrollEdgeAppearance = barAppearance
view.backgroundColor = Asset.Colors.Background.systemGroupedBackground.color
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.view.backgroundColor = theme.systemGroupedBackgroundColor
self.searchHeader.backgroundColor = theme.systemGroupedBackgroundColor
self.searchingTableView.backgroundColor = theme.systemBackgroundColor
self.statusBar.backgroundColor = theme.navigationBarBackgroundColor
}
.store(in: &disposeBag)
navigationItem.hidesBackButton = true
setupSearchBar()
@ -152,6 +159,12 @@ extension SearchViewController {
view.bringSubviewToFront(statusBar)
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
searchBar.tintColor = Asset.Colors.brandBlue.color
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

View File

@ -54,8 +54,6 @@ final class SearchingTableViewCell: UITableViewCell {
extension SearchingTableViewCell {
private func configure() {
backgroundColor = Asset.Colors.Background.systemBackground.color
let containerStackView = UIStackView()
containerStackView.axis = .horizontal
containerStackView.distribution = .fill

View File

@ -95,7 +95,7 @@ class SettingsViewController: UIViewController, NeedsDependency {
tableView.delegate = self
tableView.rowHeight = UITableView.automaticDimension
tableView.backgroundColor = .clear
tableView.separatorColor = Asset.Colors.Background.Cell.separator.color
tableView.separatorColor = ThemeService.shared.currentTheme.value.separator
tableView.register(SettingsAppearanceTableViewCell.self, forCellReuseIdentifier: String(describing: SettingsAppearanceTableViewCell.self))
tableView.register(SettingsToggleTableViewCell.self, forCellReuseIdentifier: String(describing: SettingsToggleTableViewCell.self))
@ -129,6 +129,13 @@ class SettingsViewController: UIViewController, NeedsDependency {
viewModel.viewDidLoad.send()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
// make large title not collapsed
navigationController?.navigationBar.sizeToFit()
}
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
@ -186,16 +193,31 @@ class SettingsViewController: UIViewController, NeedsDependency {
}
private func setupView() {
view.backgroundColor = UIColor(dynamicProvider: { traitCollection in
self.view.backgroundColor = UIColor(dynamicProvider: { traitCollection in
switch traitCollection.userInterfaceLevel {
case .elevated where traitCollection.userInterfaceStyle == .dark:
return Asset.Colors.Background.systemElevatedBackground.color
return ThemeService.shared.currentTheme.value.systemElevatedBackgroundColor
default:
return Asset.Colors.Background.secondarySystemBackground.color
return ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
}
})
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.view.backgroundColor = UIColor(dynamicProvider: { traitCollection in
switch traitCollection.userInterfaceLevel {
case .elevated where traitCollection.userInterfaceStyle == .dark:
return theme.systemElevatedBackgroundColor
default:
return theme.secondarySystemBackgroundColor
}
})
}
.store(in: &disposeBag)
setupNavigation()
view.addSubview(tableView)
NSLayoutConstraint.activate([
tableView.topAnchor.constraint(equalTo: view.topAnchor),
@ -215,12 +237,6 @@ class SettingsViewController: UIViewController, NeedsDependency {
target: self,
action: #selector(doneButtonDidClick))
navigationItem.title = L10n.Scene.Settings.title
let barAppearance = UINavigationBarAppearance()
barAppearance.configureWithDefaultBackground()
navigationItem.standardAppearance = barAppearance
navigationItem.compactAppearance = barAppearance
navigationItem.scrollEdgeAppearance = barAppearance
}
private func setupTableView() {
@ -332,6 +348,9 @@ extension SettingsViewController: UITableViewDelegate {
case .appearance:
// do nothing
break
case .appearanceDarkMode:
// do nothing
break
case .notification:
// do nothing
break
@ -418,6 +437,23 @@ extension SettingsViewController: SettingsToggleCellDelegate {
guard let indexPath = tableView.indexPath(for: cell) else { return }
let item = dataSource.itemIdentifier(for: indexPath)
switch item {
case .appearanceDarkMode(let settingObjectID):
let isOn = `switch`.isOn
let managedObjectContext = context.backgroundManagedObjectContext
managedObjectContext.performChanges {
let setting = managedObjectContext.object(with: settingObjectID) as! Setting
setting.update(preferredTrueBlackDarkMode: isOn)
}
.sink { result in
switch result {
case .success:
ThemeService.shared.set(themeName: isOn ? .system : .mastodon)
case .failure(let error):
assertionFailure(error.localizedDescription)
break
}
}
.store(in: &disposeBag)
case .notification(let settingObjectID, let switchMode):
let isOn = `switch`.isOn
let managedObjectContext = context.backgroundManagedObjectContext

View File

@ -74,6 +74,10 @@ extension SettingsViewModel {
let appearanceItems = [SettingsItem.appearance(settingObjectID: setting.objectID)]
snapshot.appendSections([.appearance])
snapshot.appendItems(appearanceItems, toSection: .appearance)
let appearanceSettingItems = [SettingsItem.appearanceDarkMode(settingObjectID: setting.objectID)]
snapshot.appendSections([.appearanceSettings])
snapshot.appendItems(appearanceSettingItems, toSection: .appearanceSettings)
let notificationItems = SettingsItem.NotificationSwitchMode.allCases.map { mode in
SettingsItem.notification(settingObjectID: setting.objectID, switchMode: mode)
@ -129,6 +133,7 @@ extension SettingsViewModel {
let setting = self.context.managedObjectContext.object(with: objectID) as! Setting
cell.update(with: setting.appearance)
ManagedObjectObserver.observe(object: setting)
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { _ in
// do nothing
}, receiveValue: { [weak cell] change in
@ -141,6 +146,26 @@ extension SettingsViewModel {
}
cell.delegate = settingsAppearanceTableViewCellDelegate
return cell
case .appearanceDarkMode(let objectID):
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsToggleTableViewCell.self), for: indexPath) as! SettingsToggleTableViewCell
cell.delegate = settingsToggleCellDelegate
cell.textLabel?.text = L10n.Scene.Settings.Section.AppearanceSettings.DarkMode.title
self.context.managedObjectContext.performAndWait {
let setting = self.context.managedObjectContext.object(with: objectID) as! Setting
cell.switchButton.isOn = setting.preferredTrueBlackDarkMode
ManagedObjectObserver.observe(object: setting)
.receive(on: DispatchQueue.main)
.sink(receiveCompletion: { _ in
// do nothing
}, receiveValue: { [weak cell] change in
guard let cell = cell else { return }
guard case .update(let object) = change.changeType,
let setting = object as? Setting else { return }
cell.switchButton.isOn = setting.preferredTrueBlackDarkMode
})
.store(in: &cell.disposeBag)
}
return cell
case .notification(let objectID, let switchMode):
let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsToggleTableViewCell.self), for: indexPath) as! SettingsToggleTableViewCell
self.context.managedObjectContext.performAndWait {

View File

@ -31,6 +31,5 @@ extension SettingsLinkTableViewCell {
func update(with link: SettingsItem.Link) {
textLabel?.text = link.title
textLabel?.textColor = link.textColor
backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
}
}

View File

@ -38,7 +38,6 @@ class SettingsToggleTableViewCell: UITableViewCell {
private func setupUI() {
selectionStyle = .none
accessoryView = switchButton
backgroundColor = Asset.Colors.Background.secondaryGroupedSystemBackground.color
switchButton.addTarget(self, action: #selector(switchValueDidChange(sender:)), for: .valueChanged)
}

View File

@ -7,6 +7,7 @@
import os.log
import Foundation
import Combine
import UIKit
protocol ContentWarningOverlayViewDelegate: AnyObject {
@ -14,6 +15,8 @@ protocol ContentWarningOverlayViewDelegate: AnyObject {
}
class ContentWarningOverlayView: UIView {
var disposeBag = Set<AnyCancellable>()
static let cornerRadius: CGFloat = 4
static let blurVisualEffect = UIBlurEffect(style: .systemUltraThinMaterial)
@ -33,7 +36,7 @@ class ContentWarningOverlayView: UIView {
// for status style overlay
let contentOverlayView: UIView = {
let view = UIView()
view.backgroundColor = Asset.Colors.ContentWarningOverlay.background.color
view.backgroundColor = ThemeService.shared.currentTheme.value.contentWarningOverlayBackgroundColor
view.applyCornerRadius(radius: ContentWarningOverlayView.cornerRadius)
return view
}()

View File

@ -17,6 +17,8 @@ final class PollOptionView: UIView {
static let checkmarkBackgroundLeadingMargin: CGFloat = 9
private var viewStateDisposeBag = Set<AnyCancellable>()
var disposeBag = Set<AnyCancellable>()
let roundedBackgroundView = UIView()
let voteProgressStripView: StripProgressView = {
@ -82,7 +84,7 @@ final class PollOptionView: UIView {
extension PollOptionView {
private func _init() {
// default color in the timeline
roundedBackgroundView.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
roundedBackgroundView.backgroundColor = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
roundedBackgroundView.translatesAutoresizingMaskIntoConstraints = false
addSubview(roundedBackgroundView)

View File

@ -9,6 +9,8 @@ import UIKit
import Combine
final class PollOptionTableViewCell: UITableViewCell {
var disposeBag = Set<AnyCancellable>()
let pollOptionView = PollOptionView()
var attribute: PollItem.Attribute?
@ -29,7 +31,7 @@ final class PollOptionTableViewCell: UITableViewCell {
guard let voteState = attribute?.voteState else { return }
switch voteState {
case .hidden:
let color = Asset.Colors.Background.systemGroupedBackground.color
let color = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
pollOptionView.roundedBackgroundView.backgroundColor = isHighlighted ? color.withAlphaComponent(0.8) : color
case .reveal:
break
@ -42,7 +44,7 @@ final class PollOptionTableViewCell: UITableViewCell {
guard let voteState = attribute?.voteState else { return }
switch voteState {
case .hidden:
let color = Asset.Colors.Background.systemGroupedBackground.color
let color = ThemeService.shared.currentTheme.value.secondarySystemBackgroundColor
pollOptionView.roundedBackgroundView.backgroundColor = isHighlighted ? color.withAlphaComponent(0.8) : color
case .reveal:
break

View File

@ -103,13 +103,6 @@ final class StatusTableViewCell: UITableViewCell, StatusCell {
extension StatusTableViewCell {
private func _init() {
backgroundColor = Asset.Colors.Background.systemBackground.color
selectedBackgroundView = {
let view = UIView()
view.backgroundColor = Asset.Colors.Background.Cell.highlight.color
return view
}()
statusView.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(statusView)
NSLayoutConstraint.activate([
@ -214,7 +207,7 @@ extension StatusTableViewCell: UITableViewDelegate {
os_log(.info, log: .debug, "%{public}s[%{public}ld], %{public}s: indexPath: %s. PollID: %s", ((#file as NSString).lastPathComponent), #line, #function, indexPath.debugDescription, pollID ?? "<nil>")
}
guard let item = diffableDataSource.itemIdentifier(for: indexPath),
case let .opion(objectID, _) = item,
case let .option(objectID, _) = item,
let option = delegate?.managedObjectContext.object(with: objectID) as? PollOption else {
return false
}
@ -236,7 +229,7 @@ extension StatusTableViewCell: UITableViewDelegate {
guard let context = delegate?.context else { return nil }
guard let activeMastodonAuthenticationBox = context.authenticationService.activeMastodonAuthenticationBox.value else { return nil }
guard let item = diffableDataSource.itemIdentifier(for: indexPath),
case let .opion(objectID, _) = item,
case let .option(objectID, _) = item,
let option = delegate?.managedObjectContext.object(with: objectID) as? PollOption else {
return nil
}

View File

@ -66,7 +66,16 @@ class SuggestionAccountViewController: UIViewController, NeedsDependency {
extension SuggestionAccountViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = Asset.Colors.Background.systemBackground.color
view.backgroundColor = ThemeService.shared.currentTheme.value.systemBackgroundColor
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.view.backgroundColor = theme.systemBackgroundColor
}
.store(in: &disposeBag)
title = L10n.Scene.SuggestionAccount.title
navigationItem.rightBarButtonItem
= UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.done,

View File

@ -87,8 +87,6 @@ final class SuggestionAccountTableViewCell: UITableViewCell {
extension SuggestionAccountTableViewCell {
private func configure() {
backgroundColor = .clear
let containerStackView = UIStackView()
containerStackView.axis = .horizontal
containerStackView.distribution = .fill

View File

@ -52,7 +52,13 @@ extension ThreadViewController {
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = Asset.Colors.Background.secondarySystemBackground.color
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.sink { [weak self] theme in
guard let self = self else { return }
self.view.backgroundColor = theme.secondarySystemBackgroundColor
}
.store(in: &disposeBag)
navigationItem.title = L10n.Scene.Thread.backTitle
navigationItem.titleView = titleView
navigationItem.rightBarButtonItem = replyBarButtonItem

View File

@ -0,0 +1,36 @@
//
// MastodonTheme.swift
// Mastodon
//
// Created by MainasuK Cirno on 2021-7-5.
//
import UIKit
struct MastodonTheme: Theme {
let systemBackgroundColor = Asset.Theme.Mastodon.systemBackground.color
let secondarySystemBackgroundColor = Asset.Theme.Mastodon.secondarySystemBackground.color
let tertiarySystemBackgroundColor = Asset.Theme.Mastodon.tertiarySystemBackground.color
let systemElevatedBackgroundColor = Asset.Theme.Mastodon.systemElevatedBackground.color
let systemGroupedBackgroundColor = Asset.Theme.Mastodon.systemGroupedBackground.color
let secondarySystemGroupedBackgroundColor = Asset.Theme.Mastodon.secondaryGroupedSystemBackground.color
let tertiarySystemGroupedBackgroundColor = Asset.Theme.Mastodon.tertiarySystemGroupedBackground.color
let navigationBarBackgroundColor = Asset.Theme.Mastodon.navigationBarBackground.color
let tabBarBackgroundColor = Asset.Theme.Mastodon.tabBarBackground.color
let tabBarItemSelectedIconColor = Asset.Colors.brandBlue.color
let tabBarItemFocusedIconColor = Asset.Theme.Mastodon.tabBarItemInactiveIconColor.color
let tabBarItemNormalIconColor = Asset.Theme.Mastodon.tabBarItemInactiveIconColor.color
let tabBarItemDisabledIconColor = Asset.Theme.Mastodon.tabBarItemInactiveIconColor.color
let separator = Asset.Theme.Mastodon.separator.color
let tableViewCellBackgroundColor = Asset.Theme.Mastodon.tableViewCellBackground.color
let tableViewCellSelectionBackgroundColor = Asset.Theme.Mastodon.tableViewCellSelectionBackground.color
let contentWarningOverlayBackgroundColor = Asset.Theme.Mastodon.contentWarningOverlayBackground.color
let profileFieldCollectionViewBackgroundColor = Asset.Theme.Mastodon.profileFieldCollectionViewBackground.color
}

View File

@ -0,0 +1,36 @@
//
// SystemTheme.swift
// Mastodon
//
// Created by MainasuK Cirno on 2021-7-5.
//
import UIKit
struct SystemTheme: Theme {
let systemBackgroundColor = Asset.Theme.System.systemBackground.color
let secondarySystemBackgroundColor = Asset.Theme.System.secondarySystemBackground.color
let tertiarySystemBackgroundColor = Asset.Theme.System.tertiarySystemBackground.color
let systemElevatedBackgroundColor = Asset.Theme.System.systemElevatedBackground.color
let systemGroupedBackgroundColor = Asset.Theme.System.systemGroupedBackground.color
let secondarySystemGroupedBackgroundColor = Asset.Theme.System.secondaryGroupedSystemBackground.color
let tertiarySystemGroupedBackgroundColor = Asset.Theme.System.tertiarySystemGroupedBackground.color
let navigationBarBackgroundColor = Asset.Theme.System.navigationBarBackground.color
let tabBarBackgroundColor = Asset.Theme.System.tabBarBackground.color
let tabBarItemSelectedIconColor = Asset.Colors.brandBlue.color
let tabBarItemFocusedIconColor = Asset.Theme.System.tabBarItemInactiveIconColor.color
let tabBarItemNormalIconColor = Asset.Theme.System.tabBarItemInactiveIconColor.color
let tabBarItemDisabledIconColor = Asset.Theme.System.tabBarItemInactiveIconColor.color
let separator = Asset.Theme.System.separator.color
let tableViewCellBackgroundColor = Asset.Theme.System.tableViewCellBackground.color
let tableViewCellSelectionBackgroundColor = Asset.Theme.System.tableViewCellSelectionBackground.color
let contentWarningOverlayBackgroundColor = Asset.Theme.System.contentWarningOverlayBackground.color
let profileFieldCollectionViewBackgroundColor = Asset.Theme.System.profileFieldCollectionViewBackground.color
}

View File

@ -0,0 +1,51 @@
//
// Theme.swift
// Mastodon
//
// Created by MainasuK Cirno on 2021-7-5.
//
import UIKit
protocol Theme {
var systemBackgroundColor: UIColor { get }
var secondarySystemBackgroundColor: UIColor { get }
var tertiarySystemBackgroundColor: UIColor { get }
var systemElevatedBackgroundColor: UIColor { get }
var systemGroupedBackgroundColor: UIColor { get }
var secondarySystemGroupedBackgroundColor: UIColor { get }
var tertiarySystemGroupedBackgroundColor: UIColor { get }
var navigationBarBackgroundColor: UIColor { get }
var tabBarBackgroundColor: UIColor { get }
var tabBarItemSelectedIconColor: UIColor { get }
var tabBarItemFocusedIconColor: UIColor { get }
var tabBarItemNormalIconColor: UIColor { get }
var tabBarItemDisabledIconColor: UIColor { get }
var separator: UIColor { get }
var tableViewCellBackgroundColor: UIColor { get }
var tableViewCellSelectionBackgroundColor: UIColor { get }
var contentWarningOverlayBackgroundColor: UIColor { get }
var profileFieldCollectionViewBackgroundColor: UIColor { get }
}
enum ThemeName: String, CaseIterable {
case system
case mastodon
}
extension ThemeName {
var theme: Theme {
switch self {
case .system: return SystemTheme()
case .mastodon: return MastodonTheme()
}
}
}

View File

@ -0,0 +1,71 @@
//
// ThemeService.swift
// Mastodon
//
// Created by MainasuK Cirno on 2021-7-5.
//
import UIKit
import Combine
// ref: https://zamzam.io/protocol-oriented-themes-for-ios-apps/
final class ThemeService {
// MARK: - Singleton
public static let shared = ThemeService()
let currentTheme: CurrentValueSubject<Theme, Never>
private init() {
let theme = ThemeName(rawValue: UserDefaults.shared.currentThemeNameRawValue)?.theme ?? ThemeName.mastodon.theme
currentTheme = CurrentValueSubject(theme)
}
func set(themeName: ThemeName) {
UserDefaults.shared.currentThemeNameRawValue = themeName.rawValue
let theme = themeName.theme
apply(theme: theme)
currentTheme.value = theme
}
func apply(theme: Theme) {
// set navigation bar appearance
let appearance = UINavigationBarAppearance()
appearance.configureWithDefaultBackground()
appearance.backgroundColor = theme.navigationBarBackgroundColor
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
// set tab bar appearance
let tabBarAppearance = UITabBarAppearance()
tabBarAppearance.configureWithDefaultBackground()
let tabBarItemAppearance = UITabBarItemAppearance()
tabBarItemAppearance.selected.iconColor = theme.tabBarItemSelectedIconColor
tabBarItemAppearance.focused.iconColor = theme.tabBarItemFocusedIconColor
tabBarItemAppearance.normal.iconColor = theme.tabBarItemNormalIconColor
tabBarItemAppearance.disabled.iconColor = theme.tabBarItemDisabledIconColor
tabBarAppearance.stackedLayoutAppearance = tabBarItemAppearance
tabBarAppearance.inlineLayoutAppearance = tabBarItemAppearance
tabBarAppearance.compactInlineLayoutAppearance = tabBarItemAppearance
tabBarAppearance.backgroundColor = theme.tabBarBackgroundColor
tabBarAppearance.selectionIndicatorTintColor = Asset.Colors.brandBlue.color
UITabBar.appearance().standardAppearance = tabBarAppearance
UITabBar.appearance().barTintColor = theme.tabBarBackgroundColor
// set table view cell appearance
UITableViewCell.appearance().backgroundColor = theme.tableViewCellBackgroundColor
UITableViewCell.appearance(whenContainedInInstancesOf: [SettingsViewController.self]).backgroundColor = theme.secondarySystemGroupedBackgroundColor
UITableViewCell.appearance().selectionColor = theme.tableViewCellSelectionBackgroundColor
// set search bar appearance
UISearchBar.appearance().barTintColor = theme.navigationBarBackgroundColor
UISearchBar.appearance().tintColor = Asset.Colors.brandBlue.color
}
}

View File

@ -23,6 +23,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
AppSecret.default.register()
// configure appearance
ThemeService.shared.apply(theme: ThemeService.shared.currentTheme.value)
// Update app version info. See: `Settings.bundle`
UserDefaults.standard.setValue(UIApplication.appVersion(), forKey: "Mastodon.appVersion")

View File

@ -15,6 +15,7 @@ import FPSIndicator
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var disposeBag = Set<AnyCancellable>()
var observations = Set<NSKeyValueObservation>()
var window: UIWindow?
@ -34,30 +35,18 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
// set tint color
window.tintColor = Asset.Colors.brandBlue.color
// set navigation bar appearance
let appearance = UINavigationBarAppearance()
appearance.configureWithDefaultBackground()
appearance.backgroundColor = Asset.Colors.Background.bar.color
UINavigationBar.appearance().standardAppearance = appearance
UINavigationBar.appearance().compactAppearance = appearance
UINavigationBar.appearance().scrollEdgeAppearance = appearance
// set tab bar appearance
let tabBarAppearance = UITabBarAppearance()
tabBarAppearance.configureWithDefaultBackground()
let tabBarItemAppearance = UITabBarItemAppearance()
tabBarItemAppearance.selected.iconColor = Asset.Colors.brandBlue.color
tabBarItemAppearance.focused.iconColor = Asset.Colors.TabBar.itemInactive.color
tabBarItemAppearance.normal.iconColor = Asset.Colors.TabBar.itemInactive.color
tabBarItemAppearance.disabled.iconColor = Asset.Colors.TabBar.itemInactive.color
tabBarAppearance.stackedLayoutAppearance = tabBarItemAppearance
tabBarAppearance.inlineLayoutAppearance = tabBarItemAppearance
tabBarAppearance.compactInlineLayoutAppearance = tabBarItemAppearance
tabBarAppearance.backgroundColor = Asset.Colors.Background.bar.color
tabBarAppearance.selectionIndicatorTintColor = Asset.Colors.brandBlue.color
UITabBar.appearance().standardAppearance = tabBarAppearance
ThemeService.shared.currentTheme
.receive(on: RunLoop.main)
.dropFirst()
.sink { [weak self] theme in
guard let self = self else { return }
guard let window = self.window else { return }
window.subviews.forEach { view in
view.removeFromSuperview()
window.addSubview(view)
}
}
.store(in: &disposeBag)
let appContext = AppContext.shared
let sceneCoordinator = SceneCoordinator(scene: scene, sceneDelegate: self, appContext: appContext)