Add card style option for Home shortcut cards

Adds a Style picker (Plain / Accent / Colorful) to the Customize Home
sheet, shown when the shortcuts layout is Cards. Defaults to Plain.

- Plain: current look (light accent tint + accent border)
- Accent: solid accent fill, white icon/text
- Colorful: solid fill with a fixed color per shortcut type

The filled styles use a Reminders-style layout (icon top-leading, count
top-trailing, title anchored to the bottom) with a subtle gradient sheen
over the fill color. Cards without a meaningful count (Open Link, Remote,
Subscriptions, instance content, media sources) hide the number; Remote
shows its status dot in the top-right slot instead.

Persisted via SettingsKey.homeShortcutCardStyle, mirroring the existing
homeShortcutLayout accessor.
This commit is contained in:
Arkadiusz Fal
2026-05-26 06:43:34 +02:00
parent 5f49f2d022
commit 7a1af02418
8 changed files with 294 additions and 25 deletions

View File

@@ -30,6 +30,26 @@ enum HomeShortcutLayout: String, CaseIterable, Sendable {
}
}
// MARK: - Home Shortcut Card Style
/// Visual style for shortcut cards in the Home view (cards layout only).
enum HomeShortcutCardStyle: String, CaseIterable, Sendable {
/// Current look: light accent tint background with an accent border.
case plain
/// Solid fill in the user's accent color, white icon/text.
case accent
/// Solid fill with a fixed color per shortcut type, white icon/text (Reminders-style).
case colorful
var displayName: LocalizedStringKey {
switch self {
case .plain: return "home.shortcuts.style.plain"
case .accent: return "home.shortcuts.style.accent"
case .colorful: return "home.shortcuts.style.colorful"
}
}
}
// MARK: - Home Section Layout
/// Layout mode for the configurable home sections (Continue Watching, Feed, etc.).
@@ -190,6 +210,42 @@ enum HomeShortcutItem: Codable, Hashable, Identifiable, Sendable {
}
}
/// Fixed color for this shortcut used by the "colorful" card style.
/// Dynamic items (instance content / media sources) derive a stable color
/// from their identifier so multiple items get varied hues.
var cardColor: Color {
switch self {
case .openURL: return .blue
case .remoteControl: return .teal
case .playlists: return .indigo
case .bookmarks: return .pink
case .continueWatching: return .purple
case .history: return .orange
case .downloads: return .green
case .channels: return .red
case .subscriptions: return .cyan
case .mediaSources: return .brown
case .instanceContent(let instanceID, _):
return Self.colorfulPalette[Self.stableIndex(for: instanceID.uuidString, count: Self.colorfulPalette.count)]
case .mediaSource(let sourceID):
return Self.colorfulPalette[Self.stableIndex(for: sourceID.uuidString, count: Self.colorfulPalette.count)]
}
}
/// Palette used to assign stable colors to dynamic shortcut items.
private static let colorfulPalette: [Color] = [
.blue, .red, .orange, .pink, .teal, .green, .indigo, .purple, .cyan, .brown
]
/// Deterministic (launch-stable) hash of a string into a palette index.
private static func stableIndex(for key: String, count: Int) -> Int {
var hash = 5381
for byte in key.utf8 {
hash = (hash &* 33) &+ Int(byte)
}
return abs(hash) % max(count, 1)
}
// MARK: - Codable Implementation
private enum CodingKeys: String, CodingKey {