Files
Reflect/Shared/Views/DayView/DayViewViewModel.swift
Trey t 0442eab1f8 Rebrand entire project from Feels to Reflect
Complete rename across all bundle IDs, App Groups, CloudKit containers,
StoreKit product IDs, data store filenames, URL schemes, logger subsystems,
Swift identifiers, user-facing strings (7 languages), file names, directory
names, Xcode project, schemes, assets, and documentation.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:47:16 -06:00

116 lines
3.9 KiB
Swift

//
// ContentModeViewModel.swift
// Reflect (iOS)
//
// Created by Trey Tartt on 1/20/22.
//
import SwiftUI
import SwiftData
@MainActor
class DayViewViewModel: ObservableObject {
@Published var grouped = [Int: [Int: [MoodEntryModel]]]()
@Published var numberOfItems = 0
@Published var sortedGroupedData: [(year: Int, months: [(month: Int, entries: [MoodEntryModel])])] = []
let addMonthStartWeekdayPadding: Bool
var hasNoData: Bool {
grouped.isEmpty
}
private var numberOfEntries: Int {
Self.countEntries(in: grouped)
}
/// Count total entries across all year/month groups. Extracted for testability.
static func countEntries(in grouped: [Int: [Int: [MoodEntryModel]]]) -> Int {
grouped.values.flatMap(\.values).reduce(0) { $0 + $1.count }
}
private var dataListenerToken: DataController.DataListenerToken?
init(addMonthStartWeekdayPadding: Bool) {
self.addMonthStartWeekdayPadding = addMonthStartWeekdayPadding
dataListenerToken = DataController.shared.addNewDataListener { [weak self] in
guard let self = self else { return }
// Avoid withAnimation for bulk data updates - it causes expensive view diffing
self.updateData()
}
updateData()
}
deinit {
if let token = dataListenerToken {
Task { @MainActor in
DataController.shared.removeDataListener(token: token)
}
}
}
private func getGroupedData(addMonthStartWeekdayPadding: Bool) {
var newStuff = DataController.shared.splitIntoYearMonth(includedDays: [1,2,3,4,5,6,7])
if addMonthStartWeekdayPadding {
newStuff = MoodEntryFunctions.padMoodEntriesForCalendar(entries: newStuff)
}
grouped = newStuff
numberOfItems = numberOfEntries
}
public func updateData() {
getGroupedData(addMonthStartWeekdayPadding: self.addMonthStartWeekdayPadding)
sortedGroupedData = grouped
.sorted { $0.key > $1.key }
.map { (year: $0.key, months: $0.value.sorted { $0.key > $1.key }.map { (month: $0.key, entries: $0.value) }) }
}
public func add(mood: Mood, forDate date: Date, entryType: EntryType) {
MoodLogger.shared.logMood(mood, for: date, entryType: entryType)
}
public func update(entry: MoodEntryModel, toMood mood: Mood) {
if !MoodLogger.shared.updateMood(entryDate: entry.forDate, withMood: mood) {
print("Failed to update mood entry")
}
}
public func delete(offsets: IndexSet, inMonth month: Int, inYear year: Int) {
if let monthEntries = grouped[year],
let entries = monthEntries[month] {
var mutableEntries = entries.sorted(by: {
$0.forDate > $1.forDate
})
var entriesToDelete = [MoodEntryModel]()
for idx in offsets {
let obj = mutableEntries.remove(at: idx)
entriesToDelete.append(obj)
}
entriesToDelete.forEach({ entry in
MoodLogger.shared.deleteMood(forDate: entry.forDate)
})
}
}
static func updateTitleHeader(forEntry entry: MoodEntryModel?) -> String {
guard let entry = entry else {
return ""
}
let forDate = entry.forDate
let components = Calendar.current.dateComponents([.day, .month, .year], from: forDate)
let month = components.month ?? 1
let year = components.year ?? Calendar.current.component(.year, from: Date())
let monthName = Random.monthName(fromMonthInt: month)
let weekday = Random.weekdayName(fromDate: entry.forDate)
let dayz = Random.dayFormat(fromDate: entry.forDate)
let string = weekday + " " + monthName + " " + dayz + " " + String(year)
return String(format: String(localized: "content_view_fill_in_missing_entry"), string)
}
}