change folders to the "feature" mindset

This commit is contained in:
Felix Förtsch
2024-10-21 15:03:47 +02:00
parent 97ecbcc6f4
commit d1a87957f6
34 changed files with 121 additions and 139 deletions

View File

@@ -49,19 +49,19 @@ struct SetListItem: View {
}
}
#Preview {
@Previewable @State var set = WorkoutItem(set: [
WorkoutItem(Exercise("Squat")),
WorkoutItem(Exercise("Squat")),
WorkoutItem(Exercise("Squat"))])
List {
SetListItem(workout: Workout(name: "RR"), set: $set)
}
}
#Preview("Empty Database") {
@Previewable @State var set = WorkoutItem(set: [])
List {
SetListItem(workout: Workout(name: "RR"), set: $set)
}
}
//#Preview {
// @Previewable @State var set = WorkoutItem(set: [
// WorkoutItem(Exercise("Squat")),
// WorkoutItem(Exercise("Squat")),
// WorkoutItem(Exercise("Squat"))])
// List {
// SetListItem(workout: Workout(name: "RR"), set: $set)
// }
//}
//
//#Preview("Empty Database") {
// @Previewable @State var set = WorkoutItem(set: [])
// List {
// SetListItem(workout: Workout(name: "RR"), set: $set)
// }
//}

View File

