This commit is contained in:
Trey t
2023-06-25 22:00:59 -05:00
parent d055ed182d
commit f40c40c9bb
9 changed files with 220 additions and 87 deletions

View File

@@ -9,6 +9,7 @@
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
1C485C832A489B9C00A6F896 /* CompletedWorkouts.json in Resources */ = {isa = PBXBuildFile; fileRef = 1C485C822A489B9C00A6F896 /* CompletedWorkouts.json */; }; 1C485C832A489B9C00A6F896 /* CompletedWorkouts.json in Resources */ = {isa = PBXBuildFile; fileRef = 1C485C822A489B9C00A6F896 /* CompletedWorkouts.json */; };
1C485C872A4915C400A6F896 /* CreateWorkoutItemPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C485C862A4915C400A6F896 /* CreateWorkoutItemPickerView.swift */; }; 1C485C872A4915C400A6F896 /* CreateWorkoutItemPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C485C862A4915C400A6F896 /* CreateWorkoutItemPickerView.swift */; };
1C485C8A2A492BB400A6F896 /* LoginView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C485C892A492BB400A6F896 /* LoginView.swift */; };
1CF65A262A3972840042FFBD /* Werkout_iosApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A252A3972840042FFBD /* Werkout_iosApp.swift */; }; 1CF65A262A3972840042FFBD /* Werkout_iosApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A252A3972840042FFBD /* Werkout_iosApp.swift */; };
1CF65A282A3972840042FFBD /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A272A3972840042FFBD /* Persistence.swift */; }; 1CF65A282A3972840042FFBD /* Persistence.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A272A3972840042FFBD /* Persistence.swift */; };
1CF65A2B2A3972840042FFBD /* Werkout_ios.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A292A3972840042FFBD /* Werkout_ios.xcdatamodeld */; }; 1CF65A2B2A3972840042FFBD /* Werkout_ios.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A292A3972840042FFBD /* Werkout_ios.xcdatamodeld */; };
@@ -97,6 +98,7 @@
/* Begin PBXFileReference section */ /* Begin PBXFileReference section */
1C485C822A489B9C00A6F896 /* CompletedWorkouts.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = CompletedWorkouts.json; sourceTree = "<group>"; }; 1C485C822A489B9C00A6F896 /* CompletedWorkouts.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = CompletedWorkouts.json; sourceTree = "<group>"; };
1C485C862A4915C400A6F896 /* CreateWorkoutItemPickerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateWorkoutItemPickerView.swift; sourceTree = "<group>"; }; 1C485C862A4915C400A6F896 /* CreateWorkoutItemPickerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CreateWorkoutItemPickerView.swift; sourceTree = "<group>"; };
1C485C892A492BB400A6F896 /* LoginView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoginView.swift; sourceTree = "<group>"; };
1CF65A222A3972840042FFBD /* Werkout_ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Werkout_ios.app; sourceTree = BUILT_PRODUCTS_DIR; }; 1CF65A222A3972840042FFBD /* Werkout_ios.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Werkout_ios.app; sourceTree = BUILT_PRODUCTS_DIR; };
1CF65A252A3972840042FFBD /* Werkout_iosApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Werkout_iosApp.swift; sourceTree = "<group>"; }; 1CF65A252A3972840042FFBD /* Werkout_iosApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Werkout_iosApp.swift; sourceTree = "<group>"; };
1CF65A272A3972840042FFBD /* Persistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = "<group>"; }; 1CF65A272A3972840042FFBD /* Persistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = "<group>"; };
@@ -167,6 +169,14 @@
/* End PBXFrameworksBuildPhase section */ /* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */ /* Begin PBXGroup section */
1C485C882A492BAA00A6F896 /* Login */ = {
isa = PBXGroup;
children = (
1C485C892A492BB400A6F896 /* LoginView.swift */,
);
path = Login;
sourceTree = "<group>";
};
1CF65A192A3972840042FFBD = { 1CF65A192A3972840042FFBD = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@@ -244,6 +254,7 @@
1CF65A3F2A3973840042FFBD /* Views */ = { 1CF65A3F2A3973840042FFBD /* Views */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
1C485C882A492BAA00A6F896 /* Login */,
1CF65A2C2A3972840042FFBD /* MainView.swift */, 1CF65A2C2A3972840042FFBD /* MainView.swift */,
1CF65A3B2A3972CE0042FFBD /* ExternalWorkoutDetailView.swift */, 1CF65A3B2A3972CE0042FFBD /* ExternalWorkoutDetailView.swift */,
1CF65A8B2A44B7590042FFBD /* AccountView */, 1CF65A8B2A44B7590042FFBD /* AccountView */,
@@ -483,6 +494,7 @@
1CF65A2B2A3972840042FFBD /* Werkout_ios.xcdatamodeld in Sources */, 1CF65A2B2A3972840042FFBD /* Werkout_ios.xcdatamodeld in Sources */,
1CF65A2D2A3972840042FFBD /* MainView.swift in Sources */, 1CF65A2D2A3972840042FFBD /* MainView.swift in Sources */,
1CF65A7D2A41275D0042FFBD /* Network.swift in Sources */, 1CF65A7D2A41275D0042FFBD /* Network.swift in Sources */,
1C485C8A2A492BB400A6F896 /* LoginView.swift in Sources */,
1CF65A732A3F60D20042FFBD /* CreateExerciseActionsView.swift in Sources */, 1CF65A732A3F60D20042FFBD /* CreateExerciseActionsView.swift in Sources */,
1CF65A832A42347D0042FFBD /* Extensions.swift in Sources */, 1CF65A832A42347D0042FFBD /* Extensions.swift in Sources */,
1CF65A282A3972840042FFBD /* Persistence.swift in Sources */, 1CF65A282A3972840042FFBD /* Persistence.swift in Sources */,

View File

@@ -8,10 +8,19 @@
import Foundation import Foundation
class UserStore: ObservableObject { class UserStore: ObservableObject {
static let userDefaultsRegisteredUserKey = "registeredUserKey"
static let shared = UserStore() static let shared = UserStore()
@Published public private(set) var registeredUser: RegisteredUser? @Published public private(set) var registeredUser: RegisteredUser?
init(registeredUser: RegisteredUser? = nil) {
self.registeredUser = registeredUser
if let data = UserDefaults.standard.data(forKey: UserStore.userDefaultsRegisteredUserKey),
let model = try? JSONDecoder().decode(RegisteredUser.self, from: data) {
self.registeredUser = model
}
}
public var token: String? { public var token: String? {
guard let token = registeredUser?.token else { guard let token = registeredUser?.token else {
return nil return nil
@@ -19,19 +28,28 @@ class UserStore: ObservableObject {
return "Token \(token)" return "Token \(token)"
} }
func login(completion: @escaping (Bool)-> Void) { func login(postData: [String: Any], completion: @escaping (Bool)-> Void) {
let postData = ["email": "user1@user1.com", "password":"test12345"]
LoginFetchable(postData: postData).fetch(completion: { result in LoginFetchable(postData: postData).fetch(completion: { result in
switch result { switch result {
case .success(let model): case .success(let model):
self.registeredUser = model DispatchQueue.main.async {
completion(true) self.registeredUser = model
let data = try! JSONEncoder().encode(model)
UserDefaults.standard.set(data, forKey: UserStore.userDefaultsRegisteredUserKey)
completion(true)
}
case .failure(let failure): case .failure(let failure):
completion(false) completion(false)
} }
}) })
} }
func logout() {
self.registeredUser = nil
UserDefaults.standard.set(nil, forKey: UserStore.userDefaultsRegisteredUserKey)
NotificationCenter.default.post(name: NSNotification.Name("CreatedNewWorkout"), object: nil, userInfo: nil)
}
func setFakeUser() { func setFakeUser() {
self.registeredUser = PreviewWorkout.parseRegisterdUser() self.registeredUser = PreviewWorkout.parseRegisterdUser()
} }

View File

@@ -49,6 +49,17 @@ struct AccountView: View {
} }
} }
Spacer() Spacer()
Button("Logout", action: {
userStore.logout()
})
.frame(maxWidth: .infinity, alignment: .center)
.frame(height: 44)
.foregroundColor(.white)
.background(.red)
.cornerRadius(8)
.padding()
.frame(maxWidth: .infinity)
} }
.padding() .padding()
.onAppear{ .onAppear{

View File

@@ -24,9 +24,16 @@ struct AddExerciseView: View {
var selectedWorkout: ((ExerciseExercise) -> Void) var selectedWorkout: ((ExerciseExercise) -> Void)
@State var createWorkoutItemPickerViewModel: CreateWorkoutItemPickerViewModel? @State var createWorkoutItemPickerViewModel: CreateWorkoutItemPickerViewModel?
@State var createWorkoutItemPickerViewType: CreateWorkoutItemPickerViewType? @State var createWorkoutItemPickerViewType: CreateWorkoutItemPickerViewType?
@State var searchString: String = ""
var body: some View { var body: some View {
VStack { VStack {
exerciseView()
.padding(.top)
TextField("Filter", text: $searchString)
.padding()
HStack { HStack {
muscleView() muscleView()
.frame(maxWidth: .infinity) .frame(maxWidth: .infinity)
@@ -38,9 +45,6 @@ struct AddExerciseView: View {
} }
.padding(.top) .padding(.top)
.frame(height: 44) .frame(height: 44)
exerciseView()
.padding(.top)
} }
.onAppear{ .onAppear{
if #function.hasPrefix("__preview") { if #function.hasPrefix("__preview") {
@@ -190,25 +194,27 @@ struct AddExerciseView: View {
List() { List() {
ForEach(filteredExercises.indices, id: \.self) { i in ForEach(filteredExercises.indices, id: \.self) { i in
let obj = filteredExercises[i] let obj = filteredExercises[i]
VStack { if searchString.isEmpty || obj.name.lowercased().contains(searchString.lowercased()) {
Text(obj.name) VStack {
.frame(maxWidth: .infinity, alignment: .leading) Text(obj.name)
if obj.side.count > 0 { .frame(maxWidth: .infinity, alignment: .leading)
Text(obj.side) if obj.side.count > 0 {
Text(obj.side)
.font(.footnote)
.frame(maxWidth: .infinity, alignment: .leading)
}
Text(obj.equipmentRequired)
.font(.footnote)
.frame(maxWidth: .infinity, alignment: .leading)
Text(obj.muscleGroups)
.font(.footnote) .font(.footnote)
.frame(maxWidth: .infinity, alignment: .leading) .frame(maxWidth: .infinity, alignment: .leading)
} }
Text(obj.equipmentRequired) .contentShape(Rectangle())
.font(.footnote) .onTapGesture {
.frame(maxWidth: .infinity, alignment: .leading) selectedWorkout(obj)
Text(obj.muscleGroups) dismiss()
.font(.footnote) }
.frame(maxWidth: .infinity, alignment: .leading)
}
.contentShape(Rectangle())
.onTapGesture {
selectedWorkout(obj)
dismiss()
} }
} }
} }

View File

@@ -21,6 +21,8 @@ struct AllWorkoutsView: View {
} }
} }
@State private var showLoginView = false
let pub = NotificationCenter.default.publisher(for: NSNotification.Name("CreatedNewWorkout")) let pub = NotificationCenter.default.publisher(for: NSNotification.Name("CreatedNewWorkout"))
var body: some View { var body: some View {
@@ -45,34 +47,45 @@ struct AllWorkoutsView: View {
Text("no workouts") Text("no workouts")
} }
}.onAppear{ }.onAppear{
if needsUpdating { maybeUpdateShit()
UserStore.shared.login(completion: { success in
if success {
DataStore.shared.fetchAllData()
AllWorkoutFetchable().fetch(completion: { result in
needsUpdating = false
switch result {
case .success(let model):
DispatchQueue.main.async {
self.workouts = model
}
case .failure(let failure):
fatalError("shit broke")
}
})
} else {
fatalError("shit broke")
}
})
}
} }
.sheet(item: $selectedWorkout) { item in .sheet(item: $selectedWorkout) { item in
let viewModel = WorkoutDetailViewModel(workout: item) let viewModel = WorkoutDetailViewModel(workout: item)
WorkoutDetailView(viewModel: viewModel) WorkoutDetailView(viewModel: viewModel)
} }
.sheet(isPresented: $showLoginView) {
LoginView(completion: {
self.needsUpdating = true
maybeUpdateShit()
})
}
.onReceive(pub) { (output) in .onReceive(pub) { (output) in
self.needsUpdating = true self.needsUpdating = true
maybeUpdateShit()
}
}
func maybeUpdateShit() {
if UserStore.shared.token != nil{
if needsUpdating {
DataStore.shared.fetchAllData()
AllWorkoutFetchable().fetch(completion: { result in
needsUpdating = false
switch result {
case .success(let model):
DispatchQueue.main.async {
self.workouts = model
}
case .failure(_):
fatalError("shit broke")
}
})
} else {
fatalError("shit broke")
}
} else {
showLoginView = true
} }
} }
} }

View File

@@ -43,7 +43,6 @@ struct CompletedWorkoutView: View {
.overlay(RoundedRectangle(cornerRadius: 16).stroke(Color(uiColor: .clear))).background(Color(uiColor: .init(red: 200/255, green: 200/255, blue: 200/255, alpha: 0.2))) .overlay(RoundedRectangle(cornerRadius: 16).stroke(Color(uiColor: .clear))).background(Color(uiColor: .init(red: 200/255, green: 200/255, blue: 200/255, alpha: 0.2)))
.cornerRadius(8) .cornerRadius(8)
Spacer() Spacer()
Button("Upload", action: { Button("Upload", action: {

View File

@@ -17,33 +17,6 @@ struct CreateWorkoutMainView: View {
TextField("Title", text: $viewModel.title) TextField("Title", text: $viewModel.title)
.padding() .padding()
HStack {
Button("Add Superset", action: {
viewModel.addNewSuperset()
})
.frame(maxWidth: .infinity, alignment: .center)
.frame(height: 44)
.foregroundColor(.blue)
.background(.yellow)
.cornerRadius(8)
.padding()
.frame(maxWidth: .infinity)
Divider()
Button("Done", action: {
viewModel.uploadWorkout()
})
.frame(maxWidth: .infinity, alignment: .center)
.frame(height: 44)
.foregroundColor(.white)
.background(.blue)
.cornerRadius(8)
.padding()
.frame(maxWidth: .infinity)
}
.frame(height: 44)
List() { List() {
ForEach($viewModel.superSets, id: \.id) { superset in ForEach($viewModel.superSets, id: \.id) { superset in
Section { Section {
@@ -86,6 +59,35 @@ struct CreateWorkoutMainView: View {
} }
.listRowSeparator(.hidden) .listRowSeparator(.hidden)
} }
HStack {
Button("Add Superset", action: {
viewModel.addNewSuperset()
})
.frame(maxWidth: .infinity, alignment: .center)
.frame(height: 44)
.foregroundColor(.blue)
.background(.yellow)
.cornerRadius(8)
.padding()
.frame(maxWidth: .infinity)
Divider()
Button("Done", action: {
viewModel.uploadWorkout()
})
.frame(maxWidth: .infinity, alignment: .center)
.frame(height: 44)
.foregroundColor(.white)
.background(.blue)
.cornerRadius(8)
.padding()
.frame(maxWidth: .infinity)
.disabled(viewModel.title.isEmpty)
}
.frame(height: 44)
.padding(.bottom)
} }
.sheet(isPresented: $showAddExercise) { .sheet(isPresented: $showAddExercise) {
AddExerciseView(selectedWorkout: { exercise in AddExerciseView(selectedWorkout: { exercise in

View File

@@ -22,26 +22,25 @@ struct CreateWorkoutSupersetActionsView: View {
Text("Add exercise") Text("Add exercise")
.padding() .padding()
} }
.frame(maxWidth: .infinity)
.foregroundColor(.white) .foregroundColor(.white)
.background(.green) .background(.green)
.cornerRadius(10) .cornerRadius(10)
.frame(maxWidth: .infinity, alignment: .center) .frame(maxWidth: .infinity, alignment: .center)
.buttonStyle(BorderlessButtonStyle())
// Button(action: { Button(action: {
// if let selectedCreateWorkoutSuperSet = selectedCreateWorkoutSuperSet { viewModel.delete(superset: workoutSuperSet)
// viewModel.delete(superset: selectedCreateWorkoutSuperSet) viewModel.objectWillChange.send()
// viewModel.objectWillChange.send()
// } }) {
// }) { Text("Delete superset")
// Text("Delete superset") .padding()
// .padding() }
// } .foregroundColor(.white)
// .frame(maxWidth: .infinity) .background(.red)
// .foregroundColor(.white) .cornerRadius(10)
// .background(.red) .frame(maxWidth: .infinity, alignment: .center)
// .cornerRadius(10) .buttonStyle(BorderlessButtonStyle())
// .frame(maxWidth: .infinity, alignment: .center)
} }
} }
} }

View File

@@ -0,0 +1,73 @@
//
// LoginView.swift
// Werkout_ios
//
// Created by Trey Tartt on 6/25/23.
//
import SwiftUI
struct LoginView: View {
@State var email: String = ""
@State var password: String = ""
@Environment(\.dismiss) var dismiss
let completion: (() -> Void)
var body: some View {
VStack {
Text("Login")
.font(.title)
TextField("Email", text: $email)
.autocapitalization(.none)
.frame(height: 55)
.textFieldStyle(PlainTextFieldStyle())
.padding([.horizontal], 4)
.overlay(RoundedRectangle(cornerRadius: 16).stroke(Color(uiColor: .clear))).background(Color(uiColor: .init(red: 200/255, green: 200/255, blue: 200/255, alpha: 0.2)))
.cornerRadius(8)
TextField("Password", text: $password)
.autocapitalization(.none)
.frame(height: 55)
.textFieldStyle(PlainTextFieldStyle())
.padding([.horizontal], 4)
.overlay(RoundedRectangle(cornerRadius: 16).stroke(Color(uiColor: .clear))).background(Color(uiColor: .init(red: 200/255, green: 200/255, blue: 200/255, alpha: 0.2)))
.cornerRadius(8)
Button("Login", action: {
login()
})
.frame(maxWidth: .infinity, alignment: .center)
.frame(height: 44)
.foregroundColor(.blue)
.background(.yellow)
.cornerRadius(8)
.padding()
.frame(maxWidth: .infinity)
Spacer()
}
.padding()
}
func login() {
let postData = [
"email": email,
"password": password
]
UserStore.shared.login(postData: postData, completion: { success in
if success {
completion()
dismiss()
}
})
}
}
struct LoginView_Previews: PreviewProvider {
static var previews: some View {
LoginView(completion: {
})
}
}