- Update NeonMoodTint to use synthwave colors matching Neon voting style (cyan, lime, yellow, orange, magenta) - Replace text label with 5 color circles in theme preview Colors row - Remove unused textColor customization code and picker views - Add .id(moodTint) to Month/Year views for color refresh - Clean up various unused color-related code 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
354 lines
11 KiB
Swift
354 lines
11 KiB
Swift
//
|
|
// MoodTintable.swift
|
|
// Feels (iOS)
|
|
//
|
|
// Created by Trey Tartt on 2/19/22.
|
|
//
|
|
|
|
import SwiftUI
|
|
|
|
protocol MoodTintable {
|
|
static func color(forMood mood: Mood) -> Color
|
|
static func secondary(forMood mood: Mood) -> Color
|
|
}
|
|
|
|
enum MoodTints: Int, CaseIterable {
|
|
case Default
|
|
case Neon
|
|
case Pastel
|
|
case Custom
|
|
|
|
static var defaultOptions: [MoodTints] {
|
|
return [Default, Neon, Pastel]
|
|
}
|
|
|
|
func color(forMood mood: Mood) -> Color {
|
|
switch self {
|
|
case .Default:
|
|
return DefaultMoodTint.color(forMood: mood)
|
|
case .Custom:
|
|
return CustomMoodTint.color(forMood: mood)
|
|
case .Neon:
|
|
return NeonMoodTint.color(forMood: mood)
|
|
case .Pastel:
|
|
return PastelTint.color(forMood: mood)
|
|
}
|
|
}
|
|
|
|
func secondary(forMood mood: Mood) -> Color {
|
|
switch self {
|
|
case .Default:
|
|
return DefaultMoodTint.secondary(forMood: mood)
|
|
case .Custom:
|
|
return CustomMoodTint.secondary(forMood: mood)
|
|
case .Neon:
|
|
return NeonMoodTint.secondary(forMood: mood)
|
|
case .Pastel:
|
|
return PastelTint.secondary(forMood: mood)
|
|
}
|
|
}
|
|
|
|
/// Returns black or white text color based on the mood's background luminance
|
|
func contrastingTextColor(forMood mood: Mood) -> Color {
|
|
color(forMood: mood).contrastingTextColor
|
|
}
|
|
|
|
var moodTints: MoodTintable.Type {
|
|
switch self {
|
|
case .Default:
|
|
return DefaultMoodTint.self
|
|
case .Custom:
|
|
return CustomMoodTint.self
|
|
case .Neon:
|
|
return NeonMoodTint.self
|
|
case .Pastel:
|
|
return PastelTint.self
|
|
}
|
|
}
|
|
}
|
|
|
|
final class SavedMoodTint: NSObject, ObservableObject, Codable {
|
|
@Published var colorOne: Color
|
|
@Published var colorTwo: Color
|
|
@Published var colorThree: Color
|
|
@Published var colorFour: Color
|
|
@Published var colorFive: Color
|
|
|
|
override init() {
|
|
colorOne = Color(hex: "a92b26")
|
|
colorTwo = Color(hex: "a92b26")
|
|
colorThree = Color(hex: "a92b26")
|
|
colorFour = Color(hex: "a92b26")
|
|
colorFive = Color(hex: "a92b26")
|
|
}
|
|
|
|
enum CodingKeys: CodingKey {
|
|
case colorOne, colorTwo, colorThree, colorFour, colorFive
|
|
}
|
|
|
|
init(from decoder: Decoder) throws {
|
|
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
colorOne = try container.decode(Color.self, forKey: .colorOne)
|
|
colorTwo = try container.decode(Color.self, forKey: .colorTwo)
|
|
colorThree = try container.decode(Color.self, forKey: .colorThree)
|
|
colorFour = try container.decode(Color.self, forKey: .colorFour)
|
|
colorFive = try container.decode(Color.self, forKey: .colorFive)
|
|
}
|
|
|
|
func encode(to encoder: Encoder) throws {
|
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
try container.encode(colorOne, forKey: .colorOne)
|
|
try container.encode(colorTwo, forKey: .colorTwo)
|
|
try container.encode(colorThree, forKey: .colorThree)
|
|
try container.encode(colorFour, forKey: .colorFour)
|
|
try container.encode(colorFive, forKey: .colorFive)
|
|
}
|
|
}
|
|
|
|
final class CustomMoodTint: MoodTintable {
|
|
static func color(forMood mood: Mood) -> Color {
|
|
switch mood {
|
|
case .horrible:
|
|
return UserDefaultsStore.getCustomMoodTint().colorFive
|
|
case .bad:
|
|
return UserDefaultsStore.getCustomMoodTint().colorFour
|
|
case .average:
|
|
return UserDefaultsStore.getCustomMoodTint().colorThree
|
|
case .good:
|
|
return UserDefaultsStore.getCustomMoodTint().colorTwo
|
|
case .great:
|
|
return UserDefaultsStore.getCustomMoodTint().colorOne
|
|
case .missing:
|
|
return Color(uiColor: UIColor.lightGray)
|
|
case .placeholder:
|
|
return Color(uiColor: UIColor.lightGray)
|
|
}
|
|
}
|
|
|
|
static func secondary(forMood mood: Mood) -> Color {
|
|
switch mood {
|
|
case .horrible:
|
|
return UserDefaultsStore.getCustomMoodTint().colorFive.darker(by: 40)
|
|
case .bad:
|
|
return UserDefaultsStore.getCustomMoodTint().colorFour.darker(by: 40)
|
|
case .average:
|
|
return UserDefaultsStore.getCustomMoodTint().colorThree.darker(by: 40)
|
|
case .good:
|
|
return UserDefaultsStore.getCustomMoodTint().colorTwo.darker(by: 40)
|
|
case .great:
|
|
return UserDefaultsStore.getCustomMoodTint().colorOne.darker(by: 40)
|
|
case .missing:
|
|
return Color(uiColor: UIColor.lightGray).darker(by: 40)
|
|
case .placeholder:
|
|
return Color(uiColor: UIColor.lightGray).darker(by: 40)
|
|
}
|
|
}
|
|
}
|
|
|
|
final class DefaultMoodTint: MoodTintable {
|
|
static func color(forMood mood: Mood) -> Color {
|
|
switch mood {
|
|
case .horrible:
|
|
return Color(hex: "ff453a")
|
|
case .bad:
|
|
return Color(hex: "ff9e0b")
|
|
case .average:
|
|
return Color(hex: "0b84ff")
|
|
case .good:
|
|
return Color(hex: "ffd709")
|
|
case .great:
|
|
return Color(hex: "31d158")
|
|
case .missing:
|
|
return Color(uiColor: UIColor.systemGray2)
|
|
case .placeholder:
|
|
return Color(uiColor: UIColor.systemGray2)
|
|
}
|
|
}
|
|
|
|
static func secondary(forMood mood: Mood) -> Color {
|
|
switch mood {
|
|
case .horrible:
|
|
return Color(hex: "a92b26")
|
|
case .bad:
|
|
return Color(hex: "a06407")
|
|
case .average:
|
|
return Color(hex: "074f9a")
|
|
case .good:
|
|
return Color(hex: "9d8405")
|
|
case .great:
|
|
return Color(hex: "208939")
|
|
case .missing:
|
|
return Color(uiColor: UIColor.label)
|
|
case .placeholder:
|
|
return Color(uiColor: UIColor.label)
|
|
}
|
|
}
|
|
}
|
|
|
|
final class AllRedMoodTint: MoodTintable {
|
|
static func color(forMood mood: Mood) -> Color {
|
|
switch mood {
|
|
case .horrible:
|
|
return .red
|
|
case .bad:
|
|
return .red
|
|
case .average:
|
|
return .red
|
|
case .good:
|
|
return .red
|
|
case .great:
|
|
return .red
|
|
case .missing:
|
|
return Color(uiColor: UIColor.systemGray2)
|
|
case .placeholder:
|
|
return Color(uiColor: UIColor.systemGray2)
|
|
}
|
|
}
|
|
|
|
static func secondary(forMood mood: Mood) -> Color {
|
|
switch mood {
|
|
case .horrible:
|
|
return .red
|
|
case .bad:
|
|
return .red
|
|
case .average:
|
|
return .red
|
|
case .good:
|
|
return .red
|
|
case .great:
|
|
return .red
|
|
case .missing:
|
|
return Color(uiColor: UIColor.label)
|
|
case .placeholder:
|
|
return Color(uiColor: UIColor.label)
|
|
}
|
|
}
|
|
}
|
|
|
|
final class NeonMoodTint: MoodTintable {
|
|
// Synthwave color palette matching the Neon voting style
|
|
private static let neonCyan = Color(red: 0.0, green: 1.0, blue: 0.82)
|
|
private static let neonLime = Color(red: 0.2, green: 1.0, blue: 0.6)
|
|
private static let neonYellow = Color(red: 1.0, green: 0.9, blue: 0.0)
|
|
private static let neonOrange = Color(red: 1.0, green: 0.5, blue: 0.0)
|
|
private static let neonMagenta = Color(red: 1.0, green: 0.0, blue: 0.8)
|
|
|
|
static func color(forMood mood: Mood) -> Color {
|
|
switch mood {
|
|
case .horrible:
|
|
return neonMagenta
|
|
case .bad:
|
|
return neonOrange
|
|
case .average:
|
|
return neonYellow
|
|
case .good:
|
|
return neonLime
|
|
case .great:
|
|
return neonCyan
|
|
case .missing:
|
|
return Color(uiColor: UIColor.systemGray2)
|
|
case .placeholder:
|
|
return Color(uiColor: UIColor.systemGray2)
|
|
}
|
|
}
|
|
|
|
static func secondary(forMood mood: Mood) -> Color {
|
|
switch mood {
|
|
case .horrible:
|
|
return neonMagenta.opacity(0.6)
|
|
case .bad:
|
|
return neonOrange.opacity(0.6)
|
|
case .average:
|
|
return neonYellow.opacity(0.6)
|
|
case .good:
|
|
return neonLime.opacity(0.6)
|
|
case .great:
|
|
return neonCyan.opacity(0.6)
|
|
case .missing:
|
|
return Color(uiColor: UIColor.label)
|
|
case .placeholder:
|
|
return Color(uiColor: UIColor.label)
|
|
}
|
|
}
|
|
}
|
|
|
|
final class MonoChromeTint: MoodTintable {
|
|
static func color(forMood mood: Mood) -> Color {
|
|
switch mood {
|
|
case .horrible:
|
|
return Color(hex: "#000000")
|
|
case .bad:
|
|
return Color(hex: "#47474a")
|
|
case .average:
|
|
return Color(hex: "#7b7b81")
|
|
case .good:
|
|
return Color(hex: "#a3a3ab")
|
|
case .great:
|
|
return Color(hex: "#c2c1cb")
|
|
case .missing:
|
|
return Color(hex: "#ff0000")
|
|
case .placeholder:
|
|
return Color(hex: "#efeffb")
|
|
}
|
|
}
|
|
|
|
static func secondary(forMood mood: Mood) -> Color {
|
|
switch mood {
|
|
case .horrible:
|
|
return .black
|
|
case .bad:
|
|
return Color(uiColor: UIColor.systemGray)
|
|
case .average:
|
|
return Color(uiColor: UIColor.systemGray)
|
|
case .good:
|
|
return Color(uiColor: UIColor.systemGray2)
|
|
case .great:
|
|
return Color(uiColor: UIColor.systemGray3)
|
|
case .missing:
|
|
return Color(uiColor: UIColor.systemGray2)
|
|
case .placeholder:
|
|
return Color(uiColor: UIColor.systemGray4)
|
|
}
|
|
}
|
|
}
|
|
|
|
final class PastelTint: MoodTintable {
|
|
static func color(forMood mood: Mood) -> Color {
|
|
switch mood {
|
|
case .horrible:
|
|
return Color(hex: "#FF6961")
|
|
case .bad:
|
|
return Color(hex: "#ffb347")
|
|
case .average:
|
|
return Color(hex: "#A7C7E7")
|
|
case .good:
|
|
return Color(hex: "#fdfd96")
|
|
case .great:
|
|
return Color(hex: "#C1E1C1")
|
|
case .missing:
|
|
return Color(uiColor: UIColor.systemGray2)
|
|
case .placeholder:
|
|
return Color(uiColor: UIColor.systemGray2)
|
|
}
|
|
}
|
|
|
|
static func secondary(forMood mood: Mood) -> Color {
|
|
switch mood {
|
|
case .horrible:
|
|
return Color(hex: "#893734")
|
|
case .bad:
|
|
return Color(hex: "#855d28")
|
|
case .average:
|
|
return Color(hex: "#5d6e83")
|
|
case .good:
|
|
return Color(hex: "#7f804f")
|
|
case .great:
|
|
return Color(hex: "#6b7e6d")
|
|
case .missing:
|
|
return Color(uiColor: UIColor.label)
|
|
case .placeholder:
|
|
return Color(uiColor: UIColor.label)
|
|
}
|
|
}
|
|
}
|