Migrate from Core Data to SwiftData
- Replace Core Data with SwiftData for iOS 18+ - Create MoodEntryModel as @Model class replacing MoodEntry entity - Create SharedModelContainer for App Group container sharing - Create DataController with CRUD extensions replacing PersistenceController - Update all views and view models to use MoodEntryModel - Update widget extension to use SwiftData - Remove old Core Data files (Persistence*.swift, .xcdatamodeld) - Add EntryType enum with all entry type cases - Fix widget label truncation with proper spacing and text scaling 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import CoreData
|
||||
import SwiftData
|
||||
|
||||
struct AddMoodHeaderView: View {
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
@@ -255,11 +255,11 @@ struct AddMoodHeaderView_Previews: PreviewProvider {
|
||||
Group {
|
||||
AddMoodHeaderView(addItemHeaderClosure: { (_,_) in
|
||||
|
||||
}).environment(\.managedObjectContext, PersistenceController.shared.viewContext)
|
||||
}).modelContainer(DataController.shared.container)
|
||||
|
||||
AddMoodHeaderView(addItemHeaderClosure: { (_,_) in
|
||||
|
||||
}).preferredColorScheme(.dark).environment(\.managedObjectContext, PersistenceController.shared.viewContext)
|
||||
}).preferredColorScheme(.dark).modelContainer(DataController.shared.container)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import SwiftData
|
||||
|
||||
struct BGViewItem: View {
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
@@ -81,13 +82,13 @@ struct BGView: View, Equatable {
|
||||
|
||||
struct BGView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
BGView().environment(\.managedObjectContext, PersistenceController.shared.viewContext)
|
||||
BGView().modelContainer(DataController.shared.container)
|
||||
.onAppear(perform: {
|
||||
PersistenceController.shared.populateMemory()
|
||||
DataController.shared.populateMemory()
|
||||
})
|
||||
|
||||
|
||||
BGView()
|
||||
.preferredColorScheme(.dark)
|
||||
.environment(\.managedObjectContext, PersistenceController.shared.viewContext)
|
||||
.modelContainer(DataController.shared.container)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import CoreData
|
||||
import SwiftData
|
||||
import Charts
|
||||
|
||||
struct DayViewConstants {
|
||||
@@ -15,8 +15,6 @@ struct DayViewConstants {
|
||||
}
|
||||
|
||||
struct DayView: View {
|
||||
@Environment(\.managedObjectContext) private var viewContext
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.deleteEnable.rawValue, store: GroupUserDefaults.groupDefaults) private var deleteEnabled = true
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
@@ -30,7 +28,7 @@ struct DayView: View {
|
||||
|
||||
// MARK: edit row properties
|
||||
@State private var showingSheet = false
|
||||
@State private var selectedEntry: MoodEntry?
|
||||
@State private var selectedEntry: MoodEntryModel?
|
||||
//
|
||||
|
||||
// MARK: ?? properties
|
||||
@@ -100,7 +98,7 @@ struct DayView: View {
|
||||
}
|
||||
.padding([.leading, .trailing])
|
||||
.onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in
|
||||
PersistenceController.shared.fillInMissingDates()
|
||||
DataController.shared.fillInMissingDates()
|
||||
viewModel.updateData()
|
||||
}
|
||||
.background(
|
||||
@@ -164,13 +162,13 @@ extension DayView {
|
||||
.background(.ultraThinMaterial)
|
||||
}
|
||||
|
||||
private func monthListView(month: Int, year: Int, entries: [MoodEntry]) -> some View {
|
||||
private func monthListView(month: Int, year: Int, entries: [MoodEntryModel]) -> some View {
|
||||
VStack(spacing: 12) {
|
||||
// for reach all entries
|
||||
ForEach(entries.sorted(by: {
|
||||
return $0.forDate! > $1.forDate!
|
||||
return $0.forDate > $1.forDate
|
||||
}), id: \.self) { entry in
|
||||
if filteredDays.currentFilters.contains(Int(entry.weekDay)) {
|
||||
if filteredDays.currentFilters.contains(entry.weekDay) {
|
||||
EntryListView(entry: entry)
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture(perform: {
|
||||
@@ -195,13 +193,14 @@ struct ViewOffsetKey: PreferenceKey {
|
||||
|
||||
struct DayView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
DayView(viewModel: DayViewViewModel(addMonthStartWeekdayPadding: false)).environment(\.managedObjectContext, PersistenceController.shared.viewContext)
|
||||
DayView(viewModel: DayViewViewModel(addMonthStartWeekdayPadding: false))
|
||||
.modelContainer(DataController.shared.container)
|
||||
.onAppear(perform: {
|
||||
PersistenceController.shared.populateMemory()
|
||||
DataController.shared.populateMemory()
|
||||
})
|
||||
|
||||
DayView(viewModel: DayViewViewModel(addMonthStartWeekdayPadding: false))
|
||||
.preferredColorScheme(.dark)
|
||||
.environment(\.managedObjectContext, PersistenceController.shared.viewContext)
|
||||
.modelContainer(DataController.shared.container)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,18 +6,19 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import CoreData
|
||||
import SwiftData
|
||||
|
||||
@MainActor
|
||||
class DayViewViewModel: ObservableObject {
|
||||
@Published var grouped = [Int: [Int: [MoodEntry]]]()
|
||||
@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({
|
||||
@@ -28,31 +29,25 @@ class DayViewViewModel: ObservableObject {
|
||||
})
|
||||
})
|
||||
return num
|
||||
|
||||
// grouped.keys.map{
|
||||
// grouped[$0]!.values.reduce(0) { sum, array in
|
||||
// sum + array.count
|
||||
// }
|
||||
// }.reduce(0, +)
|
||||
}
|
||||
|
||||
|
||||
init(addMonthStartWeekdayPadding: Bool) {
|
||||
self.addMonthStartWeekdayPadding = addMonthStartWeekdayPadding
|
||||
|
||||
PersistenceController.shared.switchContainerListeners.append {
|
||||
|
||||
DataController.shared.switchContainerListeners.append {
|
||||
self.getGroupedData(addMonthStartWeekdayPadding: self.addMonthStartWeekdayPadding)
|
||||
}
|
||||
|
||||
PersistenceController.shared.addNewDataListener {
|
||||
DataController.shared.addNewDataListener {
|
||||
withAnimation{
|
||||
self.updateData()
|
||||
}
|
||||
}
|
||||
updateData()
|
||||
}
|
||||
|
||||
|
||||
private func getGroupedData(addMonthStartWeekdayPadding: Bool) {
|
||||
var newStuff = PersistenceController.shared.splitIntoYearMonth(includedDays: [1,2,3,4,5,6,7])
|
||||
var newStuff = DataController.shared.splitIntoYearMonth(includedDays: [1,2,3,4,5,6,7])
|
||||
if addMonthStartWeekdayPadding {
|
||||
newStuff = MoodEntryFunctions.padMoodEntriesForCalendar(entries: newStuff)
|
||||
}
|
||||
@@ -63,65 +58,55 @@ class DayViewViewModel: ObservableObject {
|
||||
public func updateData() {
|
||||
getGroupedData(addMonthStartWeekdayPadding: self.addMonthStartWeekdayPadding)
|
||||
}
|
||||
|
||||
|
||||
public func add(mood: Mood, forDate date: Date, entryType: EntryType) {
|
||||
PersistenceController.shared.add(mood: mood, forDate: date, entryType: entryType)
|
||||
DataController.shared.add(mood: mood, forDate: date, entryType: entryType)
|
||||
}
|
||||
|
||||
public func update(entry: MoodEntry, toMood mood: Mood) {
|
||||
if !PersistenceController.shared.update(entryDate: entry.forDate!, withModd: mood) {
|
||||
|
||||
public func update(entry: MoodEntryModel, toMood mood: Mood) {
|
||||
if !DataController.shared.update(entryDate: entry.forDate, withMood: mood) {
|
||||
#warning("show error")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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!
|
||||
$0.forDate > $1.forDate
|
||||
})
|
||||
var entriesToDelete = [MoodEntry]()
|
||||
var entriesToDelete = [MoodEntryModel]()
|
||||
for idx in offsets {
|
||||
let obj = mutableEntries.remove(at: idx)
|
||||
entriesToDelete.append(obj)
|
||||
}
|
||||
entriesToDelete.forEach({ entry in
|
||||
let entryDate = entry.forDate!
|
||||
PersistenceController.shared.viewContext.delete(entry)
|
||||
let entryDate = entry.forDate
|
||||
DataController.shared.modelContext.delete(entry)
|
||||
self.add(mood: .missing, forDate: entryDate, entryType: .listView)
|
||||
})
|
||||
}
|
||||
|
||||
do {
|
||||
try PersistenceController.shared.viewContext.save()
|
||||
} catch {
|
||||
// Replace this implementation with code to handle the error appropriately.
|
||||
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
||||
let nsError = error as NSError
|
||||
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
|
||||
}
|
||||
|
||||
DataController.shared.save()
|
||||
}
|
||||
|
||||
static func updateTitleHeader(forEntry entry: MoodEntry?) -> String {
|
||||
|
||||
static func updateTitleHeader(forEntry entry: MoodEntryModel?) -> String {
|
||||
guard let entry = entry else {
|
||||
return ""
|
||||
}
|
||||
|
||||
guard let forDate = entry.forDate else {
|
||||
return ""
|
||||
}
|
||||
|
||||
|
||||
let forDate = entry.forDate
|
||||
|
||||
let components = Calendar.current.dateComponents([.day, .month, .year], from: forDate)
|
||||
// let day = components.day!
|
||||
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 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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ struct EntryListView: View {
|
||||
@AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor
|
||||
@Environment(\.colorScheme) private var colorScheme
|
||||
|
||||
public let entry: MoodEntry
|
||||
public let entry: MoodEntryModel
|
||||
|
||||
private var moodColor: Color {
|
||||
moodTint.color(forMood: entry.mood)
|
||||
@@ -53,14 +53,14 @@ struct EntryListView: View {
|
||||
VStack(alignment: .leading, spacing: 6) {
|
||||
// Date row
|
||||
HStack(spacing: 6) {
|
||||
Text(Random.weekdayName(fromDate: entry.forDate!))
|
||||
Text(Random.weekdayName(fromDate: entry.forDate))
|
||||
.font(.system(size: 17, weight: .semibold))
|
||||
.foregroundColor(textColor)
|
||||
|
||||
Text("•")
|
||||
.foregroundColor(textColor.opacity(0.4))
|
||||
|
||||
Text(Random.dayFormat(fromDate: entry.forDate!))
|
||||
Text(Random.dayFormat(fromDate: entry.forDate))
|
||||
.font(.system(size: 17, weight: .medium))
|
||||
.foregroundColor(textColor.opacity(0.8))
|
||||
}
|
||||
@@ -115,7 +115,7 @@ struct EntryListView: View {
|
||||
}
|
||||
|
||||
struct EntryListView_Previews: PreviewProvider {
|
||||
static let fakeData = PersistenceController.shared.randomEntries(count: 1).first!
|
||||
@MainActor static let fakeData = DataController.shared.randomEntries(count: 1).first!
|
||||
|
||||
static var previews: some View {
|
||||
VStack(spacing: 8) {
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import CoreData
|
||||
import Charts
|
||||
|
||||
struct GraphView: View {
|
||||
|
||||
@@ -23,18 +23,19 @@ struct HeaderPercView: View {
|
||||
let backDays: Int
|
||||
let type: PercViewType
|
||||
|
||||
@MainActor
|
||||
init(fakeData: Bool, backDays: Int, type: PercViewType) {
|
||||
self.type = type
|
||||
self.backDays = backDays
|
||||
var moodEntries: [MoodEntry]?
|
||||
var moodEntries: [MoodEntryModel]?
|
||||
|
||||
if fakeData {
|
||||
moodEntries = PersistenceController.shared.randomEntries(count: 10)
|
||||
moodEntries = DataController.shared.randomEntries(count: 10)
|
||||
} else {
|
||||
var daysAgo = Calendar.current.date(byAdding: .day, value: -backDays, to: Date())!
|
||||
daysAgo = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: daysAgo)!
|
||||
|
||||
moodEntries = PersistenceController.shared.getData(startDate: daysAgo, endDate: Date(), includedDays: [1,2,3,4,5,6,7])
|
||||
|
||||
moodEntries = DataController.shared.getData(startDate: daysAgo, endDate: Date(), includedDays: [1,2,3,4,5,6,7])
|
||||
}
|
||||
|
||||
if let moodEntries = moodEntries {
|
||||
|
||||
@@ -24,16 +24,16 @@ struct HeaderStatsView : UIViewRepresentable {
|
||||
}
|
||||
self.tmpHolderToMakeViewDiffefrent = Color.random()
|
||||
entries = [BarChartDataEntry]()
|
||||
|
||||
var moodEntries: [MoodEntry]?
|
||||
|
||||
var moodEntries: [MoodEntryModel]?
|
||||
|
||||
if fakeData {
|
||||
moodEntries = PersistenceController.shared.randomEntries(count: 10)
|
||||
moodEntries = DataController.shared.randomEntries(count: 10)
|
||||
} else {
|
||||
var daysAgo = Calendar.current.date(byAdding: .day, value: -backDays, to: Date())!
|
||||
daysAgo = Calendar.current.date(bySettingHour: 0, minute: 0, second: 0, of: daysAgo)!
|
||||
|
||||
moodEntries = PersistenceController.shared.getData(startDate: daysAgo, endDate: Date(), includedDays: [1,2,3,4,5,6,7])
|
||||
|
||||
moodEntries = DataController.shared.getData(startDate: daysAgo, endDate: Date(), includedDays: [1,2,3,4,5,6,7])
|
||||
}
|
||||
if let moodEntries = moodEntries {
|
||||
for (index, mood) in Mood.allValues.enumerated() {
|
||||
|
||||
@@ -16,6 +16,7 @@ struct Insight: Identifiable {
|
||||
let mood: Mood?
|
||||
}
|
||||
|
||||
@MainActor
|
||||
class InsightsViewModel: ObservableObject {
|
||||
@Published var monthInsights: [Insight] = []
|
||||
@Published var yearInsights: [Insight] = []
|
||||
@@ -36,9 +37,9 @@ class InsightsViewModel: ObservableObject {
|
||||
let allTimeStart = Date(timeIntervalSince1970: 0)
|
||||
|
||||
// Fetch entries for each period
|
||||
let monthEntries = PersistenceController.shared.getData(startDate: monthStart, endDate: now, includedDays: [1,2,3,4,5,6,7])
|
||||
let yearEntries = PersistenceController.shared.getData(startDate: yearStart, endDate: now, includedDays: [1,2,3,4,5,6,7])
|
||||
let allTimeEntries = PersistenceController.shared.getData(startDate: allTimeStart, endDate: now, includedDays: [1,2,3,4,5,6,7])
|
||||
let monthEntries = DataController.shared.getData(startDate: monthStart, endDate: now, includedDays: [1,2,3,4,5,6,7])
|
||||
let yearEntries = DataController.shared.getData(startDate: yearStart, endDate: now, includedDays: [1,2,3,4,5,6,7])
|
||||
let allTimeEntries = DataController.shared.getData(startDate: allTimeStart, endDate: now, includedDays: [1,2,3,4,5,6,7])
|
||||
|
||||
// Generate insights for each period
|
||||
monthInsights = generateRandomInsights(entries: monthEntries, periodName: "this month", count: 5)
|
||||
@@ -46,7 +47,7 @@ class InsightsViewModel: ObservableObject {
|
||||
allTimeInsights = generateRandomInsights(entries: allTimeEntries, periodName: "all time", count: 5)
|
||||
}
|
||||
|
||||
private func generateRandomInsights(entries: [MoodEntry], periodName: String, count: Int) -> [Insight] {
|
||||
private func generateRandomInsights(entries: [MoodEntryModel], periodName: String, count: Int) -> [Insight] {
|
||||
// Filter out missing/placeholder entries
|
||||
let validEntries = entries.filter { ![.missing, .placeholder].contains($0.mood) }
|
||||
|
||||
@@ -85,7 +86,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Most Common Mood
|
||||
private func generateMostCommonMoodInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateMostCommonMoodInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
let moodCounts = Dictionary(grouping: entries, by: { $0.mood }).mapValues { $0.count }
|
||||
|
||||
@@ -120,7 +121,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Least Common Mood
|
||||
private func generateLeastCommonMoodInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateLeastCommonMoodInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
let moodCounts = Dictionary(grouping: entries, by: { $0.mood }).mapValues { $0.count }
|
||||
|
||||
@@ -143,7 +144,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Best Day of Week
|
||||
private func generateBestDayInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateBestDayInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
let weekdayCounts = Dictionary(grouping: entries, by: { Int($0.weekDay) })
|
||||
var weekdayScores: [Int: Float] = [:]
|
||||
@@ -176,7 +177,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Worst Day of Week
|
||||
private func generateWorstDayInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateWorstDayInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
let weekdayCounts = Dictionary(grouping: entries, by: { Int($0.weekDay) })
|
||||
var weekdayScores: [Int: Float] = [:]
|
||||
@@ -208,7 +209,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Streak Insights
|
||||
private func generateStreakInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateStreakInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
let streakInfo = calculateStreaks(entries: entries)
|
||||
|
||||
@@ -271,12 +272,12 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Trend Insights
|
||||
private func generateTrendInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateTrendInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
|
||||
guard entries.count >= 4 else { return insights }
|
||||
|
||||
let sortedEntries = entries.sorted { $0.forDate! < $1.forDate! }
|
||||
let sortedEntries = entries.sorted { $0.forDate < $1.forDate }
|
||||
let halfCount = sortedEntries.count / 2
|
||||
|
||||
let firstHalf = Array(sortedEntries.prefix(halfCount))
|
||||
@@ -330,7 +331,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Positivity Insights
|
||||
private func generatePositivityInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generatePositivityInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
|
||||
let positiveDays = entries.filter { [.great, .good].contains($0.mood) }.count
|
||||
@@ -393,7 +394,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Weekend vs Weekday
|
||||
private func generateWeekendVsWeekdayInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateWeekendVsWeekdayInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
|
||||
let weekendDays = entries.filter { [1, 7].contains(Int($0.weekDay)) } // Sunday = 1, Saturday = 7
|
||||
@@ -431,12 +432,12 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Mood Swing Insights
|
||||
private func generateMoodSwingInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateMoodSwingInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
|
||||
guard entries.count >= 3 else { return insights }
|
||||
|
||||
let sortedEntries = entries.sorted { $0.forDate! < $1.forDate! }
|
||||
let sortedEntries = entries.sorted { $0.forDate < $1.forDate }
|
||||
var swings = 0
|
||||
|
||||
for i in 1..<sortedEntries.count {
|
||||
@@ -483,7 +484,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Consistency Insights
|
||||
private func generateConsistencyInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateConsistencyInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
|
||||
let totalDaysInPeriod = calculateDaysInPeriod(periodName: periodName)
|
||||
@@ -535,7 +536,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Milestone Insights
|
||||
private func generateMilestoneInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateMilestoneInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
|
||||
let count = entries.count
|
||||
@@ -557,7 +558,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Comparative Insights
|
||||
private func generateComparativeInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateComparativeInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
|
||||
let moodCounts = Dictionary(grouping: entries, by: { $0.mood }).mapValues { $0.count }
|
||||
@@ -606,7 +607,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Pattern Insights
|
||||
private func generatePatternInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generatePatternInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
|
||||
// Monday blues check
|
||||
@@ -662,7 +663,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Fun Fact Insights
|
||||
private func generateFunFactInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateFunFactInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
|
||||
let greatDays = entries.filter { $0.mood == .great }.count
|
||||
@@ -688,7 +689,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// Calculate "great day streak potential"
|
||||
let recentEntries = entries.sorted { $0.forDate! > $1.forDate! }.prefix(7)
|
||||
let recentEntries = entries.sorted { $0.forDate > $1.forDate }.prefix(7)
|
||||
let recentGreat = recentEntries.filter { $0.mood == .great }.count
|
||||
if recentGreat >= 3 {
|
||||
insights.append(Insight(
|
||||
@@ -712,7 +713,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Motivational Insights
|
||||
private func generateMotivationalInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateMotivationalInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
|
||||
let avgMood = Float(entries.reduce(0) { $0 + Int($1.moodValue) }) / Float(entries.count)
|
||||
@@ -760,7 +761,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Rare Mood Insights
|
||||
private func generateRareMoodInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateRareMoodInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
|
||||
let moodCounts = Dictionary(grouping: entries, by: { $0.mood }).mapValues { $0.count }
|
||||
@@ -800,13 +801,13 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Recent Insights
|
||||
private func generateRecentInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateRecentInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
|
||||
let sortedEntries = entries.sorted { $0.forDate! > $1.forDate! }
|
||||
let sortedEntries = entries.sorted { $0.forDate > $1.forDate }
|
||||
guard let mostRecent = sortedEntries.first else { return insights }
|
||||
|
||||
let daysSinceLastEntry = calendar.dateComponents([.day], from: mostRecent.forDate!, to: Date()).day ?? 0
|
||||
let daysSinceLastEntry = calendar.dateComponents([.day], from: mostRecent.forDate, to: Date()).day ?? 0
|
||||
|
||||
if daysSinceLastEntry == 0 {
|
||||
insights.append(Insight(
|
||||
@@ -858,13 +859,13 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Month of Year Insights
|
||||
private func generateMonthOfYearInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateMonthOfYearInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
|
||||
guard periodName == "this year" || periodName == "all time" else { return insights }
|
||||
|
||||
let monthGroups = Dictionary(grouping: entries) { entry -> Int in
|
||||
calendar.component(.month, from: entry.forDate!)
|
||||
calendar.component(.month, from: entry.forDate)
|
||||
}
|
||||
|
||||
var monthScores: [Int: Float] = [:]
|
||||
@@ -899,7 +900,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Longest Mood Run
|
||||
private func generateLongestMoodRunInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateLongestMoodRunInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
|
||||
for mood in [Mood.great, .good, .average, .bad, .horrible] {
|
||||
@@ -928,7 +929,7 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
// MARK: - Average Mood Insights
|
||||
private func generateAverageMoodInsights(entries: [MoodEntry], periodName: String) -> [Insight] {
|
||||
private func generateAverageMoodInsights(entries: [MoodEntryModel], periodName: String) -> [Insight] {
|
||||
var insights: [Insight] = []
|
||||
|
||||
let avgMood = Float(entries.reduce(0) { $0 + Int($1.moodValue) }) / Float(entries.count)
|
||||
@@ -980,8 +981,8 @@ class InsightsViewModel: ObservableObject {
|
||||
|
||||
// MARK: - Helper Functions
|
||||
|
||||
private func calculateStreaks(entries: [MoodEntry]) -> (currentStreak: Int, longestStreak: Int) {
|
||||
let sortedEntries = entries.sorted { $0.forDate! > $1.forDate! }
|
||||
private func calculateStreaks(entries: [MoodEntryModel]) -> (currentStreak: Int, longestStreak: Int) {
|
||||
let sortedEntries = entries.sorted { $0.forDate > $1.forDate }
|
||||
guard !sortedEntries.isEmpty else { return (0, 0) }
|
||||
|
||||
var currentStreak = 0
|
||||
@@ -989,14 +990,14 @@ class InsightsViewModel: ObservableObject {
|
||||
var tempStreak = 1
|
||||
|
||||
let today = calendar.startOfDay(for: Date())
|
||||
if let mostRecent = sortedEntries.first?.forDate,
|
||||
calendar.isDate(mostRecent, inSameDayAs: today) || calendar.isDate(mostRecent, inSameDayAs: calendar.date(byAdding: .day, value: -1, to: today)!) {
|
||||
let mostRecent = sortedEntries.first!.forDate
|
||||
if calendar.isDate(mostRecent, inSameDayAs: today) || calendar.isDate(mostRecent, inSameDayAs: calendar.date(byAdding: .day, value: -1, to: today)!) {
|
||||
currentStreak = 1
|
||||
var checkDate = calendar.date(byAdding: .day, value: -1, to: mostRecent)!
|
||||
|
||||
for entry in sortedEntries.dropFirst() {
|
||||
if let entryDate = entry.forDate,
|
||||
calendar.isDate(entryDate, inSameDayAs: checkDate) {
|
||||
let entryDate = entry.forDate
|
||||
if calendar.isDate(entryDate, inSameDayAs: checkDate) {
|
||||
currentStreak += 1
|
||||
checkDate = calendar.date(byAdding: .day, value: -1, to: checkDate)!
|
||||
} else {
|
||||
@@ -1006,15 +1007,14 @@ class InsightsViewModel: ObservableObject {
|
||||
}
|
||||
|
||||
for i in 1..<sortedEntries.count {
|
||||
if let currentDate = sortedEntries[i].forDate,
|
||||
let previousDate = sortedEntries[i-1].forDate {
|
||||
let dayDiff = calendar.dateComponents([.day], from: currentDate, to: previousDate).day ?? 0
|
||||
if dayDiff == 1 {
|
||||
tempStreak += 1
|
||||
} else {
|
||||
longestStreak = max(longestStreak, tempStreak)
|
||||
tempStreak = 1
|
||||
}
|
||||
let currentDate = sortedEntries[i].forDate
|
||||
let previousDate = sortedEntries[i-1].forDate
|
||||
let dayDiff = calendar.dateComponents([.day], from: currentDate, to: previousDate).day ?? 0
|
||||
if dayDiff == 1 {
|
||||
tempStreak += 1
|
||||
} else {
|
||||
longestStreak = max(longestStreak, tempStreak)
|
||||
tempStreak = 1
|
||||
}
|
||||
}
|
||||
longestStreak = max(longestStreak, tempStreak)
|
||||
@@ -1022,8 +1022,8 @@ class InsightsViewModel: ObservableObject {
|
||||
return (currentStreak, longestStreak)
|
||||
}
|
||||
|
||||
private func calculateMoodStreaks(entries: [MoodEntry], moods: [Mood]) -> (current: Int, longest: Int) {
|
||||
let sortedEntries = entries.sorted { $0.forDate! < $1.forDate! }
|
||||
private func calculateMoodStreaks(entries: [MoodEntryModel], moods: [Mood]) -> (current: Int, longest: Int) {
|
||||
let sortedEntries = entries.sorted { $0.forDate < $1.forDate }
|
||||
guard !sortedEntries.isEmpty else { return (0, 0) }
|
||||
|
||||
var currentStreak = 0
|
||||
|
||||
@@ -14,15 +14,15 @@ struct MonthDetailView: View {
|
||||
@AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor
|
||||
|
||||
@StateObject private var shareImage = StupidAssShareObservableObject()
|
||||
|
||||
|
||||
@State private var showingSheet = false
|
||||
@State private var selectedEntry: MoodEntry?
|
||||
@State private var selectedEntry: MoodEntryModel?
|
||||
@State private var showingUpdateEntryAlert = false
|
||||
@State private var showUpdateEntryAlert = false
|
||||
|
||||
|
||||
let monthInt: Int
|
||||
let yearInt: Int
|
||||
@State var entries: [MoodEntry]
|
||||
@State var entries: [MoodEntryModel]
|
||||
var parentViewModel: DayViewViewModel
|
||||
|
||||
let columns = [
|
||||
@@ -90,24 +90,24 @@ struct MonthDetailView: View {
|
||||
ForEach(Mood.allValues) { mood in
|
||||
Button(mood.strValue, action: {
|
||||
if let selectedEntry = selectedEntry {
|
||||
PersistenceController.shared.update(entryDate: selectedEntry.forDate!, withModd: mood)
|
||||
DataController.shared.update(entryDate: selectedEntry.forDate, withMood: mood)
|
||||
}
|
||||
updateEntries()
|
||||
showUpdateEntryAlert = false
|
||||
selectedEntry = nil
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
if let selectedEntry = selectedEntry,
|
||||
deleteEnabled,
|
||||
selectedEntry.mood != .missing {
|
||||
Button(String(localized: "content_view_delete_entry"), action: {
|
||||
PersistenceController.shared.update(entryDate: selectedEntry.forDate!, withModd: .missing)
|
||||
DataController.shared.update(entryDate: selectedEntry.forDate, withMood: .missing)
|
||||
updateEntries()
|
||||
showUpdateEntryAlert = false
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Button(String(localized: "content_view_fill_in_missing_entry_cancel"), role: .cancel, action: {
|
||||
updateEntries()
|
||||
selectedEntry = nil
|
||||
@@ -161,13 +161,13 @@ struct MonthDetailView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func listViewEntry(forEntry entry: MoodEntry) -> some View {
|
||||
private func listViewEntry(forEntry entry: MoodEntryModel) -> some View {
|
||||
VStack {
|
||||
if entry.mood == .placeholder {
|
||||
Text(" ")
|
||||
.font(.title3)
|
||||
.foregroundColor(Mood.placeholder.color)
|
||||
|
||||
|
||||
Circle()
|
||||
.frame(minWidth: 5,
|
||||
maxWidth: 50,
|
||||
@@ -176,11 +176,11 @@ struct MonthDetailView: View {
|
||||
alignment: .center)
|
||||
.foregroundColor(moodTint.color(forMood: entry.mood))
|
||||
} else {
|
||||
Text(entry.forDate!,
|
||||
Text(entry.forDate,
|
||||
format: Date.FormatStyle().day())
|
||||
.font(.title3)
|
||||
.foregroundColor(textColor)
|
||||
|
||||
|
||||
entry.mood.icon
|
||||
.resizable()
|
||||
.scaledToFit()
|
||||
@@ -193,11 +193,11 @@ struct MonthDetailView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func updateEntries() {
|
||||
parentViewModel.updateData()
|
||||
let (startDate, endDate) = Date.dateRange(monthInt: monthInt, yearInt: yearInt)
|
||||
let updatedEntries = PersistenceController.shared.getData(startDate: startDate, endDate: endDate, includedDays: [1,2,3,4,5,6,7])
|
||||
let updatedEntries = DataController.shared.getData(startDate: startDate, endDate: endDate, includedDays: [1,2,3,4,5,6,7])
|
||||
let padded = MoodEntryFunctions.padMoodEntriesMonth(monthEntries: updatedEntries)
|
||||
entries = padded
|
||||
}
|
||||
@@ -221,8 +221,8 @@ struct MonthDetailView: View {
|
||||
struct MonthDetailView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
MonthDetailView(monthInt: 5, yearInt: 2022, entries:
|
||||
PersistenceController.shared.randomEntries(count: 30).sorted(by: {
|
||||
$0.forDate! < $1.forDate!
|
||||
DataController.shared.randomEntries(count: 30).sorted(by: {
|
||||
$0.forDate < $1.forDate
|
||||
}), parentViewModel: DayViewViewModel(addMonthStartWeekdayPadding: true))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -162,7 +162,7 @@ struct MonthView: View {
|
||||
struct MonthCard: View {
|
||||
let month: Int
|
||||
let year: Int
|
||||
let entries: [MoodEntry]
|
||||
let entries: [MoodEntryModel]
|
||||
let moodTint: MoodTints
|
||||
let imagePack: MoodImages
|
||||
let textColor: Color
|
||||
@@ -177,7 +177,7 @@ struct MonthCard: View {
|
||||
|
||||
private var metrics: [MoodMetrics] {
|
||||
let (startDate, endDate) = Date.dateRange(monthInt: month, yearInt: year)
|
||||
let monthEntries = PersistenceController.shared.getData(startDate: startDate, endDate: endDate, includedDays: [1,2,3,4,5,6,7])
|
||||
let monthEntries = DataController.shared.getData(startDate: startDate, endDate: endDate, includedDays: [1,2,3,4,5,6,7])
|
||||
return Random.createTotalPerc(fromEntries: monthEntries)
|
||||
}
|
||||
|
||||
@@ -250,7 +250,7 @@ struct MonthCard: View {
|
||||
|
||||
// MARK: - Heatmap Cell
|
||||
struct HeatmapCell: View {
|
||||
let entry: MoodEntry
|
||||
let entry: MoodEntryModel
|
||||
let moodTint: MoodTints
|
||||
let isFiltered: Bool
|
||||
|
||||
|
||||
@@ -8,14 +8,14 @@
|
||||
import SwiftUI
|
||||
|
||||
struct SampleEntryView: View {
|
||||
@State private var sampleListEntry = PersistenceController.shared.generateObjectNotInArray(forDate: Date(), withMood: Mood.great)
|
||||
@State private var sampleListEntry = DataController.shared.generateObjectNotInArray(forDate: Date(), withMood: Mood.great)
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
@AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor
|
||||
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
|
||||
|
||||
VStack {
|
||||
HStack {
|
||||
Spacer()
|
||||
@@ -24,7 +24,7 @@ struct SampleEntryView: View {
|
||||
.frame(width: 20, height: 20, alignment: .trailing)
|
||||
.foregroundColor(Color(UIColor.systemGray))
|
||||
.onTapGesture {
|
||||
sampleListEntry = PersistenceController.shared.generateObjectNotInArray(forDate: Date(), withMood: sampleListEntry.mood.next)
|
||||
sampleListEntry = DataController.shared.generateObjectNotInArray(forDate: Date(), withMood: sampleListEntry.mood.next)
|
||||
}
|
||||
}
|
||||
Spacer()
|
||||
|
||||
@@ -119,20 +119,14 @@ struct SettingsView: View {
|
||||
if columns.count != 7 {
|
||||
continue
|
||||
}
|
||||
let moodEntry = MoodEntry(context: PersistenceController.shared.viewContext)
|
||||
moodEntry.canDelete = Bool(columns[0])!
|
||||
moodEntry.canEdit = Bool(columns[1])!
|
||||
moodEntry.entryType = Int16(columns[2])!
|
||||
moodEntry.forDate = dateFormatter.date(from: columns[3])!
|
||||
moodEntry.moodValue = Int16(columns[4])!
|
||||
moodEntry.timestamp = dateFormatter.date(from: columns[5])!
|
||||
|
||||
let localTime = dateFormatter.date(from: columns[3])!
|
||||
moodEntry.weekDay = Int16(Calendar.current.component(.weekday, from: localTime))
|
||||
// let _ = print("import info: ", columns[3], dateFormatter.date(from: columns[3]), localTime, Int16(Calendar.current.component(.weekday, from: localTime)))
|
||||
try! PersistenceController.shared.viewContext.save()
|
||||
let forDate = dateFormatter.date(from: columns[3])!
|
||||
let moodValue = Int(columns[4])!
|
||||
let mood = Mood(rawValue: moodValue) ?? .missing
|
||||
let entryType = EntryType(rawValue: Int(columns[2])!) ?? .listView
|
||||
|
||||
DataController.shared.add(mood: mood, forDate: forDate, entryType: entryType)
|
||||
}
|
||||
PersistenceController.shared.saveAndRunDataListerners()
|
||||
DataController.shared.saveAndRunDataListeners()
|
||||
EventLogger.log(event: "import_file")
|
||||
} else {
|
||||
EventLogger.log(event: "error_import_file")
|
||||
@@ -201,7 +195,7 @@ struct SettingsView: View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
PersistenceController.shared.populateTestData()
|
||||
DataController.shared.populateTestData()
|
||||
}, label: {
|
||||
Text("Add test data")
|
||||
.foregroundColor(textColor)
|
||||
@@ -257,7 +251,7 @@ struct SettingsView: View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
PersistenceController.shared.clearDB()
|
||||
DataController.shared.clearDB()
|
||||
}, label: {
|
||||
Text("Clear DB")
|
||||
.foregroundColor(textColor)
|
||||
@@ -267,12 +261,12 @@ struct SettingsView: View {
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.cornerRadius(Constants.viewsCornerRaidus, corners: [.topLeft, .topRight, .bottomLeft, .bottomRight])
|
||||
}
|
||||
|
||||
|
||||
private var fixWeekday: some View {
|
||||
ZStack {
|
||||
theme.currentTheme.secondaryBGColor
|
||||
Button(action: {
|
||||
PersistenceController.shared.fixWrongWeekdays()
|
||||
DataController.shared.fixWrongWeekdays()
|
||||
}, label: {
|
||||
Text("Fix Weekday")
|
||||
.foregroundColor(textColor)
|
||||
@@ -576,28 +570,28 @@ struct SettingsView: View {
|
||||
struct TextFile: FileDocument {
|
||||
// tell the system we support only plain text
|
||||
static var readableContentTypes = [UTType.plainText]
|
||||
|
||||
|
||||
// by default our document is empty
|
||||
var text = ""
|
||||
|
||||
|
||||
// a simple initializer that creates new, empty documents
|
||||
@MainActor
|
||||
init() {
|
||||
let entries = PersistenceController.shared.getData(startDate: Date(timeIntervalSince1970: 0),
|
||||
endDate: Date(),
|
||||
includedDays: [])
|
||||
|
||||
let entries = DataController.shared.getData(startDate: Date(timeIntervalSince1970: 0),
|
||||
endDate: Date(),
|
||||
includedDays: [])
|
||||
|
||||
var csvString = "canDelete,canEdit,entryType,forDate,moodValue,timestamp,weekDay\n"
|
||||
for entry in entries {
|
||||
let canDelete = entry.canDelete
|
||||
let canEdit = entry.canEdit
|
||||
let entryType = entry.entryType
|
||||
let forDate = entry.forDate!
|
||||
let forDate = entry.forDate
|
||||
let moodValue = entry.moodValue
|
||||
let timestamp = entry.timestamp!
|
||||
let timestamp = entry.timestamp
|
||||
let weekDay = entry.weekDay
|
||||
|
||||
|
||||
let dataString = "\(canDelete),\(canEdit),\(entryType),\(String(describing: forDate)),\(moodValue),\(String(describing:timestamp)),\(weekDay)\n"
|
||||
// print("DATA: \(dataString)")
|
||||
csvString = csvString.appending(dataString)
|
||||
}
|
||||
text = csvString
|
||||
|
||||
@@ -34,16 +34,17 @@ struct SharingListView: View {
|
||||
@StateObject private var selectedShare = StupidAssObservableObject()
|
||||
var sharebleItems = [WrappedSharable]()
|
||||
|
||||
@MainActor
|
||||
init() {
|
||||
self.sharebleItems = [
|
||||
WrappedSharable(preview: AnyView(
|
||||
AllMoodsTotalTemplate(isPreview: true,
|
||||
startDate: PersistenceController.shared.earliestEntry?.forDate ?? Date(),
|
||||
startDate: DataController.shared.earliestEntry?.forDate ?? Date(),
|
||||
endDate: Date(),
|
||||
fakeData: false)
|
||||
),destination: AnyView(
|
||||
AllMoodsTotalTemplate(isPreview: false,
|
||||
startDate: PersistenceController.shared.earliestEntry?.forDate ?? Date(),
|
||||
startDate: DataController.shared.earliestEntry?.forDate ?? Date(),
|
||||
endDate: Date(),
|
||||
fakeData: false)
|
||||
),description: AllMoodsTotalTemplate.description),
|
||||
@@ -62,12 +63,12 @@ struct SharingListView: View {
|
||||
//////////////////////////////////////////////////////////
|
||||
WrappedSharable(preview: AnyView(
|
||||
LongestStreakTemplate(isPreview: true,
|
||||
startDate: PersistenceController.shared.earliestEntry?.forDate ?? Date(),
|
||||
startDate: DataController.shared.earliestEntry?.forDate ?? Date(),
|
||||
endDate: Date(),
|
||||
fakeData: false)
|
||||
), destination: AnyView(
|
||||
LongestStreakTemplate(isPreview: false,
|
||||
startDate: PersistenceController.shared.earliestEntry?.forDate ?? Date(),
|
||||
startDate: DataController.shared.earliestEntry?.forDate ?? Date(),
|
||||
endDate: Date(),
|
||||
fakeData: false)
|
||||
), description: LongestStreakTemplate.description),
|
||||
|
||||
@@ -24,24 +24,25 @@ struct AllMoodsTotalTemplate: View, SharingTemplate {
|
||||
|
||||
@StateObject private var shareImage = StupidAssShareObservableObject()
|
||||
private var entries = [MoodMetrics]()
|
||||
|
||||
@MainActor
|
||||
init(isPreview: Bool, startDate: Date, endDate: Date, fakeData: Bool) {
|
||||
self.isPreview = isPreview
|
||||
self.startDate = startDate
|
||||
self.endDate = endDate
|
||||
|
||||
var moodEntries: [MoodEntry]?
|
||||
|
||||
|
||||
var moodEntries: [MoodEntryModel]?
|
||||
|
||||
if fakeData {
|
||||
moodEntries = PersistenceController.shared.randomEntries(count: 10)
|
||||
moodEntries = DataController.shared.randomEntries(count: 10)
|
||||
} else {
|
||||
|
||||
moodEntries = PersistenceController.shared.getData(startDate:startDate,
|
||||
endDate: endDate,
|
||||
includedDays: [1,2,3,4,5,6,7])
|
||||
moodEntries = DataController.shared.getData(startDate:startDate,
|
||||
endDate: endDate,
|
||||
includedDays: [1,2,3,4,5,6,7])
|
||||
}
|
||||
|
||||
|
||||
totalEntryCount = moodEntries?.count ?? 0
|
||||
|
||||
|
||||
if let moodEntries = moodEntries {
|
||||
entries = Random.createTotalPerc(fromEntries: moodEntries)
|
||||
entries = entries.sorted(by: {
|
||||
|
||||
@@ -11,12 +11,12 @@ struct CurrentStreakTemplate: View, SharingTemplate {
|
||||
static var description: String {
|
||||
"Last 10 Days"
|
||||
}
|
||||
|
||||
|
||||
var isPreview: Bool
|
||||
var startDate: Date
|
||||
var endDate: Date
|
||||
let moodEntries: [MoodEntry]
|
||||
|
||||
let moodEntries: [MoodEntryModel]
|
||||
|
||||
@State var showSharingTemplate = false
|
||||
@StateObject private var shareImage = StupidAssShareObservableObject()
|
||||
|
||||
@@ -32,24 +32,24 @@ struct CurrentStreakTemplate: View, SharingTemplate {
|
||||
GridItem(.flexible(minimum: 5, maximum: .infinity), alignment: .center),
|
||||
GridItem(.flexible(minimum: 5, maximum: .infinity), alignment: .center)
|
||||
]
|
||||
|
||||
|
||||
@MainActor
|
||||
init(isPreview: Bool, startDate: Date, endDate: Date, fakeData: Bool) {
|
||||
self.isPreview = isPreview
|
||||
self.startDate = startDate
|
||||
self.endDate = endDate
|
||||
|
||||
var _moodEntries: [MoodEntry]?
|
||||
|
||||
|
||||
var _moodEntries: [MoodEntryModel]?
|
||||
|
||||
if fakeData {
|
||||
_moodEntries = PersistenceController.shared.randomEntries(count: 10)
|
||||
_moodEntries = DataController.shared.randomEntries(count: 10)
|
||||
} else {
|
||||
|
||||
_moodEntries = PersistenceController.shared.getData(startDate:startDate,
|
||||
endDate: endDate,
|
||||
includedDays: [1,2,3,4,5,6,7])
|
||||
_moodEntries = DataController.shared.getData(startDate:startDate,
|
||||
endDate: endDate,
|
||||
includedDays: [1,2,3,4,5,6,7])
|
||||
}
|
||||
|
||||
self.moodEntries = _moodEntries ?? [MoodEntry]()
|
||||
|
||||
self.moodEntries = _moodEntries ?? [MoodEntryModel]()
|
||||
}
|
||||
|
||||
var image: UIImage {
|
||||
|
||||
@@ -24,7 +24,7 @@ struct LongestStreakTemplate: View, SharingTemplate {
|
||||
var endDate: Date
|
||||
var fakeData: Bool
|
||||
|
||||
@State var moodEntries = [MoodEntry]()
|
||||
@State var moodEntries = [MoodEntryModel]()
|
||||
@State var selectedMood: Mood = .great
|
||||
|
||||
@State var showSharingTemplate = false
|
||||
@@ -57,28 +57,29 @@ struct LongestStreakTemplate: View, SharingTemplate {
|
||||
return image
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func configureData(fakeData: Bool, mood: Mood) {
|
||||
var _moodEntries: [MoodEntry]?
|
||||
var _moodEntries: [MoodEntryModel]?
|
||||
|
||||
if fakeData {
|
||||
_moodEntries = PersistenceController.shared.randomEntries(count: 10)
|
||||
_moodEntries = DataController.shared.randomEntries(count: 10)
|
||||
} else {
|
||||
_moodEntries = PersistenceController.shared.getData(startDate:startDate,
|
||||
endDate: endDate,
|
||||
includedDays: [1,2,3,4,5,6,7])
|
||||
_moodEntries = DataController.shared.getData(startDate:startDate,
|
||||
endDate: endDate,
|
||||
includedDays: [1,2,3,4,5,6,7])
|
||||
}
|
||||
let data = _moodEntries ?? [MoodEntry]()
|
||||
|
||||
let data = _moodEntries ?? [MoodEntryModel]()
|
||||
|
||||
var splitArrays = createSubArrays(fromMoodEntries: data, splitOn: mood)
|
||||
splitArrays = splitArrays.sorted(by: {
|
||||
$0.count > $1.count
|
||||
} )
|
||||
self.moodEntries = splitArrays.first ?? [MoodEntry]()
|
||||
self.moodEntries = splitArrays.first ?? [MoodEntryModel]()
|
||||
}
|
||||
|
||||
private func createSubArrays(fromMoodEntries: [MoodEntry], splitOn: Mood) -> [[MoodEntry]] {
|
||||
var splitArrays = [[MoodEntry]]()
|
||||
var currentSplit = [MoodEntry]()
|
||||
|
||||
private func createSubArrays(fromMoodEntries: [MoodEntryModel], splitOn: Mood) -> [[MoodEntryModel]] {
|
||||
var splitArrays = [[MoodEntryModel]]()
|
||||
var currentSplit = [MoodEntryModel]()
|
||||
for entry in fromMoodEntries {
|
||||
if entry.mood == splitOn {
|
||||
currentSplit.append(entry)
|
||||
|
||||
@@ -28,8 +28,8 @@ struct MonthTotalTemplate: View, SharingTemplate {
|
||||
@AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = .white
|
||||
|
||||
private var moodMetrics = [MoodMetrics]()
|
||||
private var moodEntries = [MoodEntry]()
|
||||
|
||||
private var moodEntries = [MoodEntryModel]()
|
||||
|
||||
let columns = [
|
||||
GridItem(.flexible(minimum: 5, maximum: .infinity), alignment: .center),
|
||||
GridItem(.flexible(minimum: 5, maximum: .infinity), alignment: .center),
|
||||
@@ -39,30 +39,25 @@ struct MonthTotalTemplate: View, SharingTemplate {
|
||||
GridItem(.flexible(minimum: 5, maximum: .infinity), alignment: .center),
|
||||
GridItem(.flexible(minimum: 5, maximum: .infinity), alignment: .center)
|
||||
]
|
||||
|
||||
|
||||
@MainActor
|
||||
init(isPreview: Bool, startDate: Date, endDate: Date, fakeData: Bool) {
|
||||
self.isPreview = isPreview
|
||||
self.startDate = startDate
|
||||
self.endDate = endDate
|
||||
|
||||
var _moodEntries: [MoodEntry]?
|
||||
|
||||
|
||||
var _moodEntries: [MoodEntryModel]?
|
||||
|
||||
if fakeData {
|
||||
_moodEntries = PersistenceController.shared.randomEntries(count: 10)
|
||||
_moodEntries = DataController.shared.randomEntries(count: 10)
|
||||
} else {
|
||||
|
||||
_moodEntries = PersistenceController.shared.getData(startDate: startDate,
|
||||
endDate: endDate,
|
||||
includedDays: [1,2,3,4,5,6,7])
|
||||
|
||||
// _moodEntries = PersistenceController.shared.getData(startDate:Calendar.current.date(byAdding: .day, value: -33, to: Date())!,
|
||||
// endDate: Date(),
|
||||
// includedDays: [1,2,3,4,5,6,7])
|
||||
|
||||
_moodEntries = DataController.shared.getData(startDate: startDate,
|
||||
endDate: endDate,
|
||||
includedDays: [1,2,3,4,5,6,7])
|
||||
}
|
||||
|
||||
moodEntries = _moodEntries ?? [MoodEntry]()
|
||||
|
||||
|
||||
moodEntries = _moodEntries ?? [MoodEntryModel]()
|
||||
|
||||
totalEntryCount = moodEntries.count
|
||||
moodMetrics = Random.createTotalPerc(fromEntries: moodEntries)
|
||||
moodMetrics = moodMetrics.sorted(by: {
|
||||
|
||||
@@ -10,18 +10,18 @@ import SwiftUI
|
||||
struct SmallRollUpHeaderView: View {
|
||||
@Binding var viewType: MainSwitchableViewType
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.shape.rawValue, store: GroupUserDefaults.groupDefaults) private var shape: BGShape = .circle
|
||||
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor
|
||||
|
||||
let entries: [MoodEntry]
|
||||
let entries: [MoodEntryModel]
|
||||
private var moodMetrics = [MoodMetrics]()
|
||||
|
||||
init(entries: [MoodEntry], viewType: Binding<MainSwitchableViewType>) {
|
||||
|
||||
init(entries: [MoodEntryModel], viewType: Binding<MainSwitchableViewType>) {
|
||||
self.entries = entries
|
||||
self._viewType = viewType
|
||||
|
||||
|
||||
moodMetrics = Random.createTotalPerc(fromEntries: entries)
|
||||
}
|
||||
|
||||
@@ -85,16 +85,16 @@ struct SmallRollUpHeaderView: View {
|
||||
struct SmallHeaderView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
SmallRollUpHeaderView(entries: PersistenceController.shared.randomEntries(count: 10),
|
||||
SmallRollUpHeaderView(entries: DataController.shared.randomEntries(count: 10),
|
||||
viewType: .constant(.total))
|
||||
|
||||
SmallRollUpHeaderView(entries: PersistenceController.shared.randomEntries(count: 10),
|
||||
|
||||
SmallRollUpHeaderView(entries: DataController.shared.randomEntries(count: 10),
|
||||
viewType: .constant(.percentageShape))
|
||||
.background(.gray)
|
||||
|
||||
SmallRollUpHeaderView(entries: PersistenceController.shared.randomEntries(count: 10),
|
||||
|
||||
SmallRollUpHeaderView(entries: DataController.shared.randomEntries(count: 10),
|
||||
viewType: .constant(.percentage))
|
||||
|
||||
|
||||
.background(.gray)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,17 +6,15 @@
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import CoreData
|
||||
import SwiftData
|
||||
|
||||
struct YearView: View {
|
||||
let months = [(0, "J"), (1, "F"), (2,"M"), (3,"A"), (4,"M"), (5, "J"), (6,"J"), (7,"A"), (8,"S"), (9,"O"), (10, "N"), (11,"D")]
|
||||
|
||||
@State private var toggle = true
|
||||
|
||||
@FetchRequest(
|
||||
sortDescriptors: [NSSortDescriptor(keyPath: \MoodEntry.forDate, ascending: false)],
|
||||
animation: .spring())
|
||||
private var items: FetchedResults<MoodEntry>
|
||||
@Query(sort: \MoodEntryModel.forDate, order: .reverse)
|
||||
private var items: [MoodEntryModel]
|
||||
|
||||
@AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
|
||||
@AppStorage(UserDefaultsStore.Keys.moodTint.rawValue, store: GroupUserDefaults.groupDefaults) private var moodTint: MoodTints = .Default
|
||||
@@ -128,10 +126,10 @@ struct YearCard: View {
|
||||
private let months = ["J", "F", "M", "A", "M", "J", "J", "A", "S", "O", "N", "D"]
|
||||
private let heatmapColumns = Array(repeating: GridItem(.flexible(), spacing: 2), count: 12)
|
||||
|
||||
private var yearEntries: [MoodEntry] {
|
||||
private var yearEntries: [MoodEntryModel] {
|
||||
let firstOfYear = Calendar.current.date(from: DateComponents(year: year, month: 1, day: 1))!
|
||||
let lastOfYear = Calendar.current.date(from: DateComponents(year: year + 1, month: 1, day: 1))!
|
||||
return PersistenceController.shared.getData(startDate: firstOfYear, endDate: lastOfYear, includedDays: filteredDays)
|
||||
return DataController.shared.getData(startDate: firstOfYear, endDate: lastOfYear, includedDays: filteredDays)
|
||||
}
|
||||
|
||||
private var metrics: [MoodMetrics] {
|
||||
|
||||
@@ -7,41 +7,42 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
class YearViewModel: ObservableObject {
|
||||
@MainActor
|
||||
class YearViewModel: ObservableObject {
|
||||
@Published public var entryStartDate: Date = Date()
|
||||
@Published public var entryEndDate: Date = Date()
|
||||
@Published var selectedDays = [Int]()
|
||||
|
||||
|
||||
// year, month, items
|
||||
@Published public private(set) var data = [Int: [Int: [DayChartView]]]()
|
||||
@Published public private(set) var numberOfRatings: Int = 0
|
||||
public private(set) var uncategorizedData = [MoodEntry]() {
|
||||
public private(set) var uncategorizedData = [MoodEntryModel]() {
|
||||
didSet {
|
||||
self.numberOfRatings = uncategorizedData.count
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
init() {
|
||||
updateData()
|
||||
}
|
||||
|
||||
|
||||
private func updateData() {
|
||||
let filteredEntries = PersistenceController.shared.getData(startDate: Date(timeIntervalSince1970: 0),
|
||||
endDate: Date(),
|
||||
includedDays: selectedDays)
|
||||
|
||||
if let fuckingDAte = filteredEntries.sorted(by: { $0.forDate! < $1.forDate! }).first?.forDate {
|
||||
self.entryStartDate = fuckingDAte
|
||||
let filteredEntries = DataController.shared.getData(startDate: Date(timeIntervalSince1970: 0),
|
||||
endDate: Date(),
|
||||
includedDays: selectedDays)
|
||||
|
||||
if let firstDate = filteredEntries.sorted(by: { $0.forDate < $1.forDate }).first?.forDate {
|
||||
self.entryStartDate = firstDate
|
||||
}
|
||||
self.entryEndDate = Date()
|
||||
}
|
||||
|
||||
|
||||
private let chartViewBuilder = DayChartViewChartBuilder()
|
||||
|
||||
|
||||
public func filterEntries(startDate: Date, endDate: Date) {
|
||||
let filteredEntries = PersistenceController.shared.getData(startDate: startDate,
|
||||
endDate: endDate,
|
||||
includedDays: selectedDays)
|
||||
let filteredEntries = DataController.shared.getData(startDate: startDate,
|
||||
endDate: endDate,
|
||||
includedDays: selectedDays)
|
||||
data.removeAll()
|
||||
let filledOutData = chartViewBuilder.buildGridData(withData: filteredEntries)
|
||||
data = filledOutData
|
||||
|
||||
Reference in New Issue
Block a user