WIP
This commit is contained in:
@@ -8,6 +8,7 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1C485C832A489B9C00A6F896 /* CompletedWorkouts.json in Resources */ = {isa = PBXBuildFile; fileRef = 1C485C822A489B9C00A6F896 /* CompletedWorkouts.json */; };
|
||||
1C485C872A4915C400A6F896 /* CreateWorkoutItemPickerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1C485C862A4915C400A6F896 /* CreateWorkoutItemPickerView.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 */; };
|
||||
1CF65A2B2A3972840042FFBD /* Werkout_ios.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = 1CF65A292A3972840042FFBD /* Werkout_ios.xcdatamodeld */; };
|
||||
@@ -95,6 +96,7 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
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>"; };
|
||||
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>"; };
|
||||
1CF65A272A3972840042FFBD /* Persistence.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Persistence.swift; sourceTree = "<group>"; };
|
||||
@@ -275,6 +277,7 @@
|
||||
1CF65A6A2A3C1EAC0042FFBD /* CreateWorkoutMainView.swift */,
|
||||
1CF65A722A3F60D20042FFBD /* CreateExerciseActionsView.swift */,
|
||||
1CF65A7A2A3F83440042FFBD /* CreateWorkoutSupersetActionsView.swift */,
|
||||
1C485C862A4915C400A6F896 /* CreateWorkoutItemPickerView.swift */,
|
||||
);
|
||||
path = CreateWorkout;
|
||||
sourceTree = "<group>";
|
||||
@@ -487,6 +490,7 @@
|
||||
1CF65A5B2A3BF4BE0042FFBD /* Equipment.swift in Sources */,
|
||||
1CF65A452A39FB550042FFBD /* Exercise.swift in Sources */,
|
||||
1CF65A612A3BF6020042FFBD /* AddExerciseView.swift in Sources */,
|
||||
1C485C872A4915C400A6F896 /* CreateWorkoutItemPickerView.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
|
||||
@@ -10,35 +10,37 @@ import SwiftUI
|
||||
import Combine
|
||||
|
||||
struct AddExerciseView: View {
|
||||
enum CreateWorkoutItemPickerViewType {
|
||||
case muscles
|
||||
case equipment
|
||||
}
|
||||
|
||||
@State var selectedMuscles = [Muscle]()
|
||||
@State var selectedEquipment = [Equipment]()
|
||||
@State var filteredExercises = [ExerciseExercise]()
|
||||
|
||||
@State var searchString: String = ""
|
||||
|
||||
|
||||
@StateObject var bridgeModule = BridgeModule.shared
|
||||
@Environment(\.dismiss) var dismiss
|
||||
var selectedWorkout: ((ExerciseExercise) -> Void)
|
||||
@State var createWorkoutItemPickerViewModel: CreateWorkoutItemPickerViewModel?
|
||||
@State var createWorkoutItemPickerViewType: CreateWorkoutItemPickerViewType?
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
muscleView()
|
||||
|
||||
Divider()
|
||||
|
||||
equipmentView()
|
||||
|
||||
Divider()
|
||||
|
||||
TextField("Filter", text: $searchString)
|
||||
.onReceive(Just(searchString)) { location in
|
||||
filterExercises()
|
||||
}
|
||||
.padding()
|
||||
|
||||
Divider()
|
||||
|
||||
HStack {
|
||||
muscleView()
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
Divider()
|
||||
|
||||
equipmentView()
|
||||
.frame(maxWidth: .infinity)
|
||||
}
|
||||
.padding(.top)
|
||||
.frame(height: 44)
|
||||
|
||||
exerciseView()
|
||||
.padding(.top)
|
||||
}
|
||||
.onAppear{
|
||||
if #function.hasPrefix("__preview") {
|
||||
@@ -53,6 +55,38 @@ struct AddExerciseView: View {
|
||||
selectedEquipment = equipment
|
||||
filteredExercises = exercises
|
||||
}
|
||||
.sheet(item: $createWorkoutItemPickerViewModel) { item in
|
||||
CreateWorkoutItemPickerView(viewModel: item, completed: { selectedids in
|
||||
if let viewType = createWorkoutItemPickerViewType {
|
||||
switch viewType {
|
||||
case .muscles:
|
||||
if let muscles = DataStore.shared.allMuscles {
|
||||
selectedMuscles.removeAll()
|
||||
for id in selectedids {
|
||||
if let muscle = muscles.first(where: {
|
||||
$0.id == id
|
||||
}) {
|
||||
selectedMuscles.append(muscle)
|
||||
}
|
||||
}
|
||||
}
|
||||
case .equipment:
|
||||
if let equipment = DataStore.shared.allEquipment {
|
||||
selectedEquipment.removeAll()
|
||||
for id in selectedids {
|
||||
if let equipment = equipment.first(where: {
|
||||
$0.id == id
|
||||
}) {
|
||||
selectedEquipment.append(equipment)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
filterExercises()
|
||||
})
|
||||
}
|
||||
.background(Color(uiColor: .tertiarySystemBackground))
|
||||
}
|
||||
|
||||
@@ -97,94 +131,57 @@ struct AddExerciseView: View {
|
||||
}
|
||||
}
|
||||
|
||||
if !searchString.isEmpty {
|
||||
return exercise.name.contains(searchString) && hasCorrectMuscles && hasCorrectEquipment
|
||||
} else {
|
||||
return hasCorrectMuscles && hasCorrectEquipment
|
||||
}
|
||||
return hasCorrectMuscles && hasCorrectEquipment
|
||||
})
|
||||
}
|
||||
|
||||
func muscleView() -> some View {
|
||||
VStack {
|
||||
if let _ = DataStore.shared.allMuscles {
|
||||
Text("Select Muscles")
|
||||
.foregroundColor(.cyan)
|
||||
Text("\(selectedMuscles.count) Selected")
|
||||
}
|
||||
}
|
||||
.onTapGesture {
|
||||
if let muscles = DataStore.shared.allMuscles {
|
||||
Button("toggle all", action: {
|
||||
if self.selectedMuscles.count > 0 {
|
||||
self.selectedMuscles.removeAll()
|
||||
} else {
|
||||
self.selectedMuscles.append(contentsOf: muscles)
|
||||
}
|
||||
filterExercises()
|
||||
var createWorkoutItemPickerModels = [CreateWorkoutItemPickerModel]()
|
||||
muscles.forEach({
|
||||
let model = CreateWorkoutItemPickerModel(id: $0.id, name: $0.name)
|
||||
createWorkoutItemPickerModels.append(model)
|
||||
})
|
||||
ScrollView(.horizontal) {
|
||||
HStack(spacing: 10) {
|
||||
ForEach(muscles, id:\.id) { muscle in
|
||||
ZStack {
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.stroke(selectedMuscles.contains(where: { $0.id == muscle.id }) ? .green : .gray, lineWidth: 3)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
Text(muscle.name)
|
||||
.lineLimit(2)
|
||||
.multilineTextAlignment(.center)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
if selectedMuscles.contains(where: { $0.id == muscle.id }) {
|
||||
self.selectedMuscles.removeAll(where: {
|
||||
$0.id == muscle.id
|
||||
})
|
||||
} else {
|
||||
self.selectedMuscles.append(muscle)
|
||||
}
|
||||
filterExercises()
|
||||
}
|
||||
.frame(width: 150, height: 70)
|
||||
}
|
||||
}.padding()
|
||||
}.frame(height: 100)
|
||||
createWorkoutItemPickerModels = createWorkoutItemPickerModels.sorted(by: {
|
||||
$0.name < $1.name
|
||||
})
|
||||
let selectedIds = selectedMuscles.map { $0.id }
|
||||
createWorkoutItemPickerViewModel = CreateWorkoutItemPickerViewModel(allValues: createWorkoutItemPickerModels, selectedIds: selectedIds)
|
||||
createWorkoutItemPickerViewType = .muscles
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func equipmentView() -> some View {
|
||||
VStack {
|
||||
if let _ = DataStore.shared.allEquipment {
|
||||
Text("Select Equipment")
|
||||
.foregroundColor(.cyan)
|
||||
Text("\(selectedEquipment.count) Selected")
|
||||
}
|
||||
}
|
||||
.onTapGesture {
|
||||
if let equipment = DataStore.shared.allEquipment {
|
||||
Button("toggle all", action: {
|
||||
if self.selectedEquipment.count > 0 {
|
||||
self.selectedEquipment.removeAll()
|
||||
} else {
|
||||
self.selectedEquipment.append(contentsOf: equipment)
|
||||
}
|
||||
filterExercises()
|
||||
var createWorkoutItemPickerModels = [CreateWorkoutItemPickerModel]()
|
||||
equipment.forEach({
|
||||
let model = CreateWorkoutItemPickerModel(id: $0.id,
|
||||
name: $0.name ?? "-")
|
||||
createWorkoutItemPickerModels.append(model)
|
||||
})
|
||||
ScrollView(.horizontal) {
|
||||
HStack(spacing: 10) {
|
||||
ForEach(equipment, id:\.id) { aequipment in
|
||||
ZStack {
|
||||
RoundedRectangle(cornerRadius: 8)
|
||||
.stroke(selectedEquipment.contains(where: { $0.id == aequipment.id }) ? .green : .gray, lineWidth: 3)
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
Text(aequipment.name ?? "--")
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.lineLimit(2)
|
||||
.multilineTextAlignment(.center)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture {
|
||||
if selectedEquipment.contains(where: { $0.id == aequipment.id }) {
|
||||
self.selectedEquipment.removeAll(where: {
|
||||
$0.id == aequipment.id
|
||||
})
|
||||
} else {
|
||||
self.selectedEquipment.append(aequipment)
|
||||
}
|
||||
filterExercises()
|
||||
}
|
||||
.frame(width: 150, height: 70)
|
||||
}
|
||||
}.padding()
|
||||
}.frame(height: 100)
|
||||
createWorkoutItemPickerModels = createWorkoutItemPickerModels.sorted(by: {
|
||||
$0.name < $1.name
|
||||
})
|
||||
let selectedIds = selectedEquipment.map { $0.id }
|
||||
createWorkoutItemPickerViewModel = CreateWorkoutItemPickerViewModel(allValues: createWorkoutItemPickerModels, selectedIds: selectedIds)
|
||||
createWorkoutItemPickerViewType = .equipment
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,112 @@
|
||||
//
|
||||
// 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
|
||||
|
||||
})
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user