add apple tv app
This commit is contained in:
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// CreateViewRepsWeightView.swift
|
||||
// Werkout_ios
|
||||
//
|
||||
// Created by Trey Tartt on 6/18/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CreateExerciseActionsView: View {
|
||||
@ObservedObject var workoutExercise: CreateWorkoutExercise
|
||||
var superset: CreateWorkoutSuperSet
|
||||
var viewModel: WorkoutViewModel
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
HStack {
|
||||
VStack {
|
||||
VStack {
|
||||
Text("Reps: ")
|
||||
Text("\(workoutExercise.reps)")
|
||||
.foregroundColor(workoutExercise.reps == 0 && workoutExercise.duration == 0 ? .red : Color(uiColor: .label))
|
||||
.bold()
|
||||
}
|
||||
Stepper("", onIncrement: {
|
||||
workoutExercise.increaseReps()
|
||||
}, onDecrement: {
|
||||
workoutExercise.decreaseReps()
|
||||
})
|
||||
.labelsHidden()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
Divider()
|
||||
|
||||
VStack{
|
||||
VStack {
|
||||
Text("Weight: ")
|
||||
Text("\(workoutExercise.weight)")
|
||||
}
|
||||
Stepper("", onIncrement: {
|
||||
workoutExercise.increaseWeight()
|
||||
}, onDecrement: {
|
||||
workoutExercise.decreaseWeight()
|
||||
})
|
||||
.labelsHidden()
|
||||
}
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
Divider()
|
||||
|
||||
VStack{
|
||||
VStack {
|
||||
Text("Duration: ")
|
||||
Text("\(workoutExercise.duration)")
|
||||
.foregroundColor(workoutExercise.reps == 0 && workoutExercise.duration == 0 ? .red : Color(uiColor: .label))
|
||||
.bold()
|
||||
}
|
||||
Stepper("", onIncrement: {
|
||||
workoutExercise.increaseDuration()
|
||||
}, onDecrement: {
|
||||
workoutExercise.decreaseDuration()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
HStack {
|
||||
Spacer()
|
||||
Button(action: {
|
||||
}) {
|
||||
Image(systemName: "video.fill")
|
||||
}
|
||||
.frame(width: 88, height: 44)
|
||||
.foregroundColor(.white)
|
||||
.background(.blue)
|
||||
.cornerRadius(10)
|
||||
.buttonStyle(BorderlessButtonStyle())
|
||||
|
||||
Spacer()
|
||||
|
||||
Divider()
|
||||
|
||||
Spacer()
|
||||
|
||||
Button(action: {
|
||||
superset.deleteExerciseForChosenSuperset(exercise: workoutExercise)
|
||||
viewModel.increaseRandomNumberForUpdating()
|
||||
viewModel.objectWillChange.send()
|
||||
}) {
|
||||
Image(systemName: "trash.fill")
|
||||
}
|
||||
.frame(width: 88, height: 44)
|
||||
.foregroundColor(.white)
|
||||
.background(.red)
|
||||
.cornerRadius(10)
|
||||
.buttonStyle(BorderlessButtonStyle())
|
||||
|
||||
Spacer()
|
||||
}
|
||||
|
||||
Divider()
|
||||
.background(.blue)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//struct CreateViewRepsWeightView_Previews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// CreateViewRepsWeightView()
|
||||
// }
|
||||
//}
|
||||
170
iphone/Werkout_ios/Views/CreateWorkout/CreateViewModels.swift
Normal file
170
iphone/Werkout_ios/Views/CreateWorkout/CreateViewModels.swift
Normal file
@@ -0,0 +1,170 @@
|
||||
//
|
||||
// CreateViewModels.swift
|
||||
// Werkout_ios
|
||||
//
|
||||
// Created by Trey Tartt on 6/18/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
class CreateWorkoutExercise: ObservableObject, Identifiable {
|
||||
let id = UUID()
|
||||
var exercise: Exercise
|
||||
@Published var reps: Int = 0
|
||||
@Published var duration: Int = 0
|
||||
@Published var weight: Int = 0
|
||||
|
||||
init(exercise: Exercise, reps: Int = 0, duration: Int = 0, weight: Int = 0) {
|
||||
self.exercise = exercise
|
||||
self.reps = reps
|
||||
self.duration = duration
|
||||
self.weight = weight
|
||||
}
|
||||
|
||||
func increaseReps() {
|
||||
self.reps += 1
|
||||
}
|
||||
|
||||
func decreaseReps() {
|
||||
self.reps -= 1
|
||||
if self.reps < 0 {
|
||||
self.reps = 0
|
||||
}
|
||||
}
|
||||
|
||||
func increaseDuration() {
|
||||
self.duration += 15
|
||||
self.reps = 0
|
||||
}
|
||||
|
||||
func decreaseDuration() {
|
||||
self.duration -= 15
|
||||
if self.duration < 0 {
|
||||
self.duration = 0
|
||||
}
|
||||
}
|
||||
|
||||
func increaseWeight() {
|
||||
self.weight += 5
|
||||
}
|
||||
|
||||
func decreaseWeight() {
|
||||
self.weight -= 15
|
||||
if self.weight < 0 {
|
||||
self.weight = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class CreateWorkoutSuperSet: ObservableObject, Identifiable, Equatable {
|
||||
static func == (lhs: CreateWorkoutSuperSet, rhs: CreateWorkoutSuperSet) -> Bool {
|
||||
lhs.id == rhs.id
|
||||
}
|
||||
|
||||
let id = UUID()
|
||||
@Published var exercises = [CreateWorkoutExercise]()
|
||||
@Published var numberOfRounds = 0
|
||||
|
||||
func increaseNumberOfRounds() {
|
||||
self.numberOfRounds += 1
|
||||
}
|
||||
|
||||
func decreaseNumberOfRounds() {
|
||||
self.numberOfRounds -= 1
|
||||
if self.numberOfRounds < 0 {
|
||||
self.numberOfRounds = 0
|
||||
}
|
||||
}
|
||||
|
||||
func deleteExerciseForChosenSuperset(exercise: CreateWorkoutExercise) {
|
||||
if let idx = exercises.firstIndex(where: {
|
||||
$0.id == exercise.id
|
||||
}) {
|
||||
exercises.remove(at: idx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class WorkoutViewModel: ObservableObject {
|
||||
@Published var superSets = [CreateWorkoutSuperSet]()
|
||||
@Published var title = String()
|
||||
@Published var description = String()
|
||||
@Published var randomValueForUpdatingValue = 0
|
||||
|
||||
func increaseRandomNumberForUpdating() {
|
||||
randomValueForUpdatingValue += 1
|
||||
}
|
||||
|
||||
func addNewSuperset() {
|
||||
increaseRandomNumberForUpdating()
|
||||
superSets.append(CreateWorkoutSuperSet())
|
||||
}
|
||||
|
||||
func delete(superset: CreateWorkoutSuperSet) {
|
||||
if let idx = superSets.firstIndex(where: {
|
||||
$0.id == superset.id
|
||||
}) {
|
||||
superSets.remove(at: idx)
|
||||
increaseRandomNumberForUpdating()
|
||||
}
|
||||
}
|
||||
|
||||
func showRoundsError() {
|
||||
|
||||
}
|
||||
|
||||
func showNoDurationOrReps() {
|
||||
|
||||
}
|
||||
|
||||
func uploadWorkout() {
|
||||
var supersets = [[String: Any]]()
|
||||
var supersetOrder = 1
|
||||
superSets.forEach({ superset in
|
||||
if superset.numberOfRounds == 0 {
|
||||
showRoundsError()
|
||||
return
|
||||
}
|
||||
var supersetInfo = [String: Any]()
|
||||
supersetInfo["name"] = ""
|
||||
supersetInfo["rounds"] = superset.numberOfRounds
|
||||
supersetInfo["order"] = supersetOrder
|
||||
|
||||
var exercises = [[String: Any]]()
|
||||
var exerciseOrder = 1
|
||||
for exercise in superset.exercises {
|
||||
if exercise.reps == 0 && exercise.duration == 0 {
|
||||
showNoDurationOrReps()
|
||||
return
|
||||
}
|
||||
|
||||
let item = ["id": exercise.exercise.id,
|
||||
"reps": exercise.reps,
|
||||
"weight": exercise.weight,
|
||||
"duration": exercise.duration,
|
||||
"order": exerciseOrder] as [String : Any]
|
||||
exercises.append(item)
|
||||
exerciseOrder += 1
|
||||
}
|
||||
supersetInfo["exercises"] = exercises
|
||||
|
||||
supersets.append(supersetInfo)
|
||||
supersetOrder += 1
|
||||
})
|
||||
let uploadBody = ["name": title,
|
||||
"description": description,
|
||||
"supersets": supersets] as [String : Any]
|
||||
CreateWorkoutFetchable(postData: uploadBody).fetch(completion: { result in
|
||||
DispatchQueue.main.async {
|
||||
switch result {
|
||||
case .success(_):
|
||||
self.superSets.removeAll()
|
||||
self.title = ""
|
||||
NotificationCenter.default.post(name: NSNotification.Name("CreatedNewWorkout"), object: nil, userInfo: nil)
|
||||
case .failure(let failure):
|
||||
print(failure)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
//
|
||||
// CreateWorkoutItemPicker.swift
|
||||
// Werkout_ios
|
||||
//
|
||||
// Created by Trey Tartt on 6/25/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Combine
|
||||
|
||||
struct CreateWorkoutItemPickerModel {
|
||||
let id: Int
|
||||
let name: String
|
||||
}
|
||||
|
||||
class CreateWorkoutItemPickerViewModel: Identifiable, ObservableObject {
|
||||
let allValues: [CreateWorkoutItemPickerModel]
|
||||
@Published var selectedIds: [Int]
|
||||
|
||||
init(allValues: [CreateWorkoutItemPickerModel], selectedIds: [Int]) {
|
||||
self.allValues = allValues
|
||||
self.selectedIds = selectedIds
|
||||
}
|
||||
|
||||
func toggleAll() {
|
||||
if selectedIds.isEmpty {
|
||||
selectedIds.append(contentsOf: allValues.map({ $0.id }))
|
||||
} else {
|
||||
selectedIds.removeAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CreateWorkoutItemPickerView: View {
|
||||
@ObservedObject var viewModel: CreateWorkoutItemPickerViewModel
|
||||
var completed: (([Int]) -> Void)
|
||||
@Environment(\.dismiss) var dismiss
|
||||
@State var searchString: String = ""
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
List() {
|
||||
ForEach(viewModel.allValues, id:\.self.id) { value in
|
||||
if searchString.isEmpty || value.name.lowercased().contains(searchString.lowercased()) {
|
||||
HStack {
|
||||
Circle()
|
||||
.stroke(.blue, lineWidth: 1)
|
||||
.background(Circle().fill(viewModel.selectedIds.contains(value.id) ? .blue :.clear))
|
||||
.frame(width: 33, height: 33)
|
||||
|
||||
Text(value.name)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
if viewModel.selectedIds.contains(value.id) {
|
||||
if let idx = viewModel.selectedIds.firstIndex(of: value.id){
|
||||
viewModel.selectedIds.remove(at: idx)
|
||||
}
|
||||
} else {
|
||||
viewModel.selectedIds.append(value.id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TextField("Filter", text: $searchString)
|
||||
.padding()
|
||||
|
||||
|
||||
HStack {
|
||||
Button(action: {
|
||||
viewModel.toggleAll()
|
||||
}, label: {
|
||||
Image(systemName: "checklist")
|
||||
.font(.title)
|
||||
})
|
||||
.frame(maxWidth: 44, alignment: .center)
|
||||
.frame(height: 44)
|
||||
.foregroundColor(.green)
|
||||
.background(.white)
|
||||
.cornerRadius(8)
|
||||
.padding()
|
||||
|
||||
Button(action: {
|
||||
completed(viewModel.selectedIds)
|
||||
dismiss()
|
||||
}, label: {
|
||||
Text("done")
|
||||
})
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.frame(height: 44)
|
||||
.foregroundColor(.blue)
|
||||
.background(.yellow)
|
||||
.cornerRadius(8)
|
||||
.padding()
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CreateWorkoutItemPickerView_Previews: PreviewProvider {
|
||||
static let fakeValues = [CreateWorkoutItemPickerModel(id: 1, name: "one"),
|
||||
CreateWorkoutItemPickerModel(id: 2, name: "two"),
|
||||
CreateWorkoutItemPickerModel(id: 3, name: "three")]
|
||||
|
||||
static var previews: some View {
|
||||
CreateWorkoutItemPickerView(viewModel: CreateWorkoutItemPickerViewModel(allValues: fakeValues, selectedIds: [1]), completed: { selectedIds in
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,164 @@
|
||||
//
|
||||
// CreateWorkoutView.swift
|
||||
// Werkout_ios
|
||||
//
|
||||
// Created by Trey Tartt on 6/15/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CreateWorkoutMainView: View {
|
||||
@ObservedObject var viewModel = WorkoutViewModel()
|
||||
@State private var showAddExercise = false
|
||||
@State var selectedCreateWorkoutSuperSet: CreateWorkoutSuperSet?
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
|
||||
TextField("Title", text: $viewModel.title)
|
||||
.padding()
|
||||
.frame(height: 55)
|
||||
.textFieldStyle(OvalTextFieldStyle())
|
||||
|
||||
TextField("Description", text: $viewModel.description)
|
||||
.padding()
|
||||
.frame(height: 55)
|
||||
.textFieldStyle(OvalTextFieldStyle())
|
||||
ScrollViewReader { proxy in
|
||||
List() {
|
||||
ForEach($viewModel.superSets, id: \.id) { superset in
|
||||
Section {
|
||||
ForEach(superset.exercises, id: \.id) { exercise in
|
||||
HStack {
|
||||
VStack {
|
||||
Text(exercise.wrappedValue.exercise.name)
|
||||
.font(.title2)
|
||||
.frame(maxWidth: .infinity)
|
||||
if exercise.wrappedValue.exercise.side != nil && exercise.wrappedValue.exercise.side!.count > 0 {
|
||||
Text(exercise.wrappedValue.exercise.side!)
|
||||
.font(.title3)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
}
|
||||
CreateExerciseActionsView(workoutExercise: exercise.wrappedValue,
|
||||
superset: superset.wrappedValue,
|
||||
viewModel: viewModel)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HStack {
|
||||
Stepper("Number of rounds", onIncrement: {
|
||||
superset.wrappedValue.increaseNumberOfRounds()
|
||||
viewModel.increaseRandomNumberForUpdating()
|
||||
viewModel.objectWillChange.send()
|
||||
}, onDecrement: {
|
||||
superset.wrappedValue.decreaseNumberOfRounds()
|
||||
viewModel.increaseRandomNumberForUpdating()
|
||||
viewModel.objectWillChange.send()
|
||||
})
|
||||
|
||||
Text("\(superset.wrappedValue.numberOfRounds)")
|
||||
.foregroundColor(superset.numberOfRounds.wrappedValue > 0 ? .black : .red)
|
||||
.bold()
|
||||
}
|
||||
|
||||
CreateWorkoutSupersetActionsView(workoutSuperSet: superset.wrappedValue,
|
||||
showAddExercise: $showAddExercise,
|
||||
viewModel: viewModel,
|
||||
selectedCreateWorkoutSuperSet: $selectedCreateWorkoutSuperSet)
|
||||
}
|
||||
}
|
||||
Text("this is the bottom 🤷♂️")
|
||||
.id(999)
|
||||
|
||||
.listRowSeparator(.hidden)
|
||||
}
|
||||
.onChange(of: viewModel.randomValueForUpdatingValue, perform: { newValue in
|
||||
withAnimation {
|
||||
proxy.scrollTo(999, anchor: .bottom)
|
||||
}
|
||||
})
|
||||
}
|
||||
// .overlay(Group {
|
||||
// if($viewModel.superSets.isEmpty) {
|
||||
// ZStack() {
|
||||
// Color(uiColor: .secondarySystemBackground)
|
||||
// }
|
||||
// }
|
||||
// })
|
||||
|
||||
Divider()
|
||||
|
||||
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) {
|
||||
AddExerciseView(selectedExercise: { exercise in
|
||||
let workoutExercise = CreateWorkoutExercise(exercise: exercise)
|
||||
selectedCreateWorkoutSuperSet?.exercises.append(workoutExercise)
|
||||
|
||||
|
||||
// if left or right auto add the other side
|
||||
// with a recover in between b/c its
|
||||
// eaiser to delete a recover than add one
|
||||
if exercise.side != nil && exercise.side!.count > 0 {
|
||||
let exercises = DataStore.shared.allExercise?.filter({
|
||||
$0.name == exercise.name
|
||||
})
|
||||
let recover = DataStore.shared.allExercise?.first(where: {
|
||||
$0.name.lowercased() == "recover"
|
||||
})
|
||||
if let exercises = exercises, let recover = recover {
|
||||
if exercises.count == 2 {
|
||||
let recoverWorkoutExercise = CreateWorkoutExercise(exercise: recover)
|
||||
selectedCreateWorkoutSuperSet?.exercises.append(recoverWorkoutExercise)
|
||||
for LRExercise in exercises {
|
||||
if LRExercise.id != exercise.id {
|
||||
let otherSideExercise = CreateWorkoutExercise(exercise: LRExercise)
|
||||
selectedCreateWorkoutSuperSet?.exercises.append(otherSideExercise)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
viewModel.increaseRandomNumberForUpdating()
|
||||
viewModel.objectWillChange.send()
|
||||
selectedCreateWorkoutSuperSet = nil
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//struct CreateWorkoutView_Previews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// CreateWorkoutView()
|
||||
// }
|
||||
//}
|
||||
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// CreateWorkoutSupersetActionsView.swift
|
||||
// Werkout_ios
|
||||
//
|
||||
// Created by Trey Tartt on 6/18/23.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
|
||||
struct CreateWorkoutSupersetActionsView: View {
|
||||
var workoutSuperSet: CreateWorkoutSuperSet
|
||||
@Binding var showAddExercise: Bool
|
||||
var viewModel: WorkoutViewModel
|
||||
@Binding var selectedCreateWorkoutSuperSet: CreateWorkoutSuperSet?
|
||||
|
||||
var body: some View {
|
||||
HStack {
|
||||
Button(action: {
|
||||
selectedCreateWorkoutSuperSet = workoutSuperSet
|
||||
showAddExercise.toggle()
|
||||
}) {
|
||||
Text("Add exercise")
|
||||
.padding()
|
||||
}
|
||||
.foregroundColor(.white)
|
||||
.background(.green)
|
||||
.cornerRadius(10)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.buttonStyle(BorderlessButtonStyle())
|
||||
|
||||
Button(action: {
|
||||
viewModel.delete(superset: workoutSuperSet)
|
||||
viewModel.increaseRandomNumberForUpdating()
|
||||
viewModel.objectWillChange.send()
|
||||
|
||||
}) {
|
||||
Text("Delete superset")
|
||||
.padding()
|
||||
}
|
||||
.foregroundColor(.white)
|
||||
.background(.red)
|
||||
.cornerRadius(10)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.buttonStyle(BorderlessButtonStyle())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//struct CreateWorkoutSupersetActionsView_Previews: PreviewProvider {
|
||||
// static var previews: some View {
|
||||
// CreateWorkoutSupersetActionsView()
|
||||
// }
|
||||
//}
|
||||
Reference in New Issue
Block a user