// // 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: [MoodEntry]) -> [Year: [Month: [ChartType]]] } extension ChartDataBuildable { public func buildGridData(withData data: [MoodEntry]) -> [Year: [Month: [ChartType]]] { var returnData = [Int: [Int: [ChartType]]]() if let earliestEntry = data.first, let lastEntry = data.last { let calendar = Calendar.current let components = calendar.dateComponents([.year], from: earliestEntry.forDate!) let earliestYear = components.year! let latestComponents = calendar.dateComponents([.year], from: lastEntry.forDate!) let latestYear = latestComponents.year! for year in earliestYear...latestYear { var allMonths = [Int: [ChartType]]() // add back in if months header has leading (-1, ""), // and add back gridItem // var dayViews = [DayChartView]() // for day in 0...32 { // let view = DayChartView(color: Mood.missing.color, // weekDay: 2, // viewType: .text(String(day+1))) // dayViews.append(view) // } // allMonths[0] = dayViews for month in (1...12) { var components = DateComponents() components.month = month components.year = year let startDateOfMonth = Calendar.current.date(from: components)! let items = data.filter({ entry in let components = calendar.dateComponents([.month, .year], from: startDateOfMonth) let entryComponents = calendar.dateComponents([.month, .year], from: entry.forDate!) return (components.month == entryComponents.month && components.year == entryComponents.year) }) allMonths[month] = createViewFor(monthEntries: items, forMonth: startDateOfMonth) } returnData[year] = allMonths } } return returnData } private func createViewFor(monthEntries: [MoodEntry], forMonth month: Date) -> [ChartType] { var filledOutArray = [ChartType]() let calendar = Calendar.current let range = calendar.range(of: .day, in: .month, for: month)! let numDays = range.count for day in 1...numDays { if let item = monthEntries.filter({ entry in let components = calendar.dateComponents([.day], from: entry.forDate!) let date = components.day return day == date }).first { let moodTint: MoodTintable.Type = UserDefaultsStore.moodTintable() let view = ChartType(color: moodTint.color(forMood: item.mood), weekDay: Int(item.weekDay), viewType: .square) filledOutArray.append(view) } else { let thisDate = Calendar.current.date(bySetting: .day, value: day, of: month)! let view = ChartType(color: Mood.placeholder.color, weekDay: Calendar.current.component(.weekday, from: thisDate), viewType: .square) filledOutArray.append(view) } } for _ in filledOutArray.count...32 { let view = ChartType(color: Mood.placeholder.color, weekDay: 2, viewType: .cicle) filledOutArray.append(view) } return filledOutArray } } struct DayChartViewChartBuilder: ChartDataBuildable { typealias ChartType = DayChartView }