init commit - bring project over from Mood
This commit is contained in:
79
Shared/views/AddMoodHeaderView.swift
Normal file
79
Shared/views/AddMoodHeaderView.swift
Normal file
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// AddMoodHeaderView.swift
|
||||
// Feels
|
||||
//
|
||||
// Created by Trey Tartt on 1/5/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
import SwiftUI
|
||||
import CoreData
|
||||
|
||||
struct AddMoodHeaderView: View {
|
||||
@Environment(\.managedObjectContext) private var viewContext
|
||||
|
||||
var body: some View {
|
||||
ZStack {
|
||||
Color(UIColor.secondarySystemBackground)
|
||||
|
||||
VStack {
|
||||
Text("How are you feeling today?")
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.padding()
|
||||
HStack{
|
||||
ForEach(Mood.allValues) { mood in
|
||||
VStack {
|
||||
Button(action: {
|
||||
addItem(withMoodValue: mood.rawValue)
|
||||
}, label: {
|
||||
mood.icon
|
||||
.font(.system(size: 50))
|
||||
})
|
||||
|
||||
//Text(mood.strValue)
|
||||
}.frame(minWidth: 0, maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
.padding([.leading, .trailing, .bottom])
|
||||
}
|
||||
}
|
||||
.clipShape(RoundedRectangle(cornerRadius: 25, style: .continuous))
|
||||
.frame(minHeight: 85, maxHeight: 140)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
.padding()
|
||||
}
|
||||
|
||||
private func addItem(withMoodValue moodValue: Int) {
|
||||
withAnimation {
|
||||
let newItem = MoodEntry(context: viewContext)
|
||||
newItem.timestamp = Date()
|
||||
newItem.moodValue = Int16(moodValue)
|
||||
newItem.date = Date()
|
||||
|
||||
do {
|
||||
try viewContext.save()
|
||||
} catch {
|
||||
// Replace this implementation with code to handle the error appropriately.
|
||||
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
||||
let nsError = error as NSError
|
||||
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct AddMoodHeaderView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
Group {
|
||||
AddMoodHeaderView().environment(\.managedObjectContext, PersistenceController.shared.container.viewContext)
|
||||
|
||||
AddMoodHeaderView().preferredColorScheme(.dark).environment(\.managedObjectContext, PersistenceController.shared.container.viewContext)
|
||||
|
||||
AddMoodHeaderView().environment(\.managedObjectContext, PersistenceController.shared.container.viewContext)
|
||||
|
||||
AddMoodHeaderView().preferredColorScheme(.dark).environment(\.managedObjectContext, PersistenceController.shared.container.viewContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
152
Shared/views/ContentView.swift
Normal file
152
Shared/views/ContentView.swift
Normal file
@@ -0,0 +1,152 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
@State private var showingSheet = false
|
||||
@State private var showTodayInput = true
|
||||
|
||||
@FetchRequest(
|
||||
sortDescriptors: [NSSortDescriptor(keyPath: \MoodEntry.date, ascending: false)],
|
||||
animation: .spring())
|
||||
private var items: FetchedResults<MoodEntry>
|
||||
|
||||
var body: some View {
|
||||
TabView {
|
||||
mainView
|
||||
.tabItem {
|
||||
Label("Main", systemImage: "list.dash")
|
||||
}
|
||||
|
||||
GraphView()
|
||||
.tabItem {
|
||||
Label("Graph", systemImage: "chart.line.uptrend.xyaxis")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var settingsButtonView: some View {
|
||||
HStack {
|
||||
Spacer()
|
||||
Button(action: {
|
||||
showingSheet.toggle()
|
||||
}, label: {
|
||||
Image(systemName: "gear")
|
||||
.foregroundColor(Color(UIColor.systemGray))
|
||||
.font(.system(size: 20))
|
||||
}).sheet(isPresented: $showingSheet) {
|
||||
SettingsView()
|
||||
}.padding(.trailing)
|
||||
}
|
||||
}
|
||||
|
||||
private var listView: some View {
|
||||
List {
|
||||
ForEach(items) { item in
|
||||
HStack {
|
||||
item.mood.icon
|
||||
.font(.system(size: 50))
|
||||
VStack {
|
||||
Text("\(item.moodString)")
|
||||
.font(.title)
|
||||
.foregroundColor(Color(UIColor.systemGray))
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
Text(item.date!, style: .date)
|
||||
.font(.body)
|
||||
.foregroundColor(Color(UIColor.label))
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
.padding(.leading)
|
||||
}
|
||||
}
|
||||
.onDelete(perform: deleteItems)
|
||||
}
|
||||
}
|
||||
|
||||
private var mainView: some View {
|
||||
VStack{
|
||||
settingsButtonView
|
||||
if shouldShowTodayInput() {
|
||||
AddMoodHeaderView()
|
||||
.frame(minHeight: 85, maxHeight: 180)
|
||||
.frame(minWidth: 0, maxWidth: .infinity)
|
||||
} else {
|
||||
HeaderStatsView(entries: [
|
||||
//x - position of a bar, y - height of a bar
|
||||
BarChartDataEntry(x: 1, y: 1),
|
||||
BarChartDataEntry(x: 2, y: 5),
|
||||
BarChartDataEntry(x: 3, y: 2),
|
||||
BarChartDataEntry(x: 4, y: 4),
|
||||
BarChartDataEntry(x: 5, y: 1)
|
||||
])
|
||||
.frame(minHeight: 85, maxHeight: 180)
|
||||
}
|
||||
listView
|
||||
}
|
||||
}
|
||||
|
||||
private func deleteItems(offsets: IndexSet) {
|
||||
withAnimation {
|
||||
offsets.map { items[$0] }.forEach(viewContext.delete)
|
||||
|
||||
do {
|
||||
try viewContext.save()
|
||||
} catch {
|
||||
// Replace this implementation with code to handle the error appropriately.
|
||||
// fatalError() causes the application to generate a crash log and terminate. You should not use this function in a shipping application, although it may be useful during development.
|
||||
let nsError = error as NSError
|
||||
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func shouldShowTodayInput() -> Bool {
|
||||
let fetchRequest = NSFetchRequest<MoodEntry>(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
|
||||
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.date))
|
||||
let toPredicate = NSPredicate(format: "%K < %@", #keyPath(MoodEntry.date), dateTo as NSDate)
|
||||
let datePredicate = NSCompoundPredicate(andPredicateWithSubpredicates: [fromPredicate, toPredicate])
|
||||
fetchRequest.predicate = datePredicate
|
||||
let entries = try! self.viewContext.count(for: fetchRequest)
|
||||
|
||||
return entries == 0
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
16
Shared/views/GraphView.swift
Normal file
16
Shared/views/GraphView.swift
Normal file
@@ -0,0 +1,16 @@
|
||||
//
|
||||
// GraphView.swift
|
||||
// Feels
|
||||
//
|
||||
// Created by Trey Tartt on 1/8/22.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import CoreData
|
||||
|
||||
struct GraphView: View {
|
||||
var body: some View {
|
||||
Text("this is a graph")
|
||||
}
|
||||
}
|
||||
82
Shared/views/HeaderStatsView.swift
Normal file
82
Shared/views/HeaderStatsView.swift
Normal file
@@ -0,0 +1,82 @@
|
||||
//
|
||||
// HeaderStatsView.swift
|
||||
// Feels
|
||||
//
|
||||
// Created by Trey Tartt on 1/8/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Charts
|
||||
|
||||
struct HeaderStatsView : UIViewRepresentable {
|
||||
//Bar chart accepts data as array of BarChartDataEntry objects
|
||||
var entries : [BarChartDataEntry]
|
||||
// this func is required to conform to UIViewRepresentable protocol
|
||||
func makeUIView(context: Context) -> BarChartView {
|
||||
//crate new chart
|
||||
let chart = BarChartView()
|
||||
chart.drawGridBackgroundEnabled = false
|
||||
chart.drawValueAboveBarEnabled = false
|
||||
|
||||
chart.xAxis.drawAxisLineEnabled = false
|
||||
chart.xAxis.labelTextColor = .clear
|
||||
|
||||
chart.rightAxis.drawAxisLineEnabled = false
|
||||
chart.rightAxis.labelTextColor = .clear
|
||||
|
||||
chart.leftAxis.drawAxisLineEnabled = false
|
||||
chart.leftAxis.labelTextColor = .clear
|
||||
|
||||
chart.xAxis.drawGridLinesEnabled = false
|
||||
chart.leftAxis.drawGridLinesEnabled = false
|
||||
chart.leftAxis.axisLineColor = .clear
|
||||
chart.rightAxis.axisLineColor = .clear
|
||||
|
||||
chart.legend.textColor = .clear
|
||||
chart.legend.enabled = false
|
||||
|
||||
chart.drawBordersEnabled = false
|
||||
chart.drawMarkers = false
|
||||
// chart.yAxis.drawGridLinesEnabled = false
|
||||
chart.rightAxis.drawGridLinesEnabled = false
|
||||
chart.borderColor = .clear
|
||||
//it is convenient to form chart data in a separate func
|
||||
chart.data = addData()
|
||||
return chart
|
||||
}
|
||||
|
||||
// this func is required to conform to UIViewRepresentable protocol
|
||||
func updateUIView(_ uiView: BarChartView, context: Context) {
|
||||
//when data changes chartd.data update is required
|
||||
uiView.data = addData()
|
||||
}
|
||||
|
||||
func addData() -> BarChartData{
|
||||
let data = BarChartData()
|
||||
//BarChartDataSet is an object that contains information about your data, styling and more
|
||||
let dataSet = BarChartDataSet(entries: entries)
|
||||
// change bars color to green
|
||||
dataSet.colors = [NSUIColor.green]
|
||||
//change data label
|
||||
data.addDataSet(dataSet)
|
||||
return data
|
||||
}
|
||||
|
||||
typealias UIViewType = BarChartView
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
struct HeaderStatsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
HeaderStatsView(entries: [
|
||||
//x - position of a bar, y - height of a bar
|
||||
BarChartDataEntry(x: 1, y: 1),
|
||||
BarChartDataEntry(x: 2, y: 4),
|
||||
BarChartDataEntry(x: 3, y: 3),
|
||||
BarChartDataEntry(x: 4, y: 2),
|
||||
BarChartDataEntry(x: 5, y: 1)
|
||||
]).frame(minHeight: 85, maxHeight: 90)
|
||||
}
|
||||
}
|
||||
142
Shared/views/SettingsView.swift
Normal file
142
Shared/views/SettingsView.swift
Normal file
@@ -0,0 +1,142 @@
|
||||
//
|
||||
// SettingsView.swift
|
||||
// Feels
|
||||
//
|
||||
// Created by Trey Tartt on 1/8/22.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct SettingsView: View {
|
||||
@Environment(\.dismiss) var dismiss
|
||||
|
||||
@State private var currentDate = Date() {
|
||||
didSet {
|
||||
if self.showReminder {
|
||||
LocalNotification.scheduleReminder(atTime: self.currentDate)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@State private var showReminder: Bool = false {
|
||||
didSet {
|
||||
if self.showReminder {
|
||||
LocalNotification.testIfEnabled(completion: { result in
|
||||
switch result{
|
||||
case .success(_):
|
||||
LocalNotification.scheduleReminder(atTime: self.currentDate)
|
||||
case .failure(_):
|
||||
// show error
|
||||
break
|
||||
}
|
||||
})
|
||||
} else {
|
||||
LocalNotification.removeNotificaiton()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var body: some View { ZStack {
|
||||
Color(UIColor.secondarySystemBackground)
|
||||
|
||||
VStack {
|
||||
closeButtonView
|
||||
.padding()
|
||||
notificationCell
|
||||
randomShitCell
|
||||
addTestDataCell
|
||||
clearDB
|
||||
whyBackgroundMode
|
||||
Spacer()
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
|
||||
private var closeButtonView: some View {
|
||||
HStack{
|
||||
Spacer()
|
||||
Button(action: {
|
||||
dismiss()
|
||||
}, label: {
|
||||
Text("Exit")
|
||||
.font(.body)
|
||||
.foregroundColor(Color(UIColor.systemBlue))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private var notificationCell: some View {
|
||||
ZStack {
|
||||
Color(UIColor.systemBackground)
|
||||
VStack {
|
||||
Toggle("Would you like to be reminded?", isOn: $showReminder)
|
||||
.padding()
|
||||
DatePicker("", selection: $currentDate, displayedComponents: .hourAndMinute)
|
||||
.disabled(showReminder == false)
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 25, style: .continuous))
|
||||
}
|
||||
|
||||
private var randomShitCell: some View {
|
||||
ZStack {
|
||||
Color(UIColor.systemBackground)
|
||||
VStack {
|
||||
Text("random shit")
|
||||
.padding()
|
||||
}
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 25, style: .continuous))
|
||||
}
|
||||
|
||||
private var addTestDataCell: some View {
|
||||
ZStack {
|
||||
Color(UIColor.systemBackground)
|
||||
Button(action: {
|
||||
PersistenceController.shared.populateTestData()
|
||||
}, label: {
|
||||
Text("Add test data")
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 25, style: .continuous))
|
||||
}
|
||||
|
||||
private var clearDB: some View {
|
||||
ZStack {
|
||||
Color(UIColor.systemBackground)
|
||||
Button(action: {
|
||||
PersistenceController.shared.clearDB()
|
||||
}, label: {
|
||||
Text("Clear DB")
|
||||
})
|
||||
.padding()
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 25, style: .continuous))
|
||||
}
|
||||
|
||||
private var whyBackgroundMode: some View {
|
||||
ZStack {
|
||||
Color(UIColor.systemBackground)
|
||||
Text("we do bg mode b/c we can")
|
||||
.padding()
|
||||
}
|
||||
.fixedSize(horizontal: false, vertical: true)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 25, style: .continuous))
|
||||
}
|
||||
}
|
||||
|
||||
struct SettingsView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
SettingsView()
|
||||
|
||||
SettingsView()
|
||||
.preferredColorScheme(.dark)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user