// // FilterView.swift // Feels // // Created by Trey Tartt on 1/12/22. // import SwiftUI import CoreData 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 @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 @AppStorage(UserDefaultsStore.Keys.textColor.rawValue, store: GroupUserDefaults.groupDefaults) private var textColor: Color = DefaultTextColor.textColor @EnvironmentObject var iapManager: IAPManager @StateObject public var viewModel: YearViewModel @StateObject private var filteredDays = DaysFilterClass.shared @State private var trialWarningHidden = false @State private var showSubscriptionStore = false //[ // 2001: [0: [], 1: [], 2: []], // 2002: [0: [], 1: [], 2: []] // ] let columns = [ GridItem(.flexible(minimum: 5, maximum: 50)), GridItem(.flexible(minimum: 5, maximum: 50)), GridItem(.flexible(minimum: 5, maximum: 50)), GridItem(.flexible(minimum: 5, maximum: 50)), GridItem(.flexible(minimum: 5, maximum: 50)), GridItem(.flexible(minimum: 5, maximum: 50)), GridItem(.flexible(minimum: 5, maximum: 50)), GridItem(.flexible(minimum: 5, maximum: 50)), GridItem(.flexible(minimum: 5, maximum: 50)), GridItem(.flexible(minimum: 5, maximum: 50)), GridItem(.flexible(minimum: 5, maximum: 50)), GridItem(.flexible(minimum: 5, maximum: 50)), ] var body: some View { ZStack { if self.viewModel.data.keys.isEmpty { EmptyHomeView(showVote: false, viewModel: nil) .padding() } else { ScrollView { gridView .background( GeometryReader { proxy in let offset = proxy.frame(in: .named("scroll")).minY Color.clear.preference(key: ViewOffsetKey.self, value: offset) } ) } .disabled(iapManager.shouldShowPaywall) .padding(.bottom, 5) } if iapManager.shouldShowPaywall { // Paywall overlay - tap to show subscription store Color.black.opacity(0.3) .ignoresSafeArea() .onTapGesture { showSubscriptionStore = true } VStack { Spacer() Button { showSubscriptionStore = true } label: { Text(String(localized: "subscription_required_button")) .font(.headline) .foregroundColor(.white) .frame(maxWidth: .infinity) .padding() .background(RoundedRectangle(cornerRadius: 10).fill(Color.pink)) } .padding() } } else if iapManager.shouldShowTrialWarning { VStack { Spacer() if !trialWarningHidden { IAPWarningView(iapManager: iapManager) } } } } .sheet(isPresented: $showSubscriptionStore) { FeelsSubscriptionStoreView() } .onAppear(perform: { self.viewModel.filterEntries(startDate: Date(timeIntervalSince1970: 0), endDate: Date()) }) .background( theme.currentTheme.bg .edgesIgnoringSafeArea(.all) ) .onPreferenceChange(ViewOffsetKey.self) { value in withAnimation { trialWarningHidden = value < 0 } } .padding([.top]) } private var monthsHeader: some View { LazyVGrid(columns: columns, spacing: 0) { ForEach(months, id: \.self.0) { item in Text(item.1) .textCase(.uppercase) .foregroundColor(textColor) } }.padding([.leading, .trailing, .top]) } private var gridView: some View { VStack { VStack { ForEach(Array(self.viewModel.data.keys.sorted(by: >)), id: \.self) { yearKey in let yearData = self.viewModel.data[yearKey]! let firstOfYear = Calendar.current.date(from: DateComponents(year: Int(yearKey), month: 1, day: 1))! let lastOfYear = Calendar.current.date(from: DateComponents(year: Int(yearKey)+1, month: 1, day: 1))! let yearEntries = PersistenceController.shared.getData(startDate: firstOfYear, endDate: lastOfYear, includedDays: filteredDays.currentFilters) Text(String(yearKey)) .font(.title) .foregroundColor(textColor) ZStack { theme.currentTheme.secondaryBGColor HStack { Spacer() ForEach(Mood.allValues, id: \.self) { mood in VStack { Text(String(Stats.getCountFor(moodType: mood, inData: yearEntries))) .font(.title) .foregroundColor(textColor) Text(mood.strValue) .foregroundColor(moodTint.color(forMood: mood)) } Spacer() } } } .cornerRadius(10) .frame(minWidth: 0, maxWidth: .infinity, minHeight: 90, maxHeight: 90) .cornerRadius(10) .padding() Text(String(localized: "filter_view_total") + ": \(yearEntries.count)") .font(.title2) .foregroundColor(textColor) monthsHeader .cornerRadius(10) yearGridView(yearData: yearData, columns: columns) .background( theme.currentTheme.secondaryBGColor ) .cornerRadius(10) } .padding([.top, .leading, .trailing]) } } } private struct yearGridView: View { let yearData: [Int: [DayChartView]] let columns: [GridItem] var body: some View { VStack { LazyVGrid(columns: columns, spacing: 0) { ForEach(Array(yearData.keys.sorted(by: <)), id: \.self) { monthKey in let monthData = yearData[monthKey]! VStack { monthGridView(monthData: monthData) } } } .padding([.leading, .trailing, .top, .bottom]) } .cornerRadius(10) } } private struct monthGridView: View { @StateObject private var filteredDays = DaysFilterClass.shared let monthData: [DayChartView] var body: some View { VStack { ForEach(monthData, id: \.self) { view in if filteredDays.currentFilters.contains(view.weekDay) { view } else { view.filteredDaysView } } } } } } struct YearView_Previews: PreviewProvider { static var previews: some View { Group { YearView(viewModel: YearViewModel()) YearView(viewModel: YearViewModel()) .preferredColorScheme(.dark) } } }