Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Workout Selection Changes #54

Merged
merged 1 commit into from
Mar 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Stronger.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@
653A2551283387FE005D4D48 /* Stronger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653A2550283387FE005D4D48 /* Stronger.swift */; };
653A255528338800005D4D48 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 653A255428338800005D4D48 /* Assets.xcassets */; };
653A256228338800005D4D48 /* StrongerTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 653A256128338800005D4D48 /* StrongerTests.swift */; };
7DBE5D1F2B9A5AB7001C2E7C /* WorkoutSelections.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DBE5D1E2B9A5AB7001C2E7C /* WorkoutSelections.swift */; };
7DE98D812B69D96300449C81 /* InputForm.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7DE98D802B69D96300449C81 /* InputForm.swift */; };
9733CFC62A8066DE001B7ABC /* SpeziOnboarding in Frameworks */ = {isa = PBXBuildFile; productRef = 2FE5DC8029EDD91D004B9AB4 /* SpeziOnboarding */; };
9739A0C62AD7B5730084BEA5 /* FirebaseStorage in Frameworks */ = {isa = PBXBuildFile; productRef = 9739A0C52AD7B5730084BEA5 /* FirebaseStorage */; };
Expand Down Expand Up @@ -259,6 +260,7 @@
653A256128338800005D4D48 /* StrongerTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StrongerTests.swift; sourceTree = "<group>"; };
653A256728338800005D4D48 /* StrongerUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = StrongerUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
653A258928339462005D4D48 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
7DBE5D1E2B9A5AB7001C2E7C /* WorkoutSelections.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WorkoutSelections.swift; sourceTree = "<group>"; };
7DE98D802B69D96300449C81 /* InputForm.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InputForm.swift; sourceTree = "<group>"; };
A9720E422ABB68CC00872D23 /* AccountSetupHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountSetupHeader.swift; sourceTree = "<group>"; };
A9DFE8A82ABE551400428242 /* AccountButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccountButton.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -452,6 +454,7 @@
38C4563D2B96CF3B009D69AA /* WorkoutHomeButton.swift */,
4051334C2B8C8D5400ED62BA /* WorkoutHome.swift */,
4051334E2B8C9D8100ED62BA /* UploadDummyData.swift */,
7DBE5D1E2B9A5AB7001C2E7C /* WorkoutSelections.swift */,
);
path = Exercise;
sourceTree = "<group>";
Expand Down Expand Up @@ -862,6 +865,7 @@
6325F3932B830B9C00A31314 /* ProteinRing.swift in Sources */,
4011141D2B83FCD1000083A2 /* SummaryView.swift in Sources */,
4011141A2B7EE59A000083A2 /* ProgressCircle.swift in Sources */,
7DBE5D1F2B9A5AB7001C2E7C /* WorkoutSelections.swift in Sources */,
2F4E23832989D51F0013F3D9 /* StrongerTestingSetup.swift in Sources */,
7DE98D812B69D96300449C81 /* InputForm.swift in Sources */,
2FE5DC5329EDD7FA004B9AB4 /* Bundle+Questionnaire.swift in Sources */,
Expand Down
6 changes: 4 additions & 2 deletions Stronger/Exercise/WorkoutHome.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,10 @@
dayPicker
Spacer()
NavigationLink(
destination: WorkoutSelection(
presentingAccount: $presentingAccount
destination: WorkoutSelections(
presentingAccount: $presentingAccount,
selectedWeek: selectedWeek,
selectedDay: selectedDay

Check warning on line 60 in Stronger/Exercise/WorkoutHome.swift

View check run for this annotation

Codecov / codecov/patch

Stronger/Exercise/WorkoutHome.swift#L57-L60

Added lines #L57 - L60 were not covered by tests
)
) {
Text("Enter Workout Information\n for Week \(selectedWeek + 1) Day \(selectedDay + 1).")
Expand Down
343 changes: 343 additions & 0 deletions Stronger/Exercise/WorkoutSelections.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,343 @@
//
// WorkoutHome.swift
// Stronger
//
// Created by Theodore Kanell on 2/6/24.
//
// SPDX-FileCopyrightText: 2023 Stanford University
//
// SPDX-License-Identifier: MIT
//

import Firebase
import SpeziAccount
import SwiftUI

struct WorkoutSelections: View {
// Struct to hold view and string data
struct MenuItem {
var view: WorkoutInputForm
var title: String
var video: String
}
@State private var menuItems: [MenuItem] = []

Check warning on line 23 in Stronger/Exercise/WorkoutSelections.swift

View check run for this annotation

Codecov / codecov/patch

Stronger/Exercise/WorkoutSelections.swift#L23

Added line #L23 was not covered by tests
@Binding var presentingAccount: Bool
@State var selectedWeek: Int?
@State var selectedDay: Int?
@State private var geometry: CGSize = .zero

Check warning on line 27 in Stronger/Exercise/WorkoutSelections.swift

View check run for this annotation

Codecov / codecov/patch

Stronger/Exercise/WorkoutSelections.swift#L27

Added line #L27 was not covered by tests
@Environment(Account.self) var account

private var menuItemsBackup: [MenuItem] = [
MenuItem(
view: WorkoutInputForm(
workoutName: "Squats",
presentingAccount: .constant(false),
selectedWeek: 1,
selectedDay: 1
),
title: "Squats",
video: "squats"
),
MenuItem(
view: WorkoutInputForm(
workoutName: "Row",
presentingAccount: .constant(false),
selectedWeek: 1,
selectedDay: 1
),
title: "Row",
video: "row"
),
MenuItem(
view: WorkoutInputForm(
workoutName: "Pull Downs",
presentingAccount: .constant(false),
selectedWeek: 1,
selectedDay: 1
),
title: "Pull Downs",
video: "straightarmpulldowns"
)
]

Check warning on line 61 in Stronger/Exercise/WorkoutSelections.swift

View check run for this annotation

Codecov / codecov/patch

Stronger/Exercise/WorkoutSelections.swift#L30-L61

Added lines #L30 - L61 were not covered by tests


var body: some View {
GeometryReader {geometry in
NavigationStack {
VStack {
Text("Workout Home")
.font(.title)
.padding()

// Use the initialized menuItems array
ForEach(menuItems, id: \.title) { menuItem in
WorkoutHomeButton(
presentingAccount: $presentingAccount,
item: menuItem.title,
totalWidth: widthForMenuItems(in: geometry),
selectedWeek: selectedWeek ?? 1,
selectedDay: selectedDay ?? 1
)
}

Spacer()
NavigationLink(destination: WorkoutHome(presentingAccount: $presentingAccount)) {
Text("Enter Missed Workout")
.foregroundColor(.primary)
.padding()
// .frame(width: totalWidth)
.background(Color.blue)
.cornerRadius(8)
}
}
}
.navigationBarBackButtonHidden(true)
.navigationBarTitle("Workout Selection")
.onAppear {
Task {
try await onAppearFunc()
}
}
}
}

Check warning on line 102 in Stronger/Exercise/WorkoutSelections.swift

View check run for this annotation

Codecov / codecov/patch

Stronger/Exercise/WorkoutSelections.swift#L64-L102

Added lines #L64 - L102 were not covered by tests

init(presentingAccount: Binding<Bool>, selectedWeek: Int?, selectedDay: Int?) {
self._presentingAccount = presentingAccount
self.selectedWeek = selectedWeek
self.selectedDay = selectedDay
}

Check warning on line 108 in Stronger/Exercise/WorkoutSelections.swift

View check run for this annotation

Codecov / codecov/patch

Stronger/Exercise/WorkoutSelections.swift#L104-L108

Added lines #L104 - L108 were not covered by tests

private func onAppearFunc() async throws {
selectedWeek = try? await calculateWeeksElapsed()
print("Selected Week: \(selectedWeek ?? 1)")
try await updateExerciseDate()
if let exercises = parseExercises(week: selectedWeek ?? 1, day: selectedDay ?? 1) {
buildMenuItem(workoutInst: exercises)
} else {
print("Error: Unable to parse exercises for the selected week and day.")
}
}

Check warning on line 119 in Stronger/Exercise/WorkoutSelections.swift

View check run for this annotation

Codecov / codecov/patch

Stronger/Exercise/WorkoutSelections.swift#L110-L119

Added lines #L110 - L119 were not covered by tests

private func widthForMenuItems(in geometry: GeometryProxy) -> CGFloat {
// Calculate the width of the longest title
let longestTitleWidth = menuItems.map { menuItem in
menuItem.title.widthOfString(usingFont: .systemFont(ofSize: 17))
}
.max() ?? 0
// print(longestTitleWidth)
// Calculate the width as a percentage of the screen width
let desiredWidth = longestTitleWidth + 32 // Add padding

// Ensure the width does not exceed the screen width
return min(desiredWidth, geometry.size.width * 0.5) // Set width as 50% of screen width
}

Check warning on line 133 in Stronger/Exercise/WorkoutSelections.swift

View check run for this annotation

Codecov / codecov/patch

Stronger/Exercise/WorkoutSelections.swift#L121-L133

Added lines #L121 - L133 were not covered by tests

private func parseExercises(week: Int, day: Int) -> Workout? {
// Get the URL of the JSON file in the app bundle
if let fileURL = Bundle.main.url(forResource: "exercise_list", withExtension: "json") {
do {
// Read JSON data from the file
let jsonData = try Data(contentsOf: fileURL)
// print("JSON Data: \(String(describing: String(data: jsonData, encoding: .utf8)))")
// Decode JSON data into WorkoutPlan struct
let workoutPlan = try JSONDecoder().decode(WorkoutPlan.self, from: jsonData)
var workout = workoutPlan.weeks1to3
switch week {
case 1...3:
workout = workoutPlan.weeks1to3
case 4...6:
workout = workoutPlan.weeks4to6
case 7...9:
workout = workoutPlan.weeks7to9
case 10...12:
workout = workoutPlan.weeks10to12
default:
workout = workoutPlan.weeks1to3// Return the original value for any other cases
}
print("Day at parse exercises: \(day)")

if day >= workout.count || day <= 0 {
return workout[0]
}

return workout[day - 1]
// Access the decoded data

} catch {
print("Error decoding JSON: \(error)")
return nil
}
} else {
print("JSON file not found in the app bundle.")
return nil
}
}

Check warning on line 174 in Stronger/Exercise/WorkoutSelections.swift

View check run for this annotation

Codecov / codecov/patch

Stronger/Exercise/WorkoutSelections.swift#L135-L174

Added lines #L135 - L174 were not covered by tests


// week should be a value 1 - 12.
// Day should be value 1 - 3
private func buildMenuItem(workoutInst: Workout) {
self.menuItems = []
for exerciseNumber in 1...4 {
let exercise: String
let video: String
switch exerciseNumber {
case 1:
exercise = workoutInst.exercise1
video = workoutInst.exercise1video
case 2:
exercise = workoutInst.exercise2
video = workoutInst.exercise2video
case 3:
exercise = workoutInst.exercise3
video = workoutInst.exercise3video
case 4:
exercise = workoutInst.exercise4
video = workoutInst.exercise4video
default:
exercise = "" // This should never happen
video = ""
}
let menuItem = MenuItem(
view: WorkoutInputForm(
workoutName: exercise,
presentingAccount: $presentingAccount,
selectedWeek: selectedWeek ?? 1,
selectedDay: selectedDay ?? 1
),
title: exercise,
video: video
)
self.menuItems.append(menuItem)
}
}

Check warning on line 213 in Stronger/Exercise/WorkoutSelections.swift

View check run for this annotation

Codecov / codecov/patch

Stronger/Exercise/WorkoutSelections.swift#L179-L213

Added lines #L179 - L213 were not covered by tests

private func updateExerciseDate() async throws {
// Get current user ID
guard let userID = try await getCurrentUserID() else {
print("Error getting user id")
return
}

// Reference to Firestore database
let dbe = Firestore.firestore()

let userDocRef = dbe.collection("users").document(userID).collection("exerciseLog")
let query = userDocRef.whereField("week", isEqualTo: self.selectedWeek)

query.getDocuments { querySnapshot, error in
if let error = error {
print("Error fetching documents: \(error)")
} else {
// Get the count of documents
let documentCount = querySnapshot?.documents.count ?? 0

// Check if there are no documents
if documentCount == 0 {
print("No documents found. Setting selectedDay to 1.")
selectedDay = 1
} else {
// Check if there are documents with selectedDay equal to 1
let selectedDay1Count = querySnapshot?.documents.filter { $0["exerciseDay"] as? Int == 2 }.count ?? 0
if selectedDay1Count > 3 {
print("Documents found with selectedDay equal to 2. Setting selectedDay to 3.")
selectedDay = 3
} else {
// Check if there are documents with selectedDay equal to 2
let selectedDay2Count = querySnapshot?.documents.filter { $0["exerciseDay"] as? Int == 1 }.count ?? 0
if selectedDay2Count > 3 {
print("Documents found with selectedDay equal to 1. Setting selectedDay to 2.")
selectedDay = 2
} else {
// If no documents have selectedDay equal to 1 or 2, set selectedDay to 1
print("No documents found with selectedDay equal to 1 or 2. Setting selectedDay to 1.")
selectedDay = 1
}
}
}
}
}
}

Check warning on line 260 in Stronger/Exercise/WorkoutSelections.swift

View check run for this annotation

Codecov / codecov/patch

Stronger/Exercise/WorkoutSelections.swift#L215-L260

Added lines #L215 - L260 were not covered by tests


// Function to get the current user ID
private func getCurrentUserID() async throws -> String? {
guard let details = try? await account.details else {
return nil
}
return details.accountId
}

Check warning on line 269 in Stronger/Exercise/WorkoutSelections.swift

View check run for this annotation

Codecov / codecov/patch

Stronger/Exercise/WorkoutSelections.swift#L264-L269

Added lines #L264 - L269 were not covered by tests

// Function to retrieve start day field and calculate weeks elapsed
private func calculateWeeksElapsed() async throws -> Int {
// Get current user ID
guard let userID = try await getCurrentUserID() else {
return 1
}

// Reference to Firestore database
let dbe = Firestore.firestore()

// Reference to document for current user
let userDocRef = dbe.collection("users").document(userID)

// Get snapshot of document
let userDocSnapshot = try await userDocRef.getDocument()

// Check if document exists and contains start day field
guard let userData = userDocSnapshot.data(),
let startDayTimestamp = userData["StartDateKey"] as? Timestamp else {
print("did not find start day key", userID)
return 1
}

print("Found start date key", userID)
// Get start date from Timestamp
var startDayDate = startDayTimestamp.dateValue()

// Get current date
let currentDate = Date()

// Get Calendar instance
let calendar = Calendar.current

// Move start day to closest Monday
let weekday = calendar.component(.weekday, from: startDayDate)
let daysToMonday = (7 - weekday + 2) % 7 // +2 because Sunday is 1-based in `weekday` but we want Monday to be 0-based
print("daysTOMonday \(daysToMonday)")
startDayDate = calendar.date(byAdding: .day, value: -daysToMonday, to: startDayDate) ?? startDayDate
print("startDayDate \(startDayDate)")

// Calculate difference in weeks between start day and current date
let weeksElapsed = calendar.dateComponents([.weekOfYear], from: startDayDate, to: currentDate).weekOfYear ?? 0
print("weeksElapsed \(weeksElapsed)")
let roundedWeeksElapsed = weeksElapsed > 0 ? weeksElapsed : 0 // Ensure weeksElapsed is non-negative
print("rounded weeks elapsed \(roundedWeeksElapsed)")
return weeksElapsed
}

Check warning on line 317 in Stronger/Exercise/WorkoutSelections.swift

View check run for this annotation

Codecov / codecov/patch

Stronger/Exercise/WorkoutSelections.swift#L272-L317

Added lines #L272 - L317 were not covered by tests

private func uploadUserData() {
let dbe = Firestore.firestore()

// Data to be uploaded
let userData: [String: Any] = [
"name": "Rohan Gondor",
"role": "admin"
]

// Upload data to Firestore
dbe.collection("users").document("admin").setData(userData) { error in
if let error = error {
print("Error uploading user data: \(error.localizedDescription)")
} else {
print("User data uploaded successfully!")
}
}
}

Check warning on line 336 in Stronger/Exercise/WorkoutSelections.swift

View check run for this annotation

Codecov / codecov/patch

Stronger/Exercise/WorkoutSelections.swift#L319-L336

Added lines #L319 - L336 were not covered by tests
}

struct Preview: PreviewProvider {
static var previews: some View {
WorkoutSelections(presentingAccount: .constant(false), selectedWeek: 1, selectedDay: 2)
}

Check warning on line 342 in Stronger/Exercise/WorkoutSelections.swift

View check run for this annotation

Codecov / codecov/patch

Stronger/Exercise/WorkoutSelections.swift#L340-L342

Added lines #L340 - L342 were not covered by tests
}
Loading