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:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user