@@ -49,8 +49,7 @@ struct ContentView: View {
Section {
NavigationLink(
destination: ActiveWorkoutSession(
activeWorkoutSession: $activeWorkoutSession,
activeWorkout: activeWorkoutSession.workout)
activeWorkoutSession: $activeWorkoutSession)
) {
HStack {
Label("Back to Session", systemImage: "memories")

View File

@@ -75,7 +75,7 @@ struct WorkoutLog: View {
ForEach(workoutSessions) { session in
VStack(alignment: .leading) {
Text(session.startDate.ISO8601Format())
Text(session.workout.name)
Text(session.name)
.font(.subheadline)
}
}.onDelete(perform: deleteWorkoutSession)

View File

@@ -37,14 +37,14 @@ final class WorkoutItem: Nameable, Positionable {
var id = UUID()
var name: String
var workout: Workout?
// TODO: Make WorkoutItem a protocol so the type can be distinguished by the class type
var workoutItemType: WorkoutItemType // Differentiates between exercise/rest/set
var position: Int = 0
var set: [WorkoutItem] = []
// Exercise has to be optional to allow Rest and Set to be a WorkoutItem (without being an Exercise).
var exerciseData: Exercise? // Do Push-up | Run Marathon
var plannedReps: Int // 8 times | 1 time
var plannedValue: Double // With 10 | 42,187
var exercise: Exercise // Do Push-up | Run Marathon
var plannedReps: Int // 8 times | 1 time
var plannedValue: Double // With 10 | 42,187
var metric: ExerciseMetric? // kg (weight) | km (distance)
enum WorkoutItemType: Codable {
@@ -54,7 +54,7 @@ final class WorkoutItem: Nameable, Positionable {
}
init(_ exercise: Exercise) {
self.exerciseData = exercise
self.exercise = exercise
self.workoutItemType = .exercise
// Push-up
@@ -67,27 +67,25 @@ final class WorkoutItem: Nameable, Positionable {
self.metric = exercise.metric
}
init(set: [WorkoutItem] = []) {
self.workoutItemType = .set
self.name = "Set"
self.plannedReps = 3
self.plannedValue = 0
set.forEach(addChild)
}
// init(set: [WorkoutItem] = []) {
// self.workoutItemType = .set
// self.name = "Set"
// self.plannedReps = 3
// self.plannedValue = 0
// set.forEach(addChild)
// }
// init(rest: Double) {
// self.workoutItemType = .rest
// self.name = "Rest"
// self.plannedReps = 1
// self.plannedValue = rest
// self.metric = .time
// }
func addChild(_ child: WorkoutItem) {
if self.workoutItemType == .set {
self.set.append(child)
}
}
init(rest: Double) {
self.workoutItemType = .rest
self.name = "Rest"
self.plannedReps = 1
self.plannedValue = rest
self.metric = .time
}
}
extension WorkoutItem {

View File

@@ -19,17 +19,17 @@ struct WorkoutItemLibrarySheet: View {
var body: some View {
Group {
List {
Section(header: Text("Utilities")) {
AddItemButton(label: "Set") {
addWorkoutItemtoWorkout(WorkoutItem(set: [
WorkoutItem(Exercise("Set item 1")),
WorkoutItem(Exercise("Set item 2"))
]))
}
AddItemButton(label: "Rest") {
addWorkoutItemtoWorkout(WorkoutItem(rest: 45))
}
}
// Section(header: Text("Utilities")) {
// AddItemButton(label: "Set") {
// addWorkoutItemtoWorkout(WorkoutItem(set: [
// WorkoutItem(Exercise("Set item 1")),
// WorkoutItem(Exercise("Set item 2"))
// ]))
// }
// AddItemButton(label: "Rest") {
// addWorkoutItemtoWorkout(WorkoutItem(rest: 45))
// }
// }
Section(header: Text("Excersises")) {
if !exercises.isEmpty {
ForEach(exercises) { exercise in

View File

@@ -34,18 +34,20 @@ struct WorkoutLibrary: View {
NavigationLink {
WorkoutDetail(activeWorkoutSession: $activeWorkoutSession, workout: workout)
} label: {
Button(action: {
activeWorkoutSession = workout.start()
}) {
Image(systemName: "play.fill")
.foregroundStyle(.green)
}
// TODO: Decide if icon should appear here/create custom view
// Image(systemName: workout.workoutIconSystemName)
// .foregroundStyle(workout.workoutIconColorName.color)
Image(systemName: workout.workoutIconSystemName)
.foregroundStyle(workout.workoutIconColorName.color)
Text(workout.name)
}
.swipeActions(edge: .leading) {
Button {
activeWorkoutSession = workout.start()
} label: {
Label("Start", systemImage: "play")
.tint(.green)
}
}
}
.onDelete(perform: deleteWorkout)
if filteredItems.isEmpty {
ContentUnavailableView.search(text: searchText)

View File

@@ -37,12 +37,12 @@ struct WorkoutListItem: View {
#Preview {
List {
WorkoutListItem(Workout(name: "RR"), WorkoutItem(set: [
WorkoutItem(Exercise("Squat")),
WorkoutItem(Exercise("Squat")),
WorkoutItem(Exercise("Squat"))]))
// WorkoutListItem(Workout(name: "RR"), WorkoutItem(set: [
// WorkoutItem(Exercise("Squat")),
// WorkoutItem(Exercise("Squat")),
// WorkoutItem(Exercise("Squat"))]))
WorkoutListItem(Workout(name: "RR"), WorkoutItem(Exercise("Push-ups")))
WorkoutListItem(Workout(name: "RR"), WorkoutItem(rest: 15))
// WorkoutListItem(Workout(name: "RR"), WorkoutItem(rest: 15))
WorkoutListItem(Workout(name: "RR"), WorkoutItem(Exercise("Push-ups")))
WorkoutListItem(Workout(name: "RR"), WorkoutItem(Exercise("Sprint", .distance)))
WorkoutListItem(Workout(name: "RR"), WorkoutItem(Exercise("Run", .time)))

View File

@@ -1,6 +1,7 @@
import SwiftUI
import SwiftData
// This view can only be viewed, if there exists a WorkoutSession that can be considered active (a person working out).
struct ActiveWorkoutSession: View {
@Environment(\.modelContext) private var modelContext
@@ -10,17 +11,14 @@ struct ActiveWorkoutSession: View {
@Query(sort: \WorkoutSession.name) var workoutSessions: [WorkoutSession]
@Binding var activeWorkoutSession: WorkoutSession?
@Query(sort: \Workout.name) var workouts: [Workout]
@State var activeWorkout: Workout
var body: some View {
VStack {
List {
Section(header: Text("Workout")) {
Text(activeWorkout.name)
Text(activeWorkoutSession!.name)
}
Section(header: Text("Exercises")) {
ForEach(getActiveWorkoutItems(activeWorkout: activeWorkout)) { workoutItem in
ForEach(activeWorkoutSession!.workoutSessionItems) { workoutItem in
ActiveWorkoutSessionListItem(workoutItem: workoutItem)
}
}
@@ -28,7 +26,6 @@ struct ActiveWorkoutSession: View {
}
.navigationTitle("Session")
.toolbar {
if (isWorkingOut) {
Button(action: {
isWorkingOut = false
activeWorkoutSession?.stop()
@@ -41,21 +38,6 @@ struct ActiveWorkoutSession: View {
.bold()
.fontDesign(.rounded)
.tint(.red)
}
else {
Button(action: {
isWorkingOut = true
activeWorkoutSession = activeWorkout.start()
}) {
HStack {
Image(systemName: "play.fill")
Text("Start")
}
}
.bold()
.fontDesign(.rounded)
.tint(.green)
}
}
}
@@ -76,7 +58,7 @@ struct ActiveWorkoutSession: View {
@Previewable @State var workout = Workout.sampleData.first!
NavigationStack {
ActiveWorkoutSession(activeWorkoutSession: $activeWorkoutSession, activeWorkout: workout)
ActiveWorkoutSession(activeWorkoutSession: $activeWorkoutSession)
}
.onAppear {
Defaults.shared.isWorkingOut = false

View File

@@ -8,14 +8,10 @@
import SwiftUI
struct ActiveWorkoutSessionListItem: View {
var workoutItem: WorkoutItem
var workoutItem: WorkoutSessionItem
var body: some View {
HStack {
switch workoutItem.workoutItemType {
case .set:
Text(workoutItem.name)
case .exercise:
Text(workoutItem.name)
Spacer()
Button(action: {
@@ -24,17 +20,15 @@ struct ActiveWorkoutSessionListItem: View {
Image(systemName: "info.circle")
.foregroundColor(.blue)
}
case .rest:
Text("Pause")
}
}
}
}
#Preview {
@Previewable @State var workoutSession = WorkoutSession(start: Workout.sampleData.first!)
List {
ForEach(WorkoutItem.sampleDataRecommendedRoutine) { item in
ActiveWorkoutSessionListItem(workoutItem: item)
ActiveWorkoutSessionListItem(workoutItem: WorkoutSessionItem(workoutSession: workoutSession, planned: item))
}
}
}

View File

@@ -11,16 +11,16 @@ import SwiftData
@Model
final class WorkoutSession: Nameable {
var id = UUID()
var name = ""
// The Workout is what *should* happen
var workout: Workout {
didSet {
self.name = workout?.name ?? "Unknown Workout"
}
}
var name: String
// TODO: Think about if a refrence to the workout makes sense; a Workout could change.
// var workout: Workout
var workoutSessionItems: [WorkoutSessionItem] = []
init(start with: Workout) {
self.workout = with
init(start workout: Workout) {
self.name = workout.name
for workoutItem in workout.getWorkoutItems() {
workoutSessionItems.append(WorkoutSessionItem(workoutSession: self, planned: workoutItem))
}
}
// State
@@ -69,9 +69,7 @@ final class WorkoutSession: Nameable {
}
func nextExercise() {
if currentExercise < workout.getWorkoutItems().count - 1 {
currentExercise += 1
}
}
// MARK: -- Workout Information
@@ -84,7 +82,7 @@ final class WorkoutSession: Nameable {
}
func getTotalExerciseCount() -> Double {
return Double(workout.getWorkoutItems().count)
return 100.0
}
func getCurrentExerciseIndex() -> Double {
@@ -96,10 +94,10 @@ final class WorkoutSession: Nameable {
}
func getCurrentExerciseName() -> String {
return workout.getWorkoutItems()[Int(currentExercise)].name
return "Hello"
}
func getCurrentExerciseMetric() -> String {
return String(workout.getWorkoutItems()[Int(currentExercise)].plannedReps)
return "Hello"
}
}

View File

@@ -0,0 +1,34 @@
//
// WorkoutSessionItem.swift
// WorkoutsPlus
//
// Created by Felix Förtsch on 15.10.24.
//
import Foundation
import SwiftData
@Model
final class WorkoutSessionItem: Nameable, Positionable {
var id = UUID()
var position: Int
var name: String
var workoutSession: WorkoutSession
var plannedReps: Int // 8 times | 1 time
var plannedValue: Double // With 10 | 42,187
var metric: ExerciseMetric? // kg (weight) | km (distance)
var actualReps: Int?
var actualValue: Double?
init(workoutSession: WorkoutSession, planned: WorkoutItem) {
self.workoutSession = workoutSession
self.name = planned.exercise.name
self.position = planned.position
self.plannedReps = planned.plannedReps
self.plannedValue = planned.plannedValue
self.metric = planned.metric
}
}

View File

@@ -1,25 +0,0 @@
//
// WorkoutSessionItem.swift
// WorkoutsPlus
//
// Created by Felix Förtsch on 15.10.24.
//
import Foundation
import SwiftData
@Model
final class WorkoutSessionItem {
var id = UUID()
var workoutSession: WorkoutSession
var exerciseData: WorkoutItem
var actualReps: Int?
var actualValue: Double?
init(workoutSession: WorkoutSession, planned: WorkoutItem) {
self.workoutSession = workoutSession
self.exerciseData = planned
}
}

View File

@@ -3,10 +3,10 @@ erDiagram
Exercise 1 .. 0+ Equipment : uses
Exercise 1 -- 0+ WorkoutItem : "provides data for"
Workout 1 .. 0+ WorkoutItem : collects
Workout 1 .. 0+ ViewModel : "provides data for"
Workout 1 .. 0+ WorkoutSession : "starts"
WorkoutItem 1 -- 1 WorkoutSessionItem : "provides data for"
WorkoutSession 1 -- 1+ WorkoutSessionItem : collects
ViewModel 1 -- 1+ WorkoutSession : "creates, starts"
ContentView 1 -- 1 WorkoutSession : "holds onto"
Exercise {
string name
@@ -29,7 +29,7 @@ erDiagram
int actualReps
double actualValue
}
ViewModel {
ContentView {
Workout workout
WorkoutSession workoutSession
}