From d55271e921604d801b8dbd905e7ee471e8720131 Mon Sep 17 00:00:00 2001 From: Matt Bruce Date: Tue, 27 Jan 2026 12:17:21 -0600 Subject: [PATCH] Signed-off-by: Matt Bruce --- Andromida/AndromidaApp.swift | 2 +- Andromida/App/Models/AppSettingsData.swift | 1 + Andromida/App/State/SettingsStore.swift | 7 +- .../App/Views/Settings/SettingsView.swift | 5 ++ .../Accent.colorset/Contents.json | 6 +- .../AccentDark.colorset/Contents.json | 38 ++++++++++ .../AccentLight.colorset/Contents.json | 38 ++++++++++ .../AccentSecondary.colorset/Contents.json | 38 ++++++++++ .../Background.colorset/Contents.json | 6 +- .../BackgroundAlt.colorset/Contents.json | 6 +- .../BackgroundTertiary.colorset/Contents.json | 38 ++++++++++ .../Card.colorset/Contents.json | 6 +- .../Error.colorset/Contents.json | 38 ++++++++++ .../Info.colorset/Contents.json | 38 ++++++++++ .../Success.colorset/Contents.json | 12 +-- .../TextDisabled.colorset/Contents.json | 38 ++++++++++ .../TextPrimary.colorset/Contents.json | 6 +- .../TextTertiary.colorset/Contents.json | 38 ++++++++++ .../Warning.colorset/Contents.json | 10 +-- Andromida/Shared/Theme/RitualsTheme.swift | 75 ++++++++++--------- 20 files changed, 384 insertions(+), 62 deletions(-) create mode 100644 Andromida/Assets.xcassets/AccentDark.colorset/Contents.json create mode 100644 Andromida/Assets.xcassets/AccentLight.colorset/Contents.json create mode 100644 Andromida/Assets.xcassets/AccentSecondary.colorset/Contents.json create mode 100644 Andromida/Assets.xcassets/BackgroundTertiary.colorset/Contents.json create mode 100644 Andromida/Assets.xcassets/Error.colorset/Contents.json create mode 100644 Andromida/Assets.xcassets/Info.colorset/Contents.json create mode 100644 Andromida/Assets.xcassets/TextDisabled.colorset/Contents.json create mode 100644 Andromida/Assets.xcassets/TextTertiary.colorset/Contents.json diff --git a/Andromida/AndromidaApp.swift b/Andromida/AndromidaApp.swift index 1b9f3d3..c2f1925 100644 --- a/Andromida/AndromidaApp.swift +++ b/Andromida/AndromidaApp.swift @@ -76,7 +76,7 @@ struct AndromidaApp: App { } } .modelContainer(modelContainer) - .preferredColorScheme(.dark) + .preferredColorScheme(settingsStore.theme.colorScheme) } } } diff --git a/Andromida/App/Models/AppSettingsData.swift b/Andromida/App/Models/AppSettingsData.swift index 158316c..3d9ff9e 100644 --- a/Andromida/App/Models/AppSettingsData.swift +++ b/Andromida/App/Models/AppSettingsData.swift @@ -8,6 +8,7 @@ struct AppSettingsData: PersistableData { var hapticsEnabled: Bool = true var soundEnabled: Bool = true var remindersEnabled: Bool = false + var theme: AppTheme = .dark var lastModified: Date = .now /// Sync priority - uses haptics as a simple indicator of user activity diff --git a/Andromida/App/State/SettingsStore.swift b/Andromida/App/State/SettingsStore.swift index 34fc0d3..87c3790 100644 --- a/Andromida/App/State/SettingsStore.swift +++ b/Andromida/App/State/SettingsStore.swift @@ -4,7 +4,7 @@ import Bedrock @MainActor @Observable -final class SettingsStore: CloudSyncable { +final class SettingsStore: CloudSyncable, ThemeProviding { @ObservationIgnored private let cloudSync = CloudSyncManager() /// Observable copy of last sync date, updated when sync completes. @@ -26,6 +26,11 @@ final class SettingsStore: CloudSyncable { set { update { $0.soundEnabled = newValue } } } + var theme: AppTheme { + get { cloudSync.data.theme } + set { update { $0.theme = newValue } } + } + var iCloudAvailable: Bool { cloudSync.iCloudAvailable } var iCloudEnabled: Bool { diff --git a/Andromida/App/Views/Settings/SettingsView.swift b/Andromida/App/Views/Settings/SettingsView.swift index 7956a76..5b5e70d 100644 --- a/Andromida/App/Views/Settings/SettingsView.swift +++ b/Andromida/App/Views/Settings/SettingsView.swift @@ -45,6 +45,11 @@ struct SettingsView: View { ) SettingsCard(backgroundColor: AppSurface.card, borderColor: AppBorder.subtle) { + SettingsThemePicker( + store: store, + accentColor: AppAccent.primary + ) + if let categoryStore { SettingsNavigationRow( title: String(localized: "Categories"), diff --git a/Andromida/Assets.xcassets/Accent.colorset/Contents.json b/Andromida/Assets.xcassets/Accent.colorset/Contents.json index 5bb18fb..05715ef 100644 --- a/Andromida/Assets.xcassets/Accent.colorset/Contents.json +++ b/Andromida/Assets.xcassets/Accent.colorset/Contents.json @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.0", - "blue" : "0.53", - "green" : "0.63", - "red" : "0.95" + "blue" : "0.40", + "green" : "0.55", + "red" : "0.93" } }, "idiom" : "universal" diff --git a/Andromida/Assets.xcassets/AccentDark.colorset/Contents.json b/Andromida/Assets.xcassets/AccentDark.colorset/Contents.json new file mode 100644 index 0000000..542d484 --- /dev/null +++ b/Andromida/Assets.xcassets/AccentDark.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.25", + "green" : "0.38", + "red" : "0.75" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.25", + "green" : "0.38", + "red" : "0.75" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Andromida/Assets.xcassets/AccentLight.colorset/Contents.json b/Andromida/Assets.xcassets/AccentLight.colorset/Contents.json new file mode 100644 index 0000000..1544cbf --- /dev/null +++ b/Andromida/Assets.xcassets/AccentLight.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.55", + "green" : "0.70", + "red" : "0.98" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.55", + "green" : "0.70", + "red" : "0.98" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Andromida/Assets.xcassets/AccentSecondary.colorset/Contents.json b/Andromida/Assets.xcassets/AccentSecondary.colorset/Contents.json new file mode 100644 index 0000000..4da5e46 --- /dev/null +++ b/Andromida/Assets.xcassets/AccentSecondary.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.80", + "green" : "0.90", + "red" : "0.95" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.80", + "green" : "0.90", + "red" : "0.95" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Andromida/Assets.xcassets/Background.colorset/Contents.json b/Andromida/Assets.xcassets/Background.colorset/Contents.json index e9f0a0b..ab3fcb9 100644 --- a/Andromida/Assets.xcassets/Background.colorset/Contents.json +++ b/Andromida/Assets.xcassets/Background.colorset/Contents.json @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.0", - "blue" : "0.09", - "green" : "0.10", - "red" : "0.11" + "blue" : "0.08", + "green" : "0.09", + "red" : "0.12" } }, "idiom" : "universal" diff --git a/Andromida/Assets.xcassets/BackgroundAlt.colorset/Contents.json b/Andromida/Assets.xcassets/BackgroundAlt.colorset/Contents.json index 47bf0be..2ed8757 100644 --- a/Andromida/Assets.xcassets/BackgroundAlt.colorset/Contents.json +++ b/Andromida/Assets.xcassets/BackgroundAlt.colorset/Contents.json @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.0", - "blue" : "0.12", - "green" : "0.14", - "red" : "0.15" + "blue" : "0.10", + "green" : "0.11", + "red" : "0.14" } }, "idiom" : "universal" diff --git a/Andromida/Assets.xcassets/BackgroundTertiary.colorset/Contents.json b/Andromida/Assets.xcassets/BackgroundTertiary.colorset/Contents.json new file mode 100644 index 0000000..162df67 --- /dev/null +++ b/Andromida/Assets.xcassets/BackgroundTertiary.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.82", + "green" : "0.87", + "red" : "0.90" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.12", + "green" : "0.14", + "red" : "0.18" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Andromida/Assets.xcassets/Card.colorset/Contents.json b/Andromida/Assets.xcassets/Card.colorset/Contents.json index 91abdbf..14992ae 100644 --- a/Andromida/Assets.xcassets/Card.colorset/Contents.json +++ b/Andromida/Assets.xcassets/Card.colorset/Contents.json @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.0", - "blue" : "0.14", - "green" : "0.16", - "red" : "0.17" + "blue" : "0.11", + "green" : "0.12", + "red" : "0.16" } }, "idiom" : "universal" diff --git a/Andromida/Assets.xcassets/Error.colorset/Contents.json b/Andromida/Assets.xcassets/Error.colorset/Contents.json new file mode 100644 index 0000000..c727d83 --- /dev/null +++ b/Andromida/Assets.xcassets/Error.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.25", + "green" : "0.25", + "red" : "0.85" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.35", + "green" : "0.35", + "red" : "0.90" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Andromida/Assets.xcassets/Info.colorset/Contents.json b/Andromida/Assets.xcassets/Info.colorset/Contents.json new file mode 100644 index 0000000..90fd21e --- /dev/null +++ b/Andromida/Assets.xcassets/Info.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.85", + "green" : "0.62", + "red" : "0.40" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.92", + "green" : "0.72", + "red" : "0.55" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Andromida/Assets.xcassets/Success.colorset/Contents.json b/Andromida/Assets.xcassets/Success.colorset/Contents.json index d7c04b7..2458c45 100644 --- a/Andromida/Assets.xcassets/Success.colorset/Contents.json +++ b/Andromida/Assets.xcassets/Success.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.0", - "blue" : "0.56", - "green" : "0.62", - "red" : "0.17" + "blue" : "0.45", + "green" : "0.65", + "red" : "0.15" } }, "idiom" : "universal" @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.0", - "blue" : "0.66", - "green" : "0.72", - "red" : "0.24" + "blue" : "0.55", + "green" : "0.75", + "red" : "0.20" } }, "idiom" : "universal" diff --git a/Andromida/Assets.xcassets/TextDisabled.colorset/Contents.json b/Andromida/Assets.xcassets/TextDisabled.colorset/Contents.json new file mode 100644 index 0000000..1a41c1c --- /dev/null +++ b/Andromida/Assets.xcassets/TextDisabled.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.55", + "green" : "0.60", + "red" : "0.65" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.38", + "green" : "0.42", + "red" : "0.46" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Andromida/Assets.xcassets/TextPrimary.colorset/Contents.json b/Andromida/Assets.xcassets/TextPrimary.colorset/Contents.json index 0ddbad0..cfc317e 100644 --- a/Andromida/Assets.xcassets/TextPrimary.colorset/Contents.json +++ b/Andromida/Assets.xcassets/TextPrimary.colorset/Contents.json @@ -23,9 +23,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.0", - "blue" : "0.91", - "green" : "0.93", - "red" : "0.95" + "blue" : "1.0", + "green" : "1.0", + "red" : "1.0" } }, "idiom" : "universal" diff --git a/Andromida/Assets.xcassets/TextTertiary.colorset/Contents.json b/Andromida/Assets.xcassets/TextTertiary.colorset/Contents.json new file mode 100644 index 0000000..eb93475 --- /dev/null +++ b/Andromida/Assets.xcassets/TextTertiary.colorset/Contents.json @@ -0,0 +1,38 @@ +{ + "colors" : [ + { + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.45", + "green" : "0.50", + "red" : "0.55" + } + }, + "idiom" : "universal" + }, + { + "appearances" : [ + { + "appearance" : "luminosity", + "value" : "dark" + } + ], + "color" : { + "color-space" : "srgb", + "components" : { + "alpha" : "1.0", + "blue" : "0.55", + "green" : "0.58", + "red" : "0.62" + } + }, + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Andromida/Assets.xcassets/Warning.colorset/Contents.json b/Andromida/Assets.xcassets/Warning.colorset/Contents.json index 496ec03..1a7d28d 100644 --- a/Andromida/Assets.xcassets/Warning.colorset/Contents.json +++ b/Andromida/Assets.xcassets/Warning.colorset/Contents.json @@ -5,9 +5,9 @@ "color-space" : "srgb", "components" : { "alpha" : "1.0", - "blue" : "0.42", - "green" : "0.77", - "red" : "0.91" + "blue" : "0.35", + "green" : "0.70", + "red" : "0.90" } }, "idiom" : "universal" @@ -23,8 +23,8 @@ "color-space" : "srgb", "components" : { "alpha" : "1.0", - "blue" : "0.52", - "green" : "0.82", + "blue" : "0.45", + "green" : "0.78", "red" : "0.95" } }, diff --git a/Andromida/Shared/Theme/RitualsTheme.swift b/Andromida/Shared/Theme/RitualsTheme.swift index fdb661d..e8b27fb 100644 --- a/Andromida/Shared/Theme/RitualsTheme.swift +++ b/Andromida/Shared/Theme/RitualsTheme.swift @@ -3,71 +3,78 @@ import Bedrock // MARK: - Rituals Surface Colors +/// Surface colors using Asset Catalog with light/dark variants. public enum RitualsSurfaceColors: SurfaceColorProvider { - public static let primary = Color(red: 0.12, green: 0.09, blue: 0.08) - public static let secondary = Color(red: 0.14, green: 0.11, blue: 0.10) - public static let tertiary = Color(red: 0.18, green: 0.14, blue: 0.12) - public static let overlay = Color(red: 0.12, green: 0.09, blue: 0.08) - public static let card = Color(red: 0.16, green: 0.12, blue: 0.11) - public static let groupedFill = Color(red: 0.13, green: 0.10, blue: 0.09) - public static let sectionFill = Color(red: 0.18, green: 0.14, blue: 0.12) + public static let primary = Color("Background") + public static let secondary = Color("BackgroundAlt") + public static let tertiary = Color("BackgroundTertiary") + public static let overlay = Color("Background") + public static let card = Color("Card") + public static let groupedFill = Color("BackgroundAlt") + public static let sectionFill = Color("BackgroundTertiary") } // MARK: - Rituals Text Colors +/// Text colors using Asset Catalog with light/dark variants. public enum RitualsTextColors: TextColorProvider { - public static let primary = Color.white - public static let secondary = Color.white.opacity(Design.Opacity.accent) - public static let tertiary = Color.white.opacity(Design.Opacity.medium) - public static let disabled = Color.white.opacity(Design.Opacity.light) - public static let placeholder = Color.white.opacity(Design.Opacity.overlay) - public static let inverse = Color.black + public static let primary = Color("TextPrimary") + public static let secondary = Color("TextSecondary") + public static let tertiary = Color("TextTertiary") + public static let disabled = Color("TextDisabled") + public static let placeholder = Color("TextTertiary") + public static let inverse = Color("Background") } // MARK: - Rituals Accent Colors +/// Accent colors using Asset Catalog with light/dark variants. public enum RitualsAccentColors: AccentColorProvider { - public static let primary = Color(red: 0.93, green: 0.55, blue: 0.40) - public static let light = Color(red: 0.98, green: 0.70, blue: 0.55) - public static let dark = Color(red: 0.75, green: 0.38, blue: 0.25) - public static let secondary = Color(red: 0.95, green: 0.90, blue: 0.80) + public static let primary = Color("Accent") + public static let light = Color("AccentLight") + public static let dark = Color("AccentDark") + public static let secondary = Color("AccentSecondary") } // MARK: - Rituals Button Colors +/// Button colors using Asset Catalog with light/dark variants. public enum RitualsButtonColors: ButtonColorProvider { - public static let primaryLight = Color(red: 0.98, green: 0.70, blue: 0.55) - public static let primaryDark = Color(red: 0.75, green: 0.38, blue: 0.25) - public static let secondary = Color.white.opacity(Design.Opacity.subtle) - public static let destructive = Color.red.opacity(Design.Opacity.heavy) - public static let cancelText = Color.white.opacity(Design.Opacity.strong) + public static let primaryLight = Color("AccentLight") + public static let primaryDark = Color("AccentDark") + public static let secondary = Color("Divider") + public static let destructive = Color("Error") + public static let cancelText = Color("TextSecondary") } // MARK: - Rituals Status Colors +/// Status colors using Asset Catalog with light/dark variants. public enum RitualsStatusColors: StatusColorProvider { - public static let success = Color(red: 0.20, green: 0.75, blue: 0.55) - public static let warning = Color(red: 0.95, green: 0.78, blue: 0.45) - public static let error = Color(red: 0.90, green: 0.35, blue: 0.35) - public static let info = Color(red: 0.55, green: 0.72, blue: 0.92) + public static let success = Color("Success") + public static let warning = Color("Warning") + public static let error = Color("Error") + public static let info = Color("Info") } // MARK: - Rituals Border Colors +/// Border colors using Asset Catalog with light/dark variants. public enum RitualsBorderColors: BorderColorProvider { - public static let subtle = Color.white.opacity(Design.Opacity.subtle) - public static let standard = Color.white.opacity(Design.Opacity.hint) - public static let emphasized = Color.white.opacity(Design.Opacity.light) - public static let selected = RitualsAccentColors.primary.opacity(Design.Opacity.medium) + public static let subtle = Color("Divider") + public static let standard = Color("Divider") + public static let emphasized = Color("TextTertiary") + public static let selected = Color("Accent").opacity(Design.Opacity.medium) } // MARK: - Rituals Interactive Colors +/// Interactive colors using Asset Catalog with light/dark variants. public enum RitualsInteractiveColors: InteractiveColorProvider { - public static let selected = RitualsAccentColors.primary.opacity(Design.Opacity.selection) - public static let hover = Color.white.opacity(Design.Opacity.subtle) - public static let pressed = Color.white.opacity(Design.Opacity.hint) - public static let focus = RitualsAccentColors.light + public static let selected = Color("Accent").opacity(Design.Opacity.selection) + public static let hover = Color("Divider") + public static let pressed = Color("TextTertiary").opacity(Design.Opacity.hint) + public static let focus = Color("AccentLight") } // MARK: - Rituals Theme