Files
Reflect/Shared/Views/DayView/DayViewViewModel.swift
Trey t 356ce9ea62 Fix build errors, resolve all warnings, and improve code quality
Widget Extension Fixes:
- Create standalone WidgetDataProvider for widget data isolation
- Add WIDGET_EXTENSION compiler flag for conditional compilation
- Fix DataController references in widget-shared files
- Sync widget version numbers with main app (23, 1.0.2)
- Add WidgetBackground color to asset catalog

Warning Resolutions:
- Fix UIScreen.main deprecation in BGView and SharingListView
- Fix Text '+' concatenation deprecation in PurchaseButtonView and SettingsTabView
- Fix exhaustive switch in BiometricAuthManager (add .none case)
- Fix var to let in ExportService (3 instances)
- Fix unused result warning in NoteEditorView
- Fix ForEach duplicate ID warnings in MonthView and YearView

Code Quality Improvements:
- Wrap bypassSubscription in #if DEBUG for security
- Rename StupidAssCustomWidgetObservableObject to CustomWidgetStateViewModel
- Add @MainActor to IconViewModel
- Replace fatalError with graceful fallback in SharedModelContainer
- Add [weak self] to closures in DayViewViewModel
- Add OSLog-based AppLogger for production logging
- Add ImageCache with NSCache for memory efficiency
- Add AccessibilityHelpers with Reduce Motion support
- Create DataControllerProtocol for dependency injection
- Update .gitignore with secrets exclusions

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-20 00:48:35 -06:00

132 lines
4.2 KiB
Swift

//
// ContentModeViewModel.swift
// Feels (iOS)
//
// Created by Trey Tartt on 1/20/22.
//
import SwiftUI
import SwiftData
import WidgetKit
@MainActor
class DayViewViewModel: ObservableObject {
@Published var grouped = [Int: [Int: [MoodEntryModel]]]()
@Published var numberOfItems = 0
let addMonthStartWeekdayPadding: Bool
var hasNoData: Bool {
grouped.isEmpty
}
private var numberOfEntries: Int {
var num = 0
grouped.keys.forEach({
let year = grouped[$0]
let monthKeys = year?.keys
monthKeys?.forEach({
num += year![$0]!.count
})
})
return num
}
init(addMonthStartWeekdayPadding: Bool) {
self.addMonthStartWeekdayPadding = addMonthStartWeekdayPadding
DataController.shared.switchContainerListeners.append { [weak self] in
guard let self = self else { return }
self.getGroupedData(addMonthStartWeekdayPadding: self.addMonthStartWeekdayPadding)
}
DataController.shared.addNewDataListener { [weak self] in
guard let self = self else { return }
withAnimation {
self.updateData()
}
}
updateData()
}
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)
}
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 !DataController.shared.update(entryDate: entry.forDate, withMood: mood) {
print("Failed to update mood entry")
return
}
// Sync to HealthKit for past day updates
guard mood != .missing && mood != .placeholder else { return }
let healthKitEnabled = GroupUserDefaults.groupDefaults.bool(forKey: UserDefaultsStore.Keys.healthKitEnabled.rawValue)
if healthKitEnabled {
Task {
try? await HealthKitManager.shared.saveMood(mood, for: entry.forDate)
}
}
// Reload widgets asynchronously to avoid UI delay
Task { @MainActor in
WidgetCenter.shared.reloadAllTimelines()
}
}
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
let entryDate = entry.forDate
DataController.shared.modelContext.delete(entry)
self.add(mood: .missing, forDate: entryDate, entryType: .listView)
})
}
DataController.shared.save()
}
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!
let year = components.year!
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)
}
}