made bgview equatable so it doesn't get redrawn each time a sheet is shown add more string to localization fill in missing data on launch ... incase they have bgfetch turned off
240 lines
8.8 KiB
Swift
240 lines
8.8 KiB
Swift
//
|
|
// ContentView.swift
|
|
// Shared
|
|
//
|
|
// Created by Trey Tartt on 1/5/22.
|
|
//
|
|
|
|
import SwiftUI
|
|
import CoreData
|
|
import Charts
|
|
|
|
struct ContentView: View {
|
|
@Environment(\.managedObjectContext) private var viewContext
|
|
@AppStorage(UserDefaultsStore.Keys.needsOnboarding.rawValue) private var needsOnboarding = true
|
|
|
|
@State private var showingSheet = false
|
|
@State private var showTodayInput = true
|
|
@State private var selectedMissingEntry: MoodEntry?
|
|
@State private var showMissingAlert = false
|
|
|
|
@ObservedObject var viewModel = ContentModeViewModel()
|
|
|
|
init(){
|
|
UITabBar.appearance().backgroundColor = UIColor.systemBackground
|
|
}
|
|
|
|
var body: some View {
|
|
TabView {
|
|
mainView
|
|
.tabItem {
|
|
Label(String(localized: "content_view_tab_main"), systemImage: "list.dash")
|
|
}
|
|
|
|
FilterView()
|
|
.tabItem {
|
|
Label(String(localized: "content_view_tab_filter"), systemImage: "calendar.circle")
|
|
}
|
|
|
|
GraphView()
|
|
.tabItem {
|
|
Label(String(localized: "content_view_tab_stats"), systemImage: "chart.line.uptrend.xyaxis")
|
|
}
|
|
}.sheet(isPresented: $needsOnboarding, onDismiss: {
|
|
|
|
}, content: {
|
|
OnboardingMain(onboardingData: viewModel.savedOnboardingData,
|
|
updateBoardingDataClosure: { onboardingData in
|
|
needsOnboarding = false
|
|
viewModel.updateOnboardingData(onboardingData: onboardingData)
|
|
})
|
|
}).alert(String(localized: "content_view_fill_in_missing_entry"), isPresented: $showMissingAlert) {
|
|
ForEach(Mood.allValues) { mood in
|
|
Button(mood.strValue, action: {
|
|
if let selectedMissingEntry = selectedMissingEntry {
|
|
viewModel.update(entry: selectedMissingEntry, toMood: mood)
|
|
}
|
|
showMissingAlert = false
|
|
})
|
|
}
|
|
Button(String(localized: "content_view_fill_in_missing_entry_cancel"), role: .cancel, action: {
|
|
selectedMissingEntry = nil
|
|
showMissingAlert = false
|
|
})
|
|
}
|
|
}
|
|
|
|
private var settingsButtonView: some View {
|
|
HStack {
|
|
Spacer()
|
|
Button(action: {
|
|
showingSheet.toggle()
|
|
}, label: {
|
|
Image(systemName: "gear")
|
|
.foregroundColor(Color(UIColor.darkGray))
|
|
.font(.system(size: 20))
|
|
}).sheet(isPresented: $showingSheet) {
|
|
SettingsView(editedDataClosure: {
|
|
withAnimation{
|
|
viewModel.updateData()
|
|
}
|
|
}, updateBoardingDataClosure: { onboardingData in
|
|
viewModel.updateOnboardingData(onboardingData: onboardingData)
|
|
})
|
|
}.padding(.trailing)
|
|
}
|
|
}
|
|
|
|
private func weekdayName(fromDate date: Date) -> String {
|
|
let weekday = Calendar.current.component(.weekday, from: date)
|
|
let calendar = Calendar.current
|
|
let dayIndex = ((weekday - 1) + (calendar.firstWeekday - 1)) % 7
|
|
return calendar.weekdaySymbols[dayIndex]
|
|
}
|
|
|
|
private func monthName(fromMonthInt: Int) -> String {
|
|
let monthName = DateFormatter().monthSymbols[fromMonthInt-1]
|
|
return monthName
|
|
}
|
|
|
|
private func dayFormat(fromDate date: Date) -> String {
|
|
let components = Calendar.current.dateComponents([.day], from: date)
|
|
let day = components.day!
|
|
|
|
let formatter = NumberFormatter()
|
|
formatter.numberStyle = .ordinal
|
|
return formatter.string(from: NSNumber(integerLiteral: day)) ?? ""
|
|
}
|
|
|
|
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: {
|
|
$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: {
|
|
if entry.moodValue == Mood.missing.rawValue {
|
|
selectedMissingEntry = entry
|
|
showMissingAlert = true
|
|
}
|
|
})
|
|
}.onDelete(perform: { offsets in
|
|
withAnimation {
|
|
viewModel.delete(offsets: offsets, inMonth: month, inYear: year)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.background(Color.clear.ignoresSafeArea())
|
|
.onAppear {
|
|
// Set the default to clear
|
|
UITableView.appearance().backgroundColor = .clear
|
|
}
|
|
}
|
|
}
|
|
|
|
private func entryListView(entry: MoodEntry) -> some View {
|
|
HStack {
|
|
entry.mood.icon
|
|
.resizable()
|
|
.aspectRatio(contentMode: .fit)
|
|
.frame(width: 40, height: 40, alignment: .center)
|
|
.foregroundColor(entry.mood.color)
|
|
|
|
VStack {
|
|
HStack {
|
|
Text(weekdayName(fromDate:entry.forDate!))
|
|
.font(.title3)
|
|
.foregroundColor(Color(UIColor.label))
|
|
Text(" - ")
|
|
.padding([.leading, .trailing], -10)
|
|
Text(dayFormat(fromDate:entry.forDate!))
|
|
.font(.title3)
|
|
.foregroundColor(Color(UIColor.label))
|
|
|
|
Spacer()
|
|
}
|
|
.multilineTextAlignment(.leading)
|
|
|
|
Text("\(entry.moodString)")
|
|
.font(.body)
|
|
.foregroundColor(Color(UIColor.systemGray))
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
}
|
|
}
|
|
}
|
|
|
|
private var mainView: some View {
|
|
ZStack {
|
|
|
|
BGView().equatable()
|
|
|
|
VStack{
|
|
settingsButtonView
|
|
if viewModel.shouldShowVotingHeader() {
|
|
AddMoodHeaderView(addItemHeaderClosure: { (mood, date) in
|
|
withAnimation {
|
|
viewModel.add(mood: mood, forDate: date)
|
|
}
|
|
})
|
|
.frame(height: 180)
|
|
.frame(minWidth: 0, maxWidth: .infinity)
|
|
} else {
|
|
HeaderStatsView(fakeData: false, backDays: 30)
|
|
.frame(height: 180)
|
|
// should match backDays above
|
|
Text(String(format: String(localized: "content_view_header_title"), 30))
|
|
.font(.body)
|
|
.foregroundColor(Color(UIColor.systemGray))
|
|
.frame(maxWidth: .infinity, alignment: .center)
|
|
}
|
|
listView
|
|
.padding(.bottom)
|
|
}
|
|
.padding(.top, 50)
|
|
}
|
|
}
|
|
}
|
|
|
|
private let itemFormatter: DateFormatter = {
|
|
let formatter = DateFormatter()
|
|
formatter.dateStyle = .short
|
|
formatter.timeStyle = .medium
|
|
return formatter
|
|
}()
|
|
|
|
struct ContentView_Previews: PreviewProvider {
|
|
static var previews: some View {
|
|
ContentView().environment(\.managedObjectContext, PersistenceController.shared.container.viewContext)
|
|
.onAppear(perform: {
|
|
PersistenceController.shared.populateMemory()
|
|
})
|
|
|
|
ContentView()
|
|
.preferredColorScheme(.dark)
|
|
.environment(\.managedObjectContext, PersistenceController.shared.container.viewContext)
|
|
}
|
|
}
|