diff --git a/Feels.xcodeproj/project.pbxproj b/Feels.xcodeproj/project.pbxproj index 23ca716..6f49279 100644 --- a/Feels.xcodeproj/project.pbxproj +++ b/Feels.xcodeproj/project.pbxproj @@ -14,6 +14,7 @@ 1C412082278F2B8800D9153A /* FilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C412081278F2B8800D9153A /* FilterView.swift */; }; 1C412083278F2B8800D9153A /* FilterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C412081278F2B8800D9153A /* FilterView.swift */; }; 1C5F4976279C84090092F1B4 /* OnboardingData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5F4975279C84090092F1B4 /* OnboardingData.swift */; }; + 1C5F4978279C945E0092F1B4 /* UserDefaultsStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C5F4977279C945E0092F1B4 /* UserDefaultsStore.swift */; }; 1C683FCA2792281400745862 /* Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C683FC92792281400745862 /* Stats.swift */; }; 1C683FCB2792281400745862 /* Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C683FC92792281400745862 /* Stats.swift */; }; 1C683FCC2792281400745862 /* Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C683FC92792281400745862 /* Stats.swift */; }; @@ -116,6 +117,7 @@ 1C26190627960DC900FDC148 /* ChartViewItemBuildable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartViewItemBuildable.swift; sourceTree = ""; }; 1C412081278F2B8800D9153A /* FilterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterView.swift; sourceTree = ""; }; 1C5F4975279C84090092F1B4 /* OnboardingData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingData.swift; sourceTree = ""; }; + 1C5F4977279C945E0092F1B4 /* UserDefaultsStore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsStore.swift; sourceTree = ""; }; 1C683FC92792281400745862 /* Stats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Stats.swift; sourceTree = ""; }; 1C6B37792799B78A001EF820 /* BGView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGView.swift; sourceTree = ""; }; 1C744F2B278CE15600953A57 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -220,6 +222,7 @@ 1CA03771279A291F00D26164 /* Onboarding */ = { isa = PBXGroup; children = ( + 1C5F4975279C84090092F1B4 /* OnboardingData.swift */, 1CA03778279A295F00D26164 /* views */, ); path = Onboarding; @@ -351,12 +354,12 @@ 1CD90B60278C7EBA001C4FEA /* Models */ = { isa = PBXGroup; children = ( + 1C5F4977279C945E0092F1B4 /* UserDefaultsStore.swift */, 1CA0376F2799FFA600D26164 /* ContentModeViewModel.swift */, 1CC469AB27907D48003E0C6E /* DayChartView.swift */, 1CD90B61278C7EBA001C4FEA /* Mood.swift */, 1CD90B62278C7EBA001C4FEA /* MoodEntryExtension.swift */, 1C2618FD27960A4F00FDC148 /* FilterViewModel.swift */, - 1C5F4975279C84090092F1B4 /* OnboardingData.swift */, ); path = Models; sourceTree = ""; @@ -582,6 +585,7 @@ 1CD90B66278C7EBA001C4FEA /* MoodEntryExtension.swift in Sources */, 1CD90B1C278C7DE0001C4FEA /* Persistence.swift in Sources */, 1CA0377A279A296E00D26164 /* OnboardingMain.swift in Sources */, + 1C5F4978279C945E0092F1B4 /* UserDefaultsStore.swift in Sources */, 1C412082278F2B8800D9153A /* FilterView.swift in Sources */, 1CD90B18278C7DE0001C4FEA /* FeelsApp.swift in Sources */, 1CA03777279A295600D26164 /* OnboardingTitle.swift in Sources */, diff --git a/Shared/AppDelegate.swift b/Shared/AppDelegate.swift index d0abcbf..195fe1e 100644 --- a/Shared/AppDelegate.swift +++ b/Shared/AppDelegate.swift @@ -9,9 +9,12 @@ import Foundation import UserNotifications import UIKit import WidgetKit +import SwiftUI // AppDelegate.swift class AppDelegate: NSObject, UIApplicationDelegate { + @AppStorage("savedOnboardingData") private var savedOnboardingData = OnboardingData() + func application(_ application: UIApplication, willFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { // PersistenceController.shared.clearDB() application.registerForRemoteNotifications() @@ -29,17 +32,27 @@ extension AppDelegate: UNUserNotificationCenterDelegate { func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { if let action = LocalNotification.ActionType(rawValue: response.actionIdentifier) { + var date: Date + + switch savedOnboardingData.inputDay { + case .Today: + date = Date() + case .Previous: + date = Calendar.current.date(byAdding: .day, value: -1, to: Date())! + } + + switch action { case .horrible: - PersistenceController.shared.add(mood: .horrible, forDate: Date()) + PersistenceController.shared.add(mood: .horrible, forDate: date) case .bad: - PersistenceController.shared.add(mood: .bad, forDate: Date()) + PersistenceController.shared.add(mood: .bad, forDate: date) case .average: - PersistenceController.shared.add(mood: .average, forDate: Date()) + PersistenceController.shared.add(mood: .average, forDate: date) case .good: - PersistenceController.shared.add(mood: .good, forDate: Date()) + PersistenceController.shared.add(mood: .good, forDate: date) case .great: - PersistenceController.shared.add(mood: .great, forDate: Date()) + PersistenceController.shared.add(mood: .great, forDate: date) } } WidgetCenter.shared.reloadAllTimelines() diff --git a/Shared/Models/ContentModeViewModel.swift b/Shared/Models/ContentModeViewModel.swift index f3a652f..cb97ce0 100644 --- a/Shared/Models/ContentModeViewModel.swift +++ b/Shared/Models/ContentModeViewModel.swift @@ -10,7 +10,8 @@ import CoreData class ContentModeViewModel: ObservableObject { @Published var grouped = [Int: [Int: [MoodEntry]]]() - + @Published public private(set) var savedOnboardingData = UserDefaultsStore.getOnboarding() + init() { updateData() } @@ -19,18 +20,30 @@ class ContentModeViewModel: ObservableObject { grouped = PersistenceController.shared.splitIntoYearMonth() } - public func shouldShowTodayInput() -> Bool { + public func shouldShowVotingHeader() -> Bool { + isMissingCurrentVote() && savedOnboardingData.ableToVoteBasedOnCurentTime() ? true : false + } + + public func updateOnboardingData(onboardingData: OnboardingData) { + self.savedOnboardingData = UserDefaultsStore.saveOnboarding(onboardingData: onboardingData) + } + + private func isMissingCurrentVote() -> Bool { let fetchRequest = NSFetchRequest(entityName: "MoodEntry") var calendar = Calendar.current calendar.timeZone = NSTimeZone.local - // Get today's beginning & end - let dateFrom = calendar.startOfDay(for: Date()) // eg. 2016-10-10 00:00:00 + var dateFrom: Date + switch savedOnboardingData.inputDay { + case .Today: + dateFrom = calendar.startOfDay(for: Date()) + case .Previous: + dateFrom = calendar.startOfDay(for: Date()) + dateFrom = calendar.date(byAdding: .day, value: -1, to: dateFrom)! + } let dateTo = calendar.date(byAdding: .day, value: 1, to: dateFrom)! - // Note: Times are printed in UTC. Depending on where you live it won't print 00:00:00 but it will work with UTC times which can be converted to local time - // Set predicate as date being today's date let fromPredicate = NSPredicate(format: "%@ <= %K", dateFrom as NSDate, #keyPath(MoodEntry.forDate)) let toPredicate = NSPredicate(format: "%K < %@", #keyPath(MoodEntry.forDate), dateTo as NSDate) let datePredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [fromPredicate, toPredicate]) @@ -45,7 +58,7 @@ class ContentModeViewModel: ObservableObject { } public func add(mood: Mood, forDate date: Date) { - PersistenceController.shared.add(mood: mood, forDate: Date()) + PersistenceController.shared.add(mood: mood, forDate: date) getGroupedData() } diff --git a/Shared/Models/UserDefaultsStore.swift b/Shared/Models/UserDefaultsStore.swift new file mode 100644 index 0000000..0806c55 --- /dev/null +++ b/Shared/Models/UserDefaultsStore.swift @@ -0,0 +1,29 @@ +// +// UserDefaultsStore.swift +// Feels (iOS) +// +// Created by Trey Tartt on 1/22/22. +// + +import Foundation + +class UserDefaultsStore { + static func getOnboarding() -> OnboardingData { + if let data = UserDefaults.standard.object(forKey: "savedOnboardingData") as? Data, + let model = try? JSONDecoder().decode(OnboardingData.self, from: data) { + return model + } else { + return OnboardingData() + } + } + + static func saveOnboarding(onboardingData: OnboardingData) -> OnboardingData { + do { + let data = try JSONEncoder().encode(onboardingData) + UserDefaults.standard.set(data, forKey: "savedOnboardingData") + return UserDefaultsStore.getOnboarding() + } catch { + fatalError("error saving") + } + } +} diff --git a/Shared/Models/OnboardingData.swift b/Shared/Onboarding/OnboardingData.swift similarity index 100% rename from Shared/Models/OnboardingData.swift rename to Shared/Onboarding/OnboardingData.swift diff --git a/Shared/Onboarding/views/OnboardingMain.swift b/Shared/Onboarding/views/OnboardingMain.swift index 85a670a..99855fa 100644 --- a/Shared/Onboarding/views/OnboardingMain.swift +++ b/Shared/Onboarding/views/OnboardingMain.swift @@ -11,7 +11,7 @@ struct OnboardingMain: View { @Environment(\.presentationMode) var presentationMode @State var onboardingData: OnboardingData - let completionClosure: ((OnboardingData) -> Void) + let updateBoardingDataClosure: ((OnboardingData) -> Void) var body: some View { TabView { @@ -22,7 +22,7 @@ struct OnboardingMain: View { OnboardingTitle(onboardingData: onboardingData) OnboardingWrapup(onboardingData: onboardingData, completionClosure: { _ in - completionClosure(onboardingData) + updateBoardingDataClosure(onboardingData) }) } .ignoresSafeArea() @@ -42,7 +42,7 @@ struct OnboardingMain: View { struct OnboardingMain_Previews: PreviewProvider { static var previews: some View { OnboardingMain(onboardingData: OnboardingData(), - completionClosure: { _ in + updateBoardingDataClosure: { _ in }) } diff --git a/Shared/views/AddMoodHeaderView.swift b/Shared/views/AddMoodHeaderView.swift index 20c0ee8..170bf50 100644 --- a/Shared/views/AddMoodHeaderView.swift +++ b/Shared/views/AddMoodHeaderView.swift @@ -11,8 +11,9 @@ import SwiftUI import CoreData struct AddMoodHeaderView: View { - @Environment(\.managedObjectContext) private var viewContext - let addItemClosure: ((Mood, Date) -> Void) + private let savedOnboardingData = UserDefaultsStore.getOnboarding() + + let addItemHeaderClosure: ((Mood, Date) -> Void) var body: some View { ZStack { @@ -49,26 +50,32 @@ struct AddMoodHeaderView: View { } private func addItem(withMood mood: Mood) { - addItemClosure(mood, Date()) + switch savedOnboardingData.inputDay { + case .Today: + addItemHeaderClosure(mood, Date()) + case .Previous: + let date = Calendar.current.date(byAdding: .day, value: -1, to: Date())! + addItemHeaderClosure(mood, date) + } } } struct AddMoodHeaderView_Previews: PreviewProvider { static var previews: some View { Group { - AddMoodHeaderView(addItemClosure: { (_,_) in + AddMoodHeaderView(addItemHeaderClosure: { (_,_) in }).environment(\.managedObjectContext, PersistenceController.shared.container.viewContext) - AddMoodHeaderView(addItemClosure: { (_,_) in + AddMoodHeaderView(addItemHeaderClosure: { (_,_) in }).preferredColorScheme(.dark).environment(\.managedObjectContext, PersistenceController.shared.container.viewContext) - AddMoodHeaderView(addItemClosure: { (_,_) in + AddMoodHeaderView(addItemHeaderClosure: { (_,_) in }).environment(\.managedObjectContext, PersistenceController.shared.container.viewContext) - AddMoodHeaderView(addItemClosure: { (_,_) in + AddMoodHeaderView(addItemHeaderClosure: { (_,_) in }).preferredColorScheme(.dark).environment(\.managedObjectContext, PersistenceController.shared.container.viewContext) } diff --git a/Shared/views/ContentView.swift b/Shared/views/ContentView.swift index 8999448..8907eea 100644 --- a/Shared/views/ContentView.swift +++ b/Shared/views/ContentView.swift @@ -18,8 +18,6 @@ struct ContentView: View { @ObservedObject var viewModel = ContentModeViewModel() - @AppStorage("savedOnboardingData") private var savedOnboardingData = OnboardingData() - init(){ UITabBar.appearance().backgroundColor = UIColor.systemBackground } @@ -43,10 +41,10 @@ struct ContentView: View { }.sheet(isPresented: $needsOnboarding, onDismiss: { }, content: { - OnboardingMain(onboardingData: savedOnboardingData, - completionClosure: { onboardingData in + OnboardingMain(onboardingData: viewModel.savedOnboardingData, + updateBoardingDataClosure: { onboardingData in needsOnboarding = false - savedOnboardingData = onboardingData + viewModel.updateOnboardingData(onboardingData: onboardingData) }) }) } @@ -65,6 +63,8 @@ struct ContentView: View { withAnimation{ viewModel.updateData() } + }, updateBoardingDataClosure: { onboardingData in + viewModel.updateOnboardingData(onboardingData: onboardingData) }) }.padding(.trailing) } @@ -170,8 +170,8 @@ struct ContentView: View { BGView() VStack{ settingsButtonView - if viewModel.shouldShowTodayInput() && savedOnboardingData.ableToVoteBasedOnCurentTime() { - AddMoodHeaderView(addItemClosure: { (mood, date) in + if viewModel.shouldShowVotingHeader() { + AddMoodHeaderView(addItemHeaderClosure: { (mood, date) in withAnimation { viewModel.add(mood: mood, forDate: date) } diff --git a/Shared/views/SettingsView.swift b/Shared/views/SettingsView.swift index cc6bf92..670c7ff 100644 --- a/Shared/views/SettingsView.swift +++ b/Shared/views/SettingsView.swift @@ -11,11 +11,10 @@ struct SettingsView: View { @Environment(\.dismiss) var dismiss let editedDataClosure: (() -> Void) + let updateBoardingDataClosure: ((OnboardingData) -> Void) + @State private var showOnboarding = false - - @AppStorage("savedOnboardingData") private var savedOnboardingData = OnboardingData() - @AppStorage("showReminder") private var showReminder: Bool = false - + var body: some View { ZStack { Color(UIColor.secondarySystemBackground) @@ -33,10 +32,10 @@ struct SettingsView: View { } .padding() }.sheet(isPresented: $showOnboarding) { - OnboardingMain(onboardingData: savedOnboardingData, - completionClosure: { onboardingData in + OnboardingMain(onboardingData: UserDefaultsStore.getOnboarding(), + updateBoardingDataClosure: { onboardingData in + updateBoardingDataClosure(onboardingData) showOnboarding = false - savedOnboardingData = onboardingData }) } } @@ -177,10 +176,14 @@ struct SettingsView_Previews: PreviewProvider { static var previews: some View { SettingsView(editedDataClosure: { + }, updateBoardingDataClosure: { _ in + }) SettingsView(editedDataClosure: { + }, updateBoardingDataClosure: { _ in + }) .preferredColorScheme(.dark) }