Files
Reflect/Shared/Protocols/ChartDataBuildable.swift
Trey t bea2d3bbc9 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>
2025-12-30 00:08:01 -06:00

114 lines
3.8 KiB
Swift

//
// ChartDataBuildable.swift
// Feels
//
// Created by Trey Tartt on 1/17/22.
//
import SwiftUI
typealias Year = Int
typealias Month = Int
protocol ChartDataBuildable {
associatedtype ChartType: ChartViewItemBuildable
// [Year: [Month: [View]]
func buildGridData(withData data: [MoodEntryModel]) -> [Year: [Month: [ChartType]]]
}
extension ChartDataBuildable {
public func buildGridData(withData data: [MoodEntryModel]) -> [Year: [Month: [ChartType]]] {
guard let earliestEntry = data.first,
let lastEntry = data.last else { return [:] }
let calendar = Calendar.current
// Pre-group entries by year/month/day in a single pass - O(n) instead of O(n*m)
// Key: "year-month-day" -> entry
var entriesByDate = [String: MoodEntryModel]()
for entry in data {
let components = calendar.dateComponents([.year, .month, .day], from: entry.forDate)
let key = "\(components.year!)-\(components.month!)-\(components.day!)"
entriesByDate[key] = entry
}
let earliestYear = calendar.component(.year, from: earliestEntry.forDate)
let latestYear = calendar.component(.year, from: lastEntry.forDate)
// Cache expensive lookups
let moodTint: MoodTintable.Type = UserDefaultsStore.moodTintable()
let shape = UserDefaultsStore.getCustomBGShape()
var returnData = [Int: [Int: [ChartType]]]()
for year in earliestYear...latestYear {
var allMonths = [Int: [ChartType]]()
for month in 1...12 {
var components = DateComponents()
components.month = month
components.year = year
guard let startDateOfMonth = calendar.date(from: components) else { continue }
allMonths[month] = createViewFor(
year: year,
month: month,
forMonth: startDateOfMonth,
entriesByDate: entriesByDate,
moodTint: moodTint,
shape: shape,
calendar: calendar
)
}
returnData[year] = allMonths
}
return returnData
}
private func createViewFor(
year: Int,
month: Int,
forMonth monthDate: Date,
entriesByDate: [String: MoodEntryModel],
moodTint: MoodTintable.Type,
shape: BGShape,
calendar: Calendar
) -> [ChartType] {
var filledOutArray = [ChartType]()
let range = calendar.range(of: .day, in: .month, for: monthDate)!
let numDays = range.count
for day in 1...numDays {
let key = "\(year)-\(month)-\(day)"
if let item = entriesByDate[key] {
// O(1) dictionary lookup instead of O(n) filter
let view = ChartType(color: moodTint.color(forMood: item.mood),
weekDay: Int(item.weekDay),
shape: shape)
filledOutArray.append(view)
} else {
let thisDate = calendar.date(bySetting: .day, value: day, of: monthDate)!
let view = ChartType(color: Mood.placeholder.color,
weekDay: calendar.component(.weekday, from: thisDate),
shape: shape)
filledOutArray.append(view)
}
}
for _ in filledOutArray.count...32 {
let view = ChartType(color: Mood.placeholder.color,
weekDay: 2,
shape: shape)
filledOutArray.append(view)
}
return filledOutArray
}
}
struct DayChartViewChartBuilder: ChartDataBuildable {
typealias ChartType = DayChartView
}