diff --git a/Werkout_ios/BridgeModule.swift b/Werkout_ios/BridgeModule.swift index 3ad6633..ddaaf57 100644 --- a/Werkout_ios/BridgeModule.swift +++ b/Werkout_ios/BridgeModule.swift @@ -114,7 +114,7 @@ class BridgeModule: NSObject, ObservableObject { currentWorkoutRunTimer?.fire() } - private func startTimerWith(duration: Int) { + private func startExerciseTimerWith(duration: Int) { DispatchQueue.main.async { self.currentExerciseTimer?.invalidate() self.currentExerciseTimer = nil @@ -148,6 +148,15 @@ class BridgeModule: NSObject, ObservableObject { } } + func pauseWorkout() { + if let _ = currentExerciseTimer { + currentExerciseTimer?.invalidate() + currentExerciseTimer = nil + } else { + startExerciseTimerWith(duration: currentExerciseTimeLeft) + } + } + func nextExercise() { currentExerciseIdx += 1 if let currentWorkout = currentWorkout { @@ -166,10 +175,15 @@ class BridgeModule: NSObject, ObservableObject { func updateCurrent(exercise: ExerciseElement) { DispatchQueue.main.async { + self.currentExerciseTimer?.invalidate() + self.currentExerciseTimer = nil + self.currentExercise = exercise - if let duration = exercise.duration { - self.startTimerWith(duration: duration) + if let duration = exercise.duration, + duration > 0 { + print(duration) + self.startExerciseTimerWith(duration: duration) } } } diff --git a/Werkout_ios/Extensions.swift b/Werkout_ios/Extensions.swift index 856a391..55e80bb 100644 --- a/Werkout_ios/Extensions.swift +++ b/Werkout_ios/Extensions.swift @@ -6,6 +6,7 @@ // import Foundation +import UIKit extension Dictionary { func percentEncoded() -> Data? { @@ -91,3 +92,15 @@ extension Date { return weekDay } } + +extension Bundle { + public var icon: UIImage? { + if let icons = infoDictionary?["CFBundleIcons"] as? [String: Any], + let primaryIcon = icons["CFBundlePrimaryIcon"] as? [String: Any], + let iconFiles = primaryIcon["CFBundleIconFiles"] as? [String], + let lastIcon = iconFiles.last { + return UIImage(named: lastIcon) + } + return nil + } +} diff --git a/Werkout_ios/Views/AllWorkouts/AllWorkoutsView.swift b/Werkout_ios/Views/AllWorkouts/AllWorkoutsView.swift index 9dfb7ae..fb13fb1 100644 --- a/Werkout_ios/Views/AllWorkouts/AllWorkoutsView.swift +++ b/Werkout_ios/Views/AllWorkouts/AllWorkoutsView.swift @@ -23,7 +23,7 @@ struct AllWorkoutsView: View { } } } - + @State var isUpdating = false @State var workouts: [Workout]? var bridgeModule = BridgeModule.shared @State public var needsUpdating: Bool = true @@ -52,28 +52,32 @@ struct AllWorkoutsView: View { var body: some View { ZStack { 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) - } + VStack { + Picker("", selection: $selectedSegment) { + ForEach(MainViews.allCases, id: \.self) { viewType in + Text(viewType.title) } - .pickerStyle(.segmented) - .padding() + } + .pickerStyle(.segmented) + .padding() + + switch selectedSegment { + case .AllWorkout: - switch selectedSegment { - case .AllWorkout: - AllWorkoutsListView(workouts: workouts, selectedWorkout: { workout in - selectedWorkout = workout - }) - Divider() - case .MyWorkouts: - plannedWorkout(workouts: UserStore.shared.plannedWorkouts) + if isUpdating { + ProgressView() + .progressViewStyle(.circular) } + + AllWorkoutsListView(workouts: workouts, selectedWorkout: { workout in + selectedWorkout = workout + }, refresh: { + self.needsUpdating = true + maybeUpdateShit() + }) + Divider() + case .MyWorkouts: + plannedWorkout(workouts: UserStore.shared.plannedWorkouts) } } } else { @@ -150,6 +154,7 @@ struct AllWorkoutsView: View { } if needsUpdating { + self.isUpdating = true dataStore.fetchAllData() AllWorkoutFetchable().fetch(completion: { result in @@ -158,9 +163,12 @@ struct AllWorkoutsView: View { case .success(let model): DispatchQueue.main.async { self.workouts = model + self.isUpdating = false } case .failure(_): - fatalError("shit broke") + DispatchQueue.main.async { + self.isUpdating = false + } } }) } @@ -197,6 +205,7 @@ struct AllWorkoutsListView: View { return workouts } } + var refresh: (() -> Void) var body: some View { VStack { @@ -233,6 +242,9 @@ struct AllWorkoutsListView: View { } } } + .refreshable { + refresh() + } TextField("Filter", text: $searchString) .padding(.leading) } diff --git a/Werkout_ios/Views/ExternalWorkoutDetailView.swift b/Werkout_ios/Views/ExternalWorkoutDetailView.swift index b49e5ab..74415f9 100644 --- a/Werkout_ios/Views/ExternalWorkoutDetailView.swift +++ b/Werkout_ios/Views/ExternalWorkoutDetailView.swift @@ -28,7 +28,7 @@ struct ExternalWorkoutDetailView: View { VStack { if let currentExercisePositionString = bridgeModule.currentExercisePositionString { Text(currentExercisePositionString) - .font(Font.system(size: 55)) + .font(Font.system(size: 75)) .scaledToFit() .minimumScaleFactor(0.01) .lineLimit(1) @@ -47,7 +47,21 @@ struct ExternalWorkoutDetailView: View { } } } else { - Text("nothing here bro") + GeometryReader { metrics in + VStack { + Spacer() + HStack { + Spacer() + + Image(uiImage: Bundle.main.icon ?? UIImage()) + .resizable() + .scaledToFit() + .frame(width: metrics.size.width/2, height: metrics.size.height/2) + Spacer() + } + Spacer() + } + } } } .onChange(of: bridgeModule.currentExercise, perform: { newValue in @@ -69,7 +83,7 @@ struct ExternalWorkoutDetailView: View { } }) .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(.background) + .background(bridgeModule.currentWorkout == nil ? Color(red: 157/255, green: 138/255, blue: 255/255) : Color(uiColor: .systemBackground)) } } @@ -160,7 +174,8 @@ struct ExtCountdownView: View { .frame(height: metrics.size.height * 0.5) HStack { - if let duration = currenExercise.duration { + if let duration = currenExercise.duration, + duration > 0 { ProgressView(value: Float(bridgeModule.currentExerciseTimeLeft), total: Float(duration)) .scaleEffect(x: 1, y: 6, anchor: .center) Text("\(bridgeModule.currentExerciseTimeLeft)") @@ -170,9 +185,10 @@ struct ExtCountdownView: View { .lineLimit(1) .padding(.leading) .padding(.trailing, 100) - } else if let reps = currenExercise.reps { + } else if let reps = currenExercise.reps, + reps > 0 { Text("\(reps)") - .font(Font.system(size: 75)) + .font(Font.system(size: 150)) .scaledToFit() .minimumScaleFactor(0.01) .lineLimit(1) diff --git a/Werkout_ios/Views/WorkoutDetail/WorkoutDetailView.swift b/Werkout_ios/Views/WorkoutDetail/WorkoutDetailView.swift index f16e18d..971d5c9 100644 --- a/Werkout_ios/Views/WorkoutDetail/WorkoutDetailView.swift +++ b/Werkout_ios/Views/WorkoutDetail/WorkoutDetailView.swift @@ -20,7 +20,7 @@ struct WorkoutDetailView: View { case completedWorkout([String: Any]) var id: String { return UUID().uuidString } } - + @State var presentedSheet: Sheet? @State var workoutToPlan: Workout? var showAddToCalendar = true @@ -49,14 +49,14 @@ struct WorkoutDetailView: View { } InfoView(workout: workout) Divider() - .padding([.leading, .trailing]) + .padding([.leading, .trailing]) ExerciseListView(workout: workout) ActionsView(completedWorkout: { bridgeModule.completeWorkout() }, planWorkout: { workout in workoutToPlan = workout }, workout: workout, showAddToCalendar: showAddToCalendar) - .frame(height: 44) + .frame(height: 44) } .sheet(item: $presentedSheet) { item in @@ -186,7 +186,7 @@ struct ActionsView: View { } Button(action: { - startWorkout() + startWorkout() }, label: { Image(systemName: "arrowtriangle.forward.fill") .font(.title) @@ -204,6 +204,17 @@ struct ActionsView: View { .frame(maxWidth: .infinity, maxHeight: .infinity) }) .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(.green) + .foregroundColor(.white) + + Button(action: { + bridgeModule.pauseWorkout() + }, label: { + Image(systemName: "pause.circle.fill") + .font(.title) + .frame(maxWidth: .infinity, maxHeight: .infinity) + }) + .frame(maxWidth: .infinity, maxHeight: .infinity) .background(.yellow) .foregroundColor(.white) @@ -263,47 +274,70 @@ struct ExerciseListView: View { } var body: some View { - List() { + ScrollViewReader { proxy in + List() { ForEach(workout.exercisesSortedByCreated_at.indices, id: \.self) { i in let obj = workout.exercisesSortedByCreated_at[i] - VStack { - HStack { - if i == bridgeModule.currentExerciseIdx { - Image(systemName: "checkmark") - .foregroundColor(.green) - } - - Text(obj.exercise.name) - Spacer() - } - .contentShape(Rectangle()) - .onTapGesture { - if bridgeModule.isInWorkout { - bridgeModule.goToExerciseAt(index: i) - } else { - videoExercise = obj.exercise - } + HStack { + if i == bridgeModule.currentExerciseIdx { + Image(systemName: "checkmark") + .foregroundColor(.green) } - if i == bridgeModule.currentExerciseIdx { - HStack { - if obj.exercise.isReps { - Text("is reps") - .frame(maxWidth: .infinity, maxHeight: .infinity) - } - if obj.exercise.isWeight { - Text("is weight") - .frame(maxWidth: .infinity, maxHeight: .infinity) - } - if obj.exercise.isDuration { - Text("is duration") - .frame(maxWidth: .infinity, maxHeight: .infinity) - } + Text(obj.exercise.name) + .id(i) + + if let reps = obj.reps, + reps > 0 { + Text("Reps: \(reps)") + .frame(maxWidth: .infinity, alignment: .trailing) + } + if let weight = obj.weight, + weight > 0 { + Text(" - Weight: \(weight)") + .frame(maxWidth: .infinity, alignment: .trailing) + } + if let duration = obj.duration, + duration > 0 { + Text("Duration: \(duration)") + .frame(maxWidth: .infinity, alignment: .trailing) + } + + Spacer() + } + .contentShape(Rectangle()) + .onTapGesture { + if bridgeModule.isInWorkout { + bridgeModule.goToExerciseAt(index: i) + } else { + videoExercise = obj.exercise + } + } + + if i == bridgeModule.currentExerciseIdx { + HStack { + if obj.exercise.isReps { + Text("is reps") + .frame(maxWidth: .infinity, maxHeight: .infinity) + } + if obj.exercise.isWeight { + Text("is weight") + .frame(maxWidth: .infinity, maxHeight: .infinity) + } + if obj.exercise.isDuration { + Text("is duration") + .frame(maxWidth: .infinity, maxHeight: .infinity) } } } } } + .onChange(of: bridgeModule.currentExerciseIdx, perform: { newValue in + withAnimation { + proxy.scrollTo(newValue, anchor: .top) + } + }) + } .sheet(item: $videoExercise) { exercise in PlayerView(player: $avPlayer) .onAppear{ @@ -317,7 +351,8 @@ struct CountdownView: View { @StateObject var bridgeModule = BridgeModule.shared var body: some View { - if let duration = bridgeModule.currentExercise?.duration { + if let duration = bridgeModule.currentExercise?.duration, + duration > 0 { HStack { ProgressView(value: Float(bridgeModule.currentExerciseTimeLeft), total: Float(duration)) Text("\(bridgeModule.currentExerciseTimeLeft)") diff --git a/Werkout_ios/Werkout_iosApp.swift b/Werkout_ios/Werkout_iosApp.swift index d6f392d..88c640e 100644 --- a/Werkout_ios/Werkout_iosApp.swift +++ b/Werkout_ios/Werkout_iosApp.swift @@ -63,6 +63,7 @@ struct Werkout_iosApp: App { .tag(3) } .onAppear{ + UIApplication.shared.isIdleTimerDisabled = true _ = try? AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: .default, options: .mixWithOthers) // UserStore.shared.logout() }