Add custom accent color with system color picker

Add a Custom swatch to the appearance settings accent color grid,
backed by a hex value stored in settings (synced via iCloud like the
rest). iOS uses the native ColorPicker wheel; macOS uses a circular
swatch that opens NSColorPanel, since the SwiftUI color well looks out
of place among the circles. All accent consumers now read the resolved
color through SettingsManager.resolvedAccentColor.

The indigo preset is retired from the grid but kept in the enum, so
users who selected it keep their color until they pick another one.

Claude-Session: https://claude.ai/code/session_0154KH8RAVAvm6iVanhmoW8o
This commit is contained in:
Arkadiusz Fal
2026-07-04 23:57:59 +02:00
parent f5b86effd3
commit b47888fe04
25 changed files with 188 additions and 21 deletions

View File

@@ -13,6 +13,7 @@ enum SettingsKey: String, CaseIterable {
// General
case theme
case accentColor
case customAccentColor
case showWatchedCheckmark
// Playback

View File

@@ -6,6 +6,7 @@
//
import Foundation
import SwiftUI
#if os(iOS)
import UIKit
#elseif os(macOS)
@@ -37,6 +38,23 @@ extension SettingsManager {
}
}
var customAccentColor: Color {
get {
let hex = _customAccentColor ?? string(for: .customAccentColor) ?? ""
return Color(hex: hex) ?? AccentColor.default.color
}
set {
let hex = newValue.toHexString()
_customAccentColor = hex
set(hex, for: .customAccentColor)
}
}
/// The effective accent color, resolving `.custom` to the user-picked value.
var resolvedAccentColor: Color {
accentColor == .custom ? customAccentColor : accentColor.color
}
// MARK: - App Icon Settings
var appIcon: AppIcon {

View File

@@ -35,10 +35,20 @@ enum AccentColor: String, CaseIterable, Codable {
case blue
case purple
case indigo
case custom
/// Fixed swatches shown in the settings grid; `.custom` is rendered
/// separately as a color picker, and `.indigo` is retired from the grid
/// but still resolves for users who selected it before it was removed.
static var presets: [AccentColor] {
allCases.filter { $0 != .custom && $0 != .indigo }
}
/// The color for `.custom` lives in settings storage resolve through
/// `SettingsManager.resolvedAccentColor` instead of this property.
var color: Color {
switch self {
case .default: return .blue // System default accent color
case .default, .custom: return .blue // System default accent color
case .red: return .red
case .pink: return .pink
case .orange: return .orange

View File

@@ -28,6 +28,7 @@ final class SettingsManager {
// Theme
var _theme: AppTheme?
var _accentColor: AccentColor?
var _customAccentColor: String?
var _showWatchedCheckmark: Bool?
// Playback
@@ -417,6 +418,7 @@ final class SettingsManager {
func clearCache() {
_theme = nil
_accentColor = nil
_customAccentColor = nil
_showWatchedCheckmark = nil
_preferredQuality = nil
_cellularQuality = nil