diff --git a/Feels.xcodeproj/project.pbxproj b/Feels.xcodeproj/project.pbxproj index 68642c4..38a7c46 100644 --- a/Feels.xcodeproj/project.pbxproj +++ b/Feels.xcodeproj/project.pbxproj @@ -160,6 +160,7 @@ 1CAD603227A5C1C800C520BD /* ContentView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = ""; }; 1CAD603327A5C1C800C520BD /* HeaderStatsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeaderStatsView.swift; sourceTree = ""; }; 1CAD603D27A6ECCD00C520BD /* SwitchableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwitchableView.swift; sourceTree = ""; }; + 1CC03FA627B5865600B530AF /* Shared 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Shared 2.xcdatamodel"; sourceTree = ""; }; 1CC469A9278F30A0003E0C6E /* BGTask.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGTask.swift; sourceTree = ""; }; 1CC469AB27907D48003E0C6E /* DayChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DayChartView.swift; sourceTree = ""; }; 1CD90AEC278C7DDF001C4FEA /* Shared.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Shared.xcdatamodel; sourceTree = ""; }; @@ -1227,9 +1228,10 @@ 1CD90AEB278C7DDF001C4FEA /* Feels.xcdatamodeld */ = { isa = XCVersionGroup; children = ( + 1CC03FA627B5865600B530AF /* Shared 2.xcdatamodel */, 1CD90AEC278C7DDF001C4FEA /* Shared.xcdatamodel */, ); - currentVersion = 1CD90AEC278C7DDF001C4FEA /* Shared.xcdatamodel */; + currentVersion = 1CC03FA627B5865600B530AF /* Shared 2.xcdatamodel */; path = Feels.xcdatamodeld; sourceTree = ""; versionGroupType = wrapper.xcdatamodel; diff --git a/Shared/AppDelegate.swift b/Shared/AppDelegate.swift index 5b0e2a1..f9fa15d 100644 --- a/Shared/AppDelegate.swift +++ b/Shared/AppDelegate.swift @@ -16,9 +16,14 @@ class AppDelegate: NSObject, UIApplicationDelegate { func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { // PersistenceController.shared.clearDB() + PersistenceController.shared.fillInMissingDates() UNUserNotificationCenter.current().delegate = self return true } + + func applicationWillEnterForeground(_ application: UIApplication) { + PersistenceController.shared.fillInMissingDates() + } } extension AppDelegate: UNUserNotificationCenterDelegate { @@ -42,15 +47,15 @@ extension AppDelegate: UNUserNotificationCenterDelegate { switch action { case .horrible: - PersistenceController.shared.add(mood: .horrible, forDate: date) + PersistenceController.shared.add(mood: .horrible, forDate: date, entryType: .notification) case .bad: - PersistenceController.shared.add(mood: .bad, forDate: date) + PersistenceController.shared.add(mood: .bad, forDate: date, entryType: .notification) case .average: - PersistenceController.shared.add(mood: .average, forDate: date) + PersistenceController.shared.add(mood: .average, forDate: date, entryType: .notification) case .good: - PersistenceController.shared.add(mood: .good, forDate: date) + PersistenceController.shared.add(mood: .good, forDate: date, entryType: .notification) case .great: - PersistenceController.shared.add(mood: .great, forDate: date) + PersistenceController.shared.add(mood: .great, forDate: date, entryType: .notification) } UIApplication.shared.applicationIconBadgeNumber = 0 } diff --git a/Shared/Feels.xcdatamodeld/.xccurrentversion b/Shared/Feels.xcdatamodeld/.xccurrentversion index 775cb51..bc6bac5 100644 --- a/Shared/Feels.xcdatamodeld/.xccurrentversion +++ b/Shared/Feels.xcdatamodeld/.xccurrentversion @@ -3,6 +3,6 @@ _XCCurrentVersionName - Shared.xcdatamodel + Shared 2.xcdatamodel diff --git a/Shared/Feels.xcdatamodeld/Shared 2.xcdatamodel/contents b/Shared/Feels.xcdatamodeld/Shared 2.xcdatamodel/contents new file mode 100644 index 0000000..8863425 --- /dev/null +++ b/Shared/Feels.xcdatamodeld/Shared 2.xcdatamodel/contents @@ -0,0 +1,15 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Shared/FeelsApp.swift b/Shared/FeelsApp.swift index d65ebb3..0e1c5d9 100644 --- a/Shared/FeelsApp.swift +++ b/Shared/FeelsApp.swift @@ -36,7 +36,6 @@ struct FeelsApp: App { if phase == .active { UIApplication.shared.applicationIconBadgeNumber = 0 - persistenceController.fillInMissingDates() } } } diff --git a/Shared/Models/ContentModeViewModel.swift b/Shared/Models/ContentModeViewModel.swift index 1b8b2dc..49157b8 100644 --- a/Shared/Models/ContentModeViewModel.swift +++ b/Shared/Models/ContentModeViewModel.swift @@ -86,8 +86,8 @@ class ContentModeViewModel: ObservableObject { getGroupedData() } - public func add(mood: Mood, forDate date: Date) { - PersistenceController.shared.add(mood: mood, forDate: date) + public func add(mood: Mood, forDate date: Date, entryType: EntryType) { + PersistenceController.shared.add(mood: mood, forDate: date, entryType: entryType) getGroupedData() } @@ -108,7 +108,7 @@ class ContentModeViewModel: ObservableObject { fatalError("Unresolved error \(nsError), \(nsError.userInfo)") } - PersistenceController.shared.add(mood: mood, forDate: forDate) + PersistenceController.shared.add(mood: mood, forDate: forDate, entryType: .listView) do { try PersistenceController.shared.viewContext.save() @@ -135,7 +135,7 @@ class ContentModeViewModel: ObservableObject { entriesToDelete.forEach({ entry in let entryDate = entry.forDate! PersistenceController.shared.viewContext.delete(entry) - self.add(mood: .missing, forDate: entryDate) + self.add(mood: .missing, forDate: entryDate, entryType: .listView) }) } diff --git a/Shared/Models/MoodEntryExtension.swift b/Shared/Models/MoodEntryExtension.swift index b22725a..092f404 100644 --- a/Shared/Models/MoodEntryExtension.swift +++ b/Shared/Models/MoodEntryExtension.swift @@ -7,6 +7,11 @@ import Foundation +enum EntryType: Int { + case notification + case header + case listView +} extension MoodEntry { var moodString: String { diff --git a/Shared/Persistence.swift b/Shared/Persistence.swift index 3aabd0e..6e19cf8 100644 --- a/Shared/Persistence.swift +++ b/Shared/Persistence.swift @@ -34,7 +34,12 @@ class PersistenceController { return data.first } - public func add(mood: Mood, forDate date: Date) { + public func add(mood: Mood, forDate date: Date, entryType: EntryType) { + if let existingEntry = getEntry(byDate: date) { + viewContext.delete(existingEntry) + try? viewContext.save() + } + let newItem = MoodEntry(context: viewContext) newItem.timestamp = Date() newItem.moodValue = Int16(mood.rawValue) @@ -42,6 +47,7 @@ class PersistenceController { newItem.weekDay = Int16(Calendar.current.component(.weekday, from: date)) newItem.canEdit = true newItem.canDelete = true + newItem.entryType = Int16(entryType.rawValue) do { try viewContext.save() @@ -139,14 +145,26 @@ class PersistenceController { fetchRequest.sortDescriptors = [NSSortDescriptor(key: "forDate", ascending: false)] let entries = try! viewContext.fetch(fetchRequest) - if let earliestDate = entries.last?.forDate, - let diffInDays = Calendar.current.dateComponents([.day], from: earliestDate, to: Date()).day, - diffInDays > 1 { - for idx in 1..) + for date in missing { + add(mood: .missing, forDate: date, entryType: .listView) } } } @@ -202,6 +220,8 @@ class PersistenceController { for description in container.persistentStoreDescriptions { description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey) description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey) + description.setOption(true as NSNumber, forKey: NSMigratePersistentStoresAutomaticallyOption) + description.setOption(true as NSNumber, forKey: NSInferMappingModelAutomaticallyOption) } container.loadPersistentStores(completionHandler: { (storeDescription, error) in diff --git a/Shared/Random.swift b/Shared/Random.swift index f818233..b211282 100644 --- a/Shared/Random.swift +++ b/Shared/Random.swift @@ -69,3 +69,17 @@ extension View { } } } + +extension Date { + static func dates(from fromDate: Date, to toDate: Date) -> [Date] { + var dates: [Date] = [] + var date = fromDate + + while date <= toDate { + dates.append(date) + guard let newDate = Calendar.current.date(byAdding: .day, value: 1, to: date) else { break } + date = newDate + } + return dates + } +} diff --git a/Shared/views/ContentView.swift b/Shared/views/ContentView.swift index 985690f..8871491 100644 --- a/Shared/views/ContentView.swift +++ b/Shared/views/ContentView.swift @@ -71,6 +71,7 @@ struct ContentView: View { viewModel.update(entry: selectedEntry, toMood: mood) } showUpdateEntryAlert = false + selectedEntry = nil }) } @@ -279,7 +280,7 @@ struct ContentView: View { if viewModel.shouldShowVotingHeader() { AddMoodHeaderView(addItemHeaderClosure: { (mood, date) in withAnimation { - viewModel.add(mood: mood, forDate: date) + viewModel.add(mood: mood, forDate: date, entryType: .header) } }) .frame(height: headerHeight) @@ -319,7 +320,7 @@ struct ContentView: View { .padding() AddMoodHeaderView(addItemHeaderClosure: { (mood, date) in withAnimation { - viewModel.add(mood: mood, forDate: date) + viewModel.add(mood: mood, forDate: date, entryType: .header) } }, overrideDay: viewModel.shouldShowVotingHeader() ? .Today : .Previous) } @@ -368,6 +369,10 @@ struct ContentView: View { theme.currentTheme.bg .edgesIgnoringSafeArea(.all) ) + .onReceive(NotificationCenter.default.publisher(for: UIApplication.willEnterForegroundNotification)) { _ in + PersistenceController.shared.fillInMissingDates() + viewModel.updateData() + } } } diff --git a/Shared/views/SmallRollUpHeaderView.swift b/Shared/views/SmallRollUpHeaderView.swift index 6165dcc..32593ad 100644 --- a/Shared/views/SmallRollUpHeaderView.swift +++ b/Shared/views/SmallRollUpHeaderView.swift @@ -58,13 +58,20 @@ struct SmallRollUpHeaderView: View { private var circularViews: some View { HStack { ForEach(entries, id: \.0) { (mood, value) in - Text(String(value)) - .font(.title) - .fontWeight(.bold) - .frame(maxWidth: .infinity) - .padding() - .background(Circle().fill(mood.color)) - .foregroundColor(Color(UIColor.white)) + ZStack { + Circle().fill(mood.color) + .frame(width: 50, height: 50) + + Text(String(value)) + .font(.title) + .fontWeight(.bold) + .frame(maxWidth: 50) + .foregroundColor(Color(UIColor.white)) + .scaledToFill() + .minimumScaleFactor(0.5) + .lineLimit(1) + } + .padding([.leading, .trailing], 5) } } }