This commit is contained in:
Trey t
2023-07-02 16:37:45 -05:00
parent 939ea16716
commit fbc1ada8c9
14 changed files with 535 additions and 24 deletions

View File

@@ -0,0 +1,29 @@
//
// PlannedWorkout.swift
// Werkout_ios
//
// Created by Trey Tartt on 7/1/23.
//
import Foundation
struct PlannedWorkout: Codable {
let id: Int
let createdAt, updatedAt, onDate: String
let workout: Workout
enum CodingKeys: String, CodingKey {
case id
case createdAt = "created_at"
case updatedAt = "updated_at"
case onDate = "on_date"
case workout
}
var date: Date? {
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd"
df.locale = Locale(identifier: "en_US_POSIX")
return df.date(from: self.onDate)
}
}

View File

@@ -6,8 +6,9 @@
//
import Foundation
import SwiftUI
class DataStore {
class DataStore: ObservableObject {
enum DataStoreStatus {
case loading
case idle
@@ -20,10 +21,10 @@ class DataStore {
public private(set) var allEquipment: [Equipment]?
public private(set) var allExercise: [ExerciseExercise]?
public private(set) var status = DataStoreStatus.idle
@Published public private(set) var status = DataStoreStatus.idle
private let fetchAllDataQueue = DispatchGroup()
public func fetchAllData() {
status = .loading

View File

@@ -45,6 +45,13 @@ extension String {
df.locale = Locale(identifier: "en_US_POSIX")
return df.date(from: self)
}
var plannedDate: Date? {
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd"
df.locale = Locale(identifier: "en_US_POSIX")
return df.date(from: self)
}
}
extension Date {
@@ -55,4 +62,32 @@ extension Date {
func get(_ component: Calendar.Component, calendar: Calendar = Calendar.current) -> Int {
return calendar.component(component, from: self)
}
var formatForPlannedWorkout: String {
let df = DateFormatter()
df.dateFormat = "yyyy-MM-dd"
df.locale = Locale(identifier: "en_US_POSIX")
return df.string(from: self)
}
var weekDay: String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "EEE"
let weekDay = dateFormatter.string(from: self)
return weekDay
}
var monthString: String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "MMM"
let weekDay = dateFormatter.string(from: self)
return weekDay
}
var dateString: String {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "d"
let weekDay = dateFormatter.string(from: self)
return weekDay
}
}

View File

@@ -0,0 +1,16 @@
[
{
"id": 1,
"created_at": "2023-07-02T04:16:34.262272Z",
"updated_at": "2023-07-02T04:16:34.262315Z",
"on_date": "2023-07-02",
"workout": {
"id": 22,
"created_at": "2023-06-26T02:53:56.101972Z",
"updated_at": "2023-06-26T02:53:56.106136Z",
"name": "Aaaa",
"description": "description",
"registered_user": 1
}
}
]

View File

@@ -41,6 +41,11 @@ class CompletedWorkoutFetchable: Fetchable {
var endPoint: String = "/workout/completed/"
}
class PlannedWorkoutFetchable: Fetchable {
typealias Response = [PlannedWorkout]
var endPoint: String = "/workout/planned_workouts/"
}
class CreateWorkoutFetchable: Postable {
var postableData: [String : Any]?
var successStatus = 201
@@ -80,3 +85,15 @@ class LoginFetchable: Postable {
self.postableData = postData
}
}
class PlanWorkoutFetchable: Postable {
var postableData: [String : Any]?
var successStatus = 201
typealias Response = RegisteredUser
var endPoint: String = "/workout/plan_workout/"
init(postData: [String: Any]) {
self.postableData = postData
}
}

View File

@@ -8,7 +8,7 @@
import Foundation
enum BaseURLs: String {
case local = "http://127.0.0.1:8000/"
case local = "http://127.0.0.1:8000"
case dev = "https://dev.werkout.fitness"
}
@@ -37,7 +37,7 @@ protocol Postable: Fetchable {
extension Fetchable {
var baseURL: String {
BaseURLs.dev.rawValue
BaseURLs.local.rawValue
}
var attachToken: Bool {

View File

@@ -13,6 +13,8 @@ class UserStore: ObservableObject {
@Published public private(set) var registeredUser: RegisteredUser?
var plannedWorkouts = [PlannedWorkout]()
init(registeredUser: RegisteredUser? = nil) {
self.registeredUser = registeredUser
if let data = UserDefaults.standard.data(forKey: UserStore.userDefaultsRegisteredUserKey),
@@ -53,4 +55,26 @@ class UserStore: ObservableObject {
func setFakeUser() {
self.registeredUser = PreviewData.parseRegisterdUser()
}
func fetchPlannedWorkouts() {
PlannedWorkoutFetchable().fetch(completion: { result in
switch result {
case .success(let models):
self.plannedWorkouts = models
case .failure(let failure):
fatalError("shit broke")
}
})
}
func plannedWorkoutFor(date: Date) -> PlannedWorkout? {
for plannedWorkout in plannedWorkouts {
if let plannedworkoutDate = plannedWorkout.date {
if Calendar.current.isDate(date, equalTo: plannedworkoutDate, toGranularity: .day) {
return plannedWorkout
}
}
}
return nil
}
}

View File

@@ -9,10 +9,27 @@ import Foundation
import SwiftUI
struct AllWorkoutsView: View {
enum MainViews: Int, CaseIterable {
case AllWorkout = 0
case MyWorkouts
var title: String {
switch self {
case .AllWorkout:
return "All Workouts"
case .MyWorkouts:
return "Planned Workouts"
}
}
}
@State var workouts: [Workout]?
var bridgeModule = BridgeModule.shared
@State public var needsUpdating: Bool = true
@ObservedObject var dataStore = DataStore.shared
@State private var showWorkoutDetail = false
@State private var selectedWorkout: Workout? {
didSet {
@@ -22,27 +39,32 @@ struct AllWorkoutsView: View {
}
@State private var showLoginView = false
@State private var selectedSegment: MainViews = .AllWorkout
@State var selectedDate: Date = Date()
let pub = NotificationCenter.default.publisher(for: NSNotification.Name("CreatedNewWorkout"))
var body: some View {
ZStack {
if let workouts = workouts,
let _ = DataStore.shared.allExercise,
let _ = DataStore.shared.allMuscles,
let _ = DataStore.shared.allEquipment {
List {
ForEach(workouts, id:\.name) { workout in
VStack {
Text(workout.name)
.font(.title2)
.frame(maxWidth: .infinity, alignment: .leading)
Text(workout.description ?? "")
.frame(maxWidth: .infinity, alignment: .leading)
if let workouts = workouts {
if dataStore.status == .loading {
ProgressView()
.progressViewStyle(.circular)
} else {
VStack {
Picker("", selection: $selectedSegment) {
ForEach(MainViews.allCases, id: \.self) { viewType in
Text(viewType.title)
}
}
.contentShape(Rectangle())
.onTapGesture {
selectedWorkout = workout
.pickerStyle(.segmented)
.padding()
switch selectedSegment {
case .AllWorkout:
allWorkoutView(workouts: workouts)
case .MyWorkouts:
plannedWorkout(workouts: UserStore.shared.plannedWorkouts)
}
}
}
@@ -51,6 +73,7 @@ struct AllWorkoutsView: View {
.progressViewStyle(.circular)
}
}.onAppear{
// UserStore.shared.logout()
maybeUpdateShit()
}
.sheet(item: $selectedWorkout) { item in
@@ -69,10 +92,70 @@ struct AllWorkoutsView: View {
}
}
func allWorkoutView(workouts: [Workout]) -> some View {
List {
ForEach(workouts, id:\.name) { workout in
VStack {
Text(workout.name)
.font(.title2)
.frame(maxWidth: .infinity, alignment: .leading)
Text(workout.description ?? "")
.frame(maxWidth: .infinity, alignment: .leading)
}
.contentShape(Rectangle())
.onTapGesture {
selectedWorkout = workout
}
}
}
}
func plannedWorkout(workouts: [PlannedWorkout]) -> some View {
List {
ForEach(workouts, id:\.workout.name) { plannedWorkout in
HStack {
VStack(alignment: .leading) {
Text(plannedWorkout.onDate.plannedDate?.weekDay ?? "-")
.font(.title)
Text(plannedWorkout.onDate.plannedDate?.monthString ?? "-")
.font(.title)
Text(plannedWorkout.onDate.plannedDate?.dateString ?? "-")
.font(.title)
}
Divider()
VStack {
Text(plannedWorkout.workout.name)
.font(.title)
.frame(maxWidth: .infinity, alignment: .leading)
Text(plannedWorkout.workout.description ?? "")
.font(.body)
.frame(maxWidth: .infinity, alignment: .leading)
Text(plannedWorkout.onDate)
.font(.footnote)
.frame(maxWidth: .infinity, alignment: .leading)
}
.contentShape(Rectangle())
.onTapGesture {
}
}
}
}
}
func maybeUpdateShit() {
if UserStore.shared.token != nil{
if UserStore.shared.plannedWorkouts.isEmpty {
UserStore.shared.fetchPlannedWorkouts()
}
if needsUpdating {
DataStore.shared.fetchAllData()
dataStore.fetchAllData()
AllWorkoutFetchable().fetch(completion: { result in
needsUpdating = false

View File

@@ -0,0 +1,95 @@
//
// PlanWorkoutView.swift
// Werkout_ios
//
// Created by Trey Tartt on 7/2/23.
//
import SwiftUI
struct PlanWorkoutView: View {
@State var selectedDate = Date()
let workout: Workout
@Environment(\.dismiss) var dismiss
var addedPlannedWorkout: (() -> Void)?
var body: some View {
VStack() {
Text(workout.name)
.font(.title)
Text(selectedDate.formatted(date: .abbreviated, time: .omitted))
.font(.system(size: 28))
.bold()
.foregroundColor(Color.accentColor)
.padding()
.animation(.spring(), value: selectedDate)
.frame(width: 500)
Divider().frame(height: 1)
DatePicker("Select Date", selection: $selectedDate, displayedComponents: [.date])
.padding(.horizontal)
.datePickerStyle(.graphical)
Divider()
HStack {
Button(action: {
planWorkout()
}, label: {
Image(systemName: "plus.app")
.font(.title)
.frame(maxWidth: .infinity, maxHeight: .infinity)
})
.frame(maxWidth: .infinity, alignment: .center)
.frame(height: 44)
.foregroundColor(.blue)
.background(.yellow)
.cornerRadius(8)
.padding()
Button(action: {
dismiss()
}, label: {
Image(systemName: "xmark.octagon.fill")
.font(.title)
.frame(maxWidth: .infinity, maxHeight: .infinity)
})
.frame(maxWidth: .infinity, alignment: .center)
.frame(height: 44)
.foregroundColor(.white)
.background(.red)
.cornerRadius(8)
.padding()
}
Spacer()
}
.padding()
}
func planWorkout() {
let postData = [
"on_date": selectedDate.formatForPlannedWorkout,
"workout": workout.id
] as [String : Any]
PlanWorkoutFetchable(postData: postData).fetch(completion: { result in
switch result {
case .success(_):
UserStore.shared.fetchPlannedWorkouts()
dismiss()
addedPlannedWorkout?()
case .failure(_):
fatalError("shit broke")
}
})
}
}
struct PlanWorkoutView_Previews: PreviewProvider {
static var previews: some View {
PlanWorkoutView(workout: PreviewData.workout())
}
}

View File

@@ -18,6 +18,7 @@ struct WorkoutDetailView: View {
}
@State var presentedSheet: Sheet?
@State var workoutToPlan: Workout?
var body: some View {
ZStack {
@@ -35,6 +36,8 @@ struct WorkoutDetailView: View {
ActionsView(completedWorkout: {
bridgeModule.workoutEndDate = Date()
bridgeModule.sendWorkoutCompleteToWatch()
}, planWorkout: { workout in
workoutToPlan = workout
}, workout: workout)
.frame(height: 44)
@@ -49,6 +52,11 @@ struct WorkoutDetailView: View {
})
}
}
.sheet(item: $workoutToPlan) { workout in
PlanWorkoutView(workout: workout, addedPlannedWorkout: {
dismiss()
})
}
.interactiveDismissDisabled()
}
}
@@ -107,6 +115,7 @@ struct InfoView: View {
struct ActionsView: View {
@ObservedObject var bridgeModule = BridgeModule.shared
var completedWorkout: (() -> Void)?
var planWorkout: ((Workout) -> Void)?
var workout: Workout
@Environment(\.dismiss) var dismiss
@@ -126,6 +135,17 @@ struct ActionsView: View {
.background(.red)
.foregroundColor(.white)
Button(action: {
planWorkout?(workout)
}, label: {
Image(systemName: "calendar.badge.plus")
.font(.title)
.frame(maxWidth: .infinity, maxHeight: .infinity)
})
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(.blue)
.foregroundColor(.white)
Button(action: {
startWorkout()
}, label: {
@@ -162,8 +182,6 @@ struct ActionsView: View {
}
}
func nextExercise() {
bridgeModule.nextExercise()
}