Complete rename across all bundle IDs, App Groups, CloudKit containers, StoreKit product IDs, data store filenames, URL schemes, logger subsystems, Swift identifiers, user-facing strings (7 languages), file names, directory names, Xcode project, schemes, assets, and documentation. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
298 lines
11 KiB
Swift
298 lines
11 KiB
Swift
//
|
|
// AppTheme.swift
|
|
// Reflect (iOS)
|
|
//
|
|
// Created by Claude Code on 12/26/24.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
/// Cohesive themes that bundle colors, icons, entry styles, and voting layouts
|
|
/// into unified aesthetic experiences. Each theme is designed around a specific
|
|
/// emotional resonance and target user persona.
|
|
enum AppTheme: Int, CaseIterable, Identifiable {
|
|
case zenGarden = 0
|
|
case synthwave = 1
|
|
case celestial = 2
|
|
case editorial = 3
|
|
case mixtape = 4
|
|
case bloom = 5
|
|
case heartfelt = 6
|
|
case minimal = 7
|
|
case luxe = 8
|
|
case forecast = 9
|
|
case playful = 10
|
|
case journal = 11
|
|
|
|
var id: Int { rawValue }
|
|
|
|
// MARK: - Display Properties
|
|
|
|
var name: String {
|
|
switch self {
|
|
case .zenGarden: return "Zen Garden"
|
|
case .synthwave: return "Synthwave"
|
|
case .celestial: return "Celestial"
|
|
case .editorial: return "Editorial"
|
|
case .mixtape: return "Mixtape"
|
|
case .bloom: return "Bloom"
|
|
case .heartfelt: return "Heartfelt"
|
|
case .minimal: return "Minimal"
|
|
case .luxe: return "Luxe"
|
|
case .forecast: return "Forecast"
|
|
case .playful: return "Playful"
|
|
case .journal: return "Journal"
|
|
}
|
|
}
|
|
|
|
var tagline: String {
|
|
switch self {
|
|
case .zenGarden: return "Meditative calm"
|
|
case .synthwave: return "Retro-futuristic energy"
|
|
case .celestial: return "Cosmic wisdom"
|
|
case .editorial: return "Literary elegance"
|
|
case .mixtape: return "Analog nostalgia"
|
|
case .bloom: return "Growth & healing"
|
|
case .heartfelt: return "Emotional depth"
|
|
case .minimal: return "Pure simplicity"
|
|
case .luxe: return "Premium refinement"
|
|
case .forecast: return "Mood as weather"
|
|
case .playful: return "Fun & vibrant"
|
|
case .journal: return "Personal diary"
|
|
}
|
|
}
|
|
|
|
var description: String {
|
|
switch self {
|
|
case .zenGarden:
|
|
return "Japanese minimalism meets mindful awareness. Soft pastels, organic growth icons, clean entries, and contemplative vertical voting."
|
|
case .synthwave:
|
|
return "80s arcade aesthetic with neon glow. Electric colors, cosmic icons, grid backgrounds, and equalizer-bar voting."
|
|
case .celestial:
|
|
return "Journey from void to starlight. Moon phases, orbital layouts, and planetary arrangements for cosmic mood tracking."
|
|
case .editorial:
|
|
return "Magazine-quality typography and layout. Clean icons, pull-quote entries, and sophisticated presentation."
|
|
case .mixtape:
|
|
return "Cassette culture and analog warmth. Tape reels, track numbers, and the tactile feel of pressing play."
|
|
case .bloom:
|
|
return "From wilted flower to full bloom. Atmospheric glowing entries, organic icons, and the gentle metaphor of growth."
|
|
case .heartfelt:
|
|
return "Unashamed emotional expression. Heart icons from broken to sparkling, bold colors, intuitive selection."
|
|
case .minimal:
|
|
return "Only the essentials. Clean typography, flat design, and zero distractions."
|
|
case .luxe:
|
|
return "Liquid glass and premium materials. Cutting-edge iOS design language for the discerning user."
|
|
case .forecast:
|
|
return "Your mood is the weather. Storm to sunshine icons, colorful bubble entries, and natural intuition."
|
|
case .playful:
|
|
return "Life's too short to be serious. Vibrant neons, familiar emoji, and game-like interaction."
|
|
case .journal:
|
|
return "Like writing in a physical diary. Stacked paper notes, handwritten feel, and intimate reflection."
|
|
}
|
|
}
|
|
|
|
var emoji: String {
|
|
switch self {
|
|
case .zenGarden: return "🧘"
|
|
case .synthwave: return "🌆"
|
|
case .celestial: return "✨"
|
|
case .editorial: return "📰"
|
|
case .mixtape: return "📼"
|
|
case .bloom: return "🌸"
|
|
case .heartfelt: return "💖"
|
|
case .minimal: return "◽"
|
|
case .luxe: return "💎"
|
|
case .forecast: return "🌦️"
|
|
case .playful: return "🎮"
|
|
case .journal: return "📒"
|
|
}
|
|
}
|
|
|
|
// MARK: - Theme Components
|
|
|
|
var colorTint: MoodTints {
|
|
switch self {
|
|
case .zenGarden: return .Pastel
|
|
case .synthwave: return .Neon
|
|
case .celestial: return .Default
|
|
case .editorial: return .Pastel
|
|
case .mixtape: return .Default
|
|
case .bloom: return .Pastel
|
|
case .heartfelt: return .Pastel
|
|
case .minimal: return .Pastel
|
|
case .luxe: return .Default
|
|
case .forecast: return .Default
|
|
case .playful: return .Neon
|
|
case .journal: return .Default
|
|
}
|
|
}
|
|
|
|
var iconPack: MoodImages {
|
|
switch self {
|
|
case .zenGarden: return .Garden
|
|
case .synthwave: return .Cosmic
|
|
case .celestial: return .Cosmic
|
|
case .editorial: return .FontAwesome
|
|
case .mixtape: return .Emoji
|
|
case .bloom: return .Garden
|
|
case .heartfelt: return .Hearts
|
|
case .minimal: return .FontAwesome
|
|
case .luxe: return .Cosmic
|
|
case .forecast: return .Weather
|
|
case .playful: return .Emoji
|
|
case .journal: return .FontAwesome
|
|
}
|
|
}
|
|
|
|
var entryStyle: DayViewStyle {
|
|
switch self {
|
|
case .zenGarden: return .minimal
|
|
case .synthwave: return .neon
|
|
case .celestial: return .orbit
|
|
case .editorial: return .chronicle
|
|
case .mixtape: return .tape
|
|
case .bloom: return .aura
|
|
case .heartfelt: return .bubble
|
|
case .minimal: return .minimal
|
|
case .luxe: return .glass
|
|
case .forecast: return .bubble
|
|
case .playful: return .pattern
|
|
case .journal: return .stack
|
|
}
|
|
}
|
|
|
|
var votingLayout: VotingLayoutStyle {
|
|
switch self {
|
|
case .zenGarden: return .stacked
|
|
case .synthwave: return .neon
|
|
case .celestial: return .orbit
|
|
case .editorial: return .horizontal
|
|
case .mixtape: return .cards
|
|
case .bloom: return .aura
|
|
case .heartfelt: return .horizontal
|
|
case .minimal: return .horizontal
|
|
case .luxe: return .aura
|
|
case .forecast: return .horizontal
|
|
case .playful: return .cards
|
|
case .journal: return .stacked
|
|
}
|
|
}
|
|
|
|
var paywallStyle: PaywallStyle {
|
|
switch self {
|
|
case .zenGarden: return .zen
|
|
case .synthwave: return .neon
|
|
case .celestial: return .celestial
|
|
case .editorial: return .editorial
|
|
case .mixtape: return .mixtape
|
|
case .bloom: return .garden
|
|
case .heartfelt: return .heartfelt
|
|
case .minimal: return .minimal
|
|
case .luxe: return .luxe
|
|
case .forecast: return .forecast
|
|
case .playful: return .playful
|
|
case .journal: return .journal
|
|
}
|
|
}
|
|
|
|
var lockScreenStyle: LockScreenStyle {
|
|
switch self {
|
|
case .zenGarden: return .zen
|
|
case .synthwave: return .neon
|
|
case .celestial: return .celestial
|
|
case .editorial: return .editorial
|
|
case .mixtape: return .mixtape
|
|
case .bloom: return .bloom
|
|
case .heartfelt: return .heartfelt
|
|
case .minimal: return .minimal
|
|
case .luxe: return .luxe
|
|
case .forecast: return .forecast
|
|
case .playful: return .playful
|
|
case .journal: return .journal
|
|
}
|
|
}
|
|
|
|
// MARK: - Preview Colors (for theme picker UI)
|
|
|
|
var previewColors: [Color] {
|
|
switch self {
|
|
case .zenGarden:
|
|
return [Color(hex: "#C1E1C1"), Color(hex: "#A7C7E7"), Color(hex: "#fdfd96")]
|
|
case .synthwave:
|
|
return [Color(red: 0, green: 1, blue: 0.82), Color(red: 1, green: 0, blue: 0.8), Color(hex: "#050510")]
|
|
case .celestial:
|
|
return [Color(hex: "#0b84ff"), Color(hex: "#31d158"), Color(hex: "#1a1a2e")]
|
|
case .editorial:
|
|
return [Color(hex: "#A7C7E7"), Color(hex: "#2c2c2c"), Color(hex: "#f5f5f5")]
|
|
case .mixtape:
|
|
return [Color(hex: "#8B4513"), Color(hex: "#D2691E"), Color(hex: "#2c2c2c")]
|
|
case .bloom:
|
|
return [Color(hex: "#C1E1C1"), Color(hex: "#ffb347"), Color(hex: "#FF6961")]
|
|
case .heartfelt:
|
|
return [Color(hex: "#FF6961"), Color(hex: "#ffb347"), Color(hex: "#C1E1C1")]
|
|
case .minimal:
|
|
return [Color(hex: "#A7C7E7"), Color(hex: "#e0e0e0"), Color(hex: "#f8f8f8")]
|
|
case .luxe:
|
|
return [Color(hex: "#0b84ff"), Color(hex: "#31d158"), Color.white.opacity(0.8)]
|
|
case .forecast:
|
|
return [Color(hex: "#0b84ff"), Color(hex: "#ffd709"), Color(hex: "#ff453a")]
|
|
case .playful:
|
|
return [Color(hex: "#39FF14"), Color(hex: "#FFF01F"), Color(hex: "#FF5F1F")]
|
|
case .journal:
|
|
return [Color(hex: "#D2B48C"), Color(hex: "#8B4513"), Color(hex: "#FFFEF0")]
|
|
}
|
|
}
|
|
|
|
// MARK: - Apply Theme
|
|
|
|
/// Applies all theme settings to UserDefaults
|
|
func apply() {
|
|
// Set color tint
|
|
GroupUserDefaults.groupDefaults.set(colorTint.rawValue, forKey: UserDefaultsStore.Keys.moodTint.rawValue)
|
|
|
|
// Set icon pack
|
|
GroupUserDefaults.groupDefaults.set(iconPack.rawValue, forKey: UserDefaultsStore.Keys.moodImages.rawValue)
|
|
|
|
// Set entry style
|
|
GroupUserDefaults.groupDefaults.set(entryStyle.rawValue, forKey: UserDefaultsStore.Keys.dayViewStyle.rawValue)
|
|
|
|
// Set voting layout
|
|
GroupUserDefaults.groupDefaults.set(votingLayout.rawValue, forKey: UserDefaultsStore.Keys.votingLayoutStyle.rawValue)
|
|
|
|
// Set paywall style
|
|
GroupUserDefaults.groupDefaults.set(paywallStyle.rawValue, forKey: UserDefaultsStore.Keys.paywallStyle.rawValue)
|
|
|
|
// Set lock screen style
|
|
GroupUserDefaults.groupDefaults.set(lockScreenStyle.rawValue, forKey: UserDefaultsStore.Keys.lockScreenStyle.rawValue)
|
|
|
|
// Log the theme change
|
|
Task { @MainActor in
|
|
AnalyticsManager.shared.track(.themeApplied(themeName: name))
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - Theme Categories for Browsing
|
|
|
|
extension AppTheme {
|
|
enum Category: String, CaseIterable {
|
|
case calm = "Calm & Mindful"
|
|
case energetic = "Energetic & Bold"
|
|
case sophisticated = "Sophisticated"
|
|
case expressive = "Expressive"
|
|
|
|
var themes: [AppTheme] {
|
|
switch self {
|
|
case .calm:
|
|
return [.zenGarden, .minimal, .bloom]
|
|
case .energetic:
|
|
return [.synthwave, .playful, .mixtape]
|
|
case .sophisticated:
|
|
return [.celestial, .editorial, .luxe]
|
|
case .expressive:
|
|
return [.heartfelt, .forecast, .journal]
|
|
}
|
|
}
|
|
}
|
|
}
|