diff --git a/Feels.xcodeproj/project.pbxproj b/Feels.xcodeproj/project.pbxproj index b77a46a..1bab261 100644 --- a/Feels.xcodeproj/project.pbxproj +++ b/Feels.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ 1C683FCB2792281400745862 /* Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C683FC92792281400745862 /* Stats.swift */; }; 1C683FCC2792281400745862 /* Stats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C683FC92792281400745862 /* Stats.swift */; }; 1C6B377A2799B78A001EF820 /* BGView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C6B37792799B78A001EF820 /* BGView.swift */; }; + 1C7190A427A483D300388EDC /* SmallHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C7190A327A483D300388EDC /* SmallHeaderView.swift */; }; 1C744F2C278CE15600953A57 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C744F2B278CE15600953A57 /* AppDelegate.swift */; }; 1C747CC9279F06EB00762CBD /* CloudKitSyncMonitor in Frameworks */ = {isa = PBXBuildFile; productRef = 1C747CC8279F06EB00762CBD /* CloudKitSyncMonitor */; }; 1CA037702799FFA600D26164 /* ContentModeViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CA0376F2799FFA600D26164 /* ContentModeViewModel.swift */; }; @@ -128,6 +129,7 @@ 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 = ""; }; + 1C7190A327A483D300388EDC /* SmallHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SmallHeaderView.swift; sourceTree = ""; }; 1C744F2B278CE15600953A57 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 1CA0376F2799FFA600D26164 /* ContentModeViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentModeViewModel.swift; sourceTree = ""; }; 1CA03772279A293D00D26164 /* OnboardingTime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingTime.swift; sourceTree = ""; }; @@ -336,6 +338,7 @@ 1CD90B36278C7E38001C4FEA /* HeaderStatsView.swift */, 1CD90B32278C7E38001C4FEA /* SettingsView.swift */, 1C6B37792799B78A001EF820 /* BGView.swift */, + 1C7190A327A483D300388EDC /* SmallHeaderView.swift */, ); path = views; sourceTree = ""; @@ -593,6 +596,7 @@ 1CD90B3D278C7E38001C4FEA /* ContentView.swift in Sources */, 1CD90B3F278C7E38001C4FEA /* HeaderStatsView.swift in Sources */, 1CD90B3B278C7E38001C4FEA /* AddMoodHeaderView.swift in Sources */, + 1C7190A427A483D300388EDC /* SmallHeaderView.swift in Sources */, 1CC469AC27907D48003E0C6E /* DayChartView.swift in Sources */, 1CD90B37278C7E38001C4FEA /* SettingsView.swift in Sources */, 1C26190327960CE500FDC148 /* ChartDataBuildable.swift in Sources */, diff --git a/Shared/FeelsApp.swift b/Shared/FeelsApp.swift index 288345c..d65ebb3 100644 --- a/Shared/FeelsApp.swift +++ b/Shared/FeelsApp.swift @@ -31,7 +31,6 @@ struct FeelsApp: App { }.onChange(of: scenePhase) { phase in if phase == .background { BGTask.scheduleBackgroundProcessing() - print("background") WidgetCenter.shared.reloadAllTimelines() } diff --git a/Shared/views/AddMoodHeaderView.swift b/Shared/views/AddMoodHeaderView.swift index d5bb84c..fa335f8 100644 --- a/Shared/views/AddMoodHeaderView.swift +++ b/Shared/views/AddMoodHeaderView.swift @@ -12,7 +12,7 @@ import CoreData struct AddMoodHeaderView: View { private let savedOnboardingData = UserDefaultsStore.getOnboarding() - + let addItemHeaderClosure: ((Mood, Date) -> Void) var overrideDay: DayOptions? @@ -34,7 +34,7 @@ struct AddMoodHeaderView: View { }, label: { mood.icon .resizable() - .frame(width: 50, height: 50, alignment: .center) + .frame(width: CGFloat(50), height: CGFloat(50), alignment: .center) .foregroundColor(mood.color) }) @@ -42,13 +42,12 @@ struct AddMoodHeaderView: View { }.frame(minWidth: 0, maxWidth: .infinity) } } - .padding([.leading, .trailing, .bottom]) } + .padding([.leading, .trailing, .bottom]) } .clipShape(RoundedRectangle(cornerRadius: 25, style: .continuous)) - .frame(minHeight: 85, maxHeight: 140) + .frame(minHeight: 88, maxHeight: 150) .frame(minWidth: 0, maxWidth: .infinity) - .padding() } private func getTitle() -> String { diff --git a/Shared/views/ContentView.swift b/Shared/views/ContentView.swift index 4899aae..6952f84 100644 --- a/Shared/views/ContentView.swift +++ b/Shared/views/ContentView.swift @@ -17,9 +17,14 @@ struct ContentView: View { @State private var showTodayInput = true @State private var selectedEntry: MoodEntry? @State private var showUpdateEntryAlert = false - + @State private var headerHeight: CGFloat = 150 + + let minHeaderHeight = 88.0 + let maxHeaderHeight = 150.0 + @State private var headerOpacity: Double = 1.0 + @ObservedObject var viewModel = ContentModeViewModel() - + init(){ UITabBar.appearance().backgroundColor = UIColor.systemBackground } @@ -106,50 +111,86 @@ struct ContentView: View { return formatter.string(from: NSNumber(integerLiteral: day)) ?? "" } + func calcuateViewAlpha() { + let perc = (((Double(headerHeight) - minHeaderHeight) * 100) / (maxHeaderHeight - minHeaderHeight)) / 100 + headerOpacity = perc + } + + func calculateHeight(minHeight: CGFloat, maxHeight: CGFloat, yOffset: CGFloat) { + calcuateViewAlpha() + + let newValue = maxHeight + yOffset + // If scrolling up, yOffset will be a negative number + if newValue < minHeight { + // SCROLLING UP + // Never go smaller than our minimum height + headerHeight = minHeight + return + } + + if newValue > maxHeight { + // SCROLLING UP + // Never go smaller than our minimum height + headerHeight = maxHeight + return + } + + // SCROLLING DOWN + headerHeight = newValue + } + private var listView: some View { - VStack { - List { - // for reach year - ForEach(viewModel.grouped.sorted(by: { - $0.key > $1.key - }), id: \.key) { year, months in - - // for reach month - ForEach(months.sorted(by: { + ScrollView { + ZStack { + Color(.systemBackground).edgesIgnoringSafeArea(.bottom) + .cornerRadius(10) + + LazyVStack { + // for reach year + ForEach(viewModel.grouped.sorted(by: { $0.key > $1.key - }), id: \.key) { month, entries in - Section(header: - HStack{ - Text(monthName(fromMonthInt: month)) - .font(.title2) - .foregroundColor(Color(UIColor.label)) - Text(String(year)) - .font(.title2) - .foregroundColor(Color(UIColor.label)) - }) { - // for reach all entries - ForEach(entries.sorted(by: { - return $0.forDate! > $1.forDate! - }), id: \.self) { entry in - entryListView(entry: entry) - .onTapGesture(perform: { - selectedEntry = entry - showUpdateEntryAlert = true - }) - }.onDelete(perform: { offsets in - withAnimation { - viewModel.delete(offsets: offsets, inMonth: month, inYear: year) - } - }) + }), id: \.key) { year, months in + + // for reach month + ForEach(months.sorted(by: { + $0.key > $1.key + }), id: \.key) { month, entries in + Section(header: + HStack{ + Text(monthName(fromMonthInt: month)) + .font(.title2) + .foregroundColor(Color(UIColor.label)) + Text(String(year)) + .font(.title2) + .foregroundColor(Color(UIColor.label)) + }) { + // for reach all entries + ForEach(entries.sorted(by: { + return $0.forDate! > $1.forDate! + }), id: \.self) { entry in + entryListView(entry: entry) + .onTapGesture(perform: { + selectedEntry = entry + showUpdateEntryAlert = true + }) + }.onDelete(perform: { offsets in + withAnimation { + viewModel.delete(offsets: offsets, inMonth: month, inYear: year) + } + }) + } } } } + GeometryReader { proxy in + let offset = proxy.frame(in: .named("scroll")).minY + Color.clear.preference(key: ViewOffsetKey.self, value: offset) + } } - .background(Color.clear.ignoresSafeArea()) - .onAppear { - // Set the default to clear - UITableView.appearance().backgroundColor = .clear - } + } + .coordinateSpace(name: "scroll") + .onPreferenceChange(ViewOffsetKey.self) { value in + calculateHeight(minHeight: 88, maxHeight: 180, yOffset: value) } } @@ -191,12 +232,13 @@ struct ContentView: View { viewModel.add(mood: mood, forDate: date) } }) - .frame(height: 180) + .frame(height: headerHeight) .frame(minWidth: 0, maxWidth: .infinity) } else { HeaderStatsView(fakeData: false, backDays: 30) - .frame(height: 180) - // should match backDays above + .frame(height: headerHeight) + + // should match backDays above Text(String(format: String(localized: "content_view_header_title"), 30)) .font(.body) .foregroundColor(Color(UIColor.systemGray)) @@ -233,26 +275,50 @@ struct ContentView: View { private var mainView: some View { ZStack { - BGView().equatable() VStack{ settingsButtonView .padding(.top, 50) + if viewModel.hasNoData { Spacer() emptyView Spacer() } else { - headerView - listView + ZStack { + VStack { + headerView + Spacer() + } + .opacity(headerOpacity) + + VStack { + SmallRollUpHeaderView(fakeData: false, backDays: 30) + .padding([.leading, .trailing]) + Spacer() + } + .opacity(1 - headerOpacity) + + listView + .padding([.leading, .trailing]) + .padding(.top, headerHeight+10) + .padding(.bottom, 60) + } } } - .padding(.bottom) } } } +struct ViewOffsetKey: PreferenceKey { + typealias Value = CGFloat + static var defaultValue = CGFloat.zero + static func reduce(value: inout Value, nextValue: () -> Value) { + value += nextValue() + } +} + private let itemFormatter: DateFormatter = { let formatter = DateFormatter() formatter.dateStyle = .short diff --git a/Shared/views/SettingsView.swift b/Shared/views/SettingsView.swift index 73c1ff8..cbf5e20 100644 --- a/Shared/views/SettingsView.swift +++ b/Shared/views/SettingsView.swift @@ -206,7 +206,6 @@ struct SettingsView: View { Toggle(String(localized: "settings_use_cloudkit_title"), isOn: $useCloudKit) .onChange(of: useCloudKit) { value in - print(value) PersistenceController.shared.switchContainer() } .padding() diff --git a/Shared/views/SmallHeaderView.swift b/Shared/views/SmallHeaderView.swift new file mode 100644 index 0000000..9fe8444 --- /dev/null +++ b/Shared/views/SmallHeaderView.swift @@ -0,0 +1,65 @@ +// +// SmallHeaderView.swift +// Feels (iOS) +// +// Created by Trey Tartt on 1/28/22. +// + +import SwiftUI + +struct SmallRollUpHeaderView: View { + var entries = [(Mood, Int)]() + let backDays: Int + + init(fakeData: Bool, backDays: Int) { + self.backDays = backDays + var moodEntries: [MoodEntry]? + + if fakeData { + moodEntries = PersistenceController.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]) + } + if let moodEntries = moodEntries { + for (_, mood) in Mood.allValues.enumerated() { + entries.append((mood, moodEntries.filter({ + Int($0.moodValue) == mood.rawValue + }).count)) + } + } + + entries = entries.sorted(by: { + $0.0.rawValue > $1.0.rawValue + }) + } + + var body: some View { + VStack { + HStack { + ForEach(entries, id: \.0) { (mood, value) in + Text(String(value)) + .font(.title) + .fontWeight(.bold) + .foregroundColor(mood.color) + .frame(maxWidth: .infinity) + } + } + + Text(String(format: String(localized: "content_view_header_title"), self.backDays)) + .font(.body) + .foregroundColor(Color(UIColor.systemGray)) + .frame(maxWidth: .infinity, alignment: .center) + .padding(.top, 2) + } + .padding([.top]) + } +} + +struct SmallHeaderView_Previews: PreviewProvider { + static var previews: some View { + SmallRollUpHeaderView(fakeData: true, backDays: 30) + } +}