Update Neon colors and show color circles in theme picker

- 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>
This commit is contained in:
Trey t
2025-12-30 00:08:01 -06:00
parent 51c5777c03
commit bea2d3bbc9
58 changed files with 1142 additions and 967 deletions

View File

@@ -58,9 +58,11 @@ class Random {
return newValue
}
/// Cached month symbols to avoid creating DateFormatter repeatedly
private static let monthSymbols: [String] = DateFormatter().monthSymbols
static func monthName(fromMonthInt: Int) -> String {
let monthName = DateFormatter().monthSymbols[fromMonthInt-1]
return monthName
return monthSymbols[fromMonthInt-1]
}
static var existingDayFormat = [NSNumber: String]()
@@ -165,7 +167,15 @@ extension Color {
}
extension String {
/// Cache for rendered emoji images to avoid expensive re-rendering
private static var textToImageCache = [String: UIImage]()
func textToImage() -> UIImage? {
// Return cached image if available
if let cached = Self.textToImageCache[self] {
return cached
}
let nsString = (self as NSString)
let font = UIFont.systemFont(ofSize: 100) // you can change your font size here
let stringAttributes = [NSAttributedString.Key.font: font]
@@ -178,7 +188,12 @@ extension String {
let image = UIGraphicsGetImageFromCurrentImageContext() // create image from context
UIGraphicsEndImageContext() // end image context
return image ?? UIImage()
let result = image ?? UIImage()
// Cache the rendered image
Self.textToImageCache[self] = result
return result
}
}
@@ -218,6 +233,179 @@ extension UIColor {
}
#endif
// MARK: - Date Formatting Cache
/// High-performance date formatting cache to eliminate repeated ICU Calendar operations.
/// Caches formatted date strings keyed by (date's day start, format type).
final class DateFormattingCache {
static let shared = DateFormattingCache()
enum Format: Int {
case day // "15"
case weekdayWide // "Monday"
case weekdayAbbreviated // "Mon"
case weekdayWideDay // "Monday 15"
case monthWide // "January"
case monthAbbreviated // "Jan"
case monthAbbreviatedDay // "Jan 15"
case monthAbbreviatedYear // "Jan 2025"
case monthWideYear // "January 2025"
case weekdayAbbrevMonthAbbrev // "Mon Jan"
case weekdayWideMonthAbbrev // "Monday Jan"
case yearMonthDayDigits // "2025/01/15"
case dateMedium // "Jan 15, 2025" (dateStyle = .medium)
case dateFull // "Monday, January 15, 2025" (dateStyle = .full)
}
private var cache = [Int: [Format: String]]()
private let calendar = Calendar.current
// Reusable formatters (creating DateFormatter is expensive)
private lazy var dayFormatter: DateFormatter = {
let f = DateFormatter()
f.dateFormat = "d"
return f
}()
private lazy var weekdayWideFormatter: DateFormatter = {
let f = DateFormatter()
f.dateFormat = "EEEE"
return f
}()
private lazy var weekdayAbbrevFormatter: DateFormatter = {
let f = DateFormatter()
f.dateFormat = "EEE"
return f
}()
private lazy var weekdayWideDayFormatter: DateFormatter = {
let f = DateFormatter()
f.dateFormat = "EEEE d"
return f
}()
private lazy var monthWideFormatter: DateFormatter = {
let f = DateFormatter()
f.dateFormat = "MMMM"
return f
}()
private lazy var monthAbbrevFormatter: DateFormatter = {
let f = DateFormatter()
f.dateFormat = "MMM"
return f
}()
private lazy var monthAbbrevDayFormatter: DateFormatter = {
let f = DateFormatter()
f.dateFormat = "MMM d"
return f
}()
private lazy var monthAbbrevYearFormatter: DateFormatter = {
let f = DateFormatter()
f.dateFormat = "MMM yyyy"
return f
}()
private lazy var monthWideYearFormatter: DateFormatter = {
let f = DateFormatter()
f.dateFormat = "MMMM yyyy"
return f
}()
private lazy var weekdayAbbrevMonthAbbrevFormatter: DateFormatter = {
let f = DateFormatter()
f.dateFormat = "EEE MMM"
return f
}()
private lazy var weekdayWideMonthAbbrevFormatter: DateFormatter = {
let f = DateFormatter()
f.dateFormat = "EEEE MMM"
return f
}()
private lazy var yearMonthDayDigitsFormatter: DateFormatter = {
let f = DateFormatter()
f.dateFormat = "yyyy/MM/dd"
return f
}()
private lazy var dateMediumFormatter: DateFormatter = {
let f = DateFormatter()
f.dateStyle = .medium
return f
}()
private lazy var dateFullFormatter: DateFormatter = {
let f = DateFormatter()
f.dateStyle = .full
return f
}()
private init() {}
/// Get cached formatted string for a date
func string(for date: Date, format: Format) -> String {
let dayKey = dayIdentifier(for: date)
// Check cache
if let formatCache = cache[dayKey], let cached = formatCache[format] {
return cached
}
// Format and cache
let formatted = formatDate(date, format: format)
if cache[dayKey] == nil {
cache[dayKey] = [:]
}
cache[dayKey]?[format] = formatted
return formatted
}
private func dayIdentifier(for date: Date) -> Int {
// Use days since reference date as unique key
Int(calendar.startOfDay(for: date).timeIntervalSinceReferenceDate / 86400)
}
private func formatDate(_ date: Date, format: Format) -> String {
switch format {
case .day:
return dayFormatter.string(from: date)
case .weekdayWide:
return weekdayWideFormatter.string(from: date)
case .weekdayAbbreviated:
return weekdayAbbrevFormatter.string(from: date)
case .weekdayWideDay:
return weekdayWideDayFormatter.string(from: date)
case .monthWide:
return monthWideFormatter.string(from: date)
case .monthAbbreviated:
return monthAbbrevFormatter.string(from: date)
case .monthAbbreviatedDay:
return monthAbbrevDayFormatter.string(from: date)
case .monthAbbreviatedYear:
return monthAbbrevYearFormatter.string(from: date)
case .monthWideYear:
return monthWideYearFormatter.string(from: date)
case .weekdayAbbrevMonthAbbrev:
return weekdayAbbrevMonthAbbrevFormatter.string(from: date)
case .weekdayWideMonthAbbrev:
return weekdayWideMonthAbbrevFormatter.string(from: date)
case .yearMonthDayDigits:
return yearMonthDayDigitsFormatter.string(from: date)
case .dateMedium:
return dateMediumFormatter.string(from: date)
case .dateFull:
return dateFullFormatter.string(from: date)
}
}
}
extension Bundle {
var appName: String {
return infoDictionary?["CFBundleName"] as! String