Skip to content
Open
Show file tree
Hide file tree
Changes from 3 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
12 changes: 7 additions & 5 deletions Dropped/Models/UserData.swift
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,6 @@ struct Workout: Identifiable, Codable, Equatable {
enum WeightUnit: String, CaseIterable, Identifiable, Codable {
case pounds = "lb"
case kilograms = "kg"
case stones = "st"

var id: String { self.rawValue }

Expand All @@ -103,8 +102,6 @@ enum WeightUnit: String, CaseIterable, Identifiable, Codable {
valueInKg = value * 0.453592
case .kilograms:
valueInKg = value
case .stones:
valueInKg = value * 6.35029
}

// Convert from kg to target unit
Expand All @@ -113,8 +110,6 @@ enum WeightUnit: String, CaseIterable, Identifiable, Codable {
return valueInKg / 0.453592
case .kilograms:
return valueInKg
case .stones:
return valueInKg / 6.35029
}
}
}
Expand Down Expand Up @@ -199,6 +194,13 @@ class UserDataManager {
}

func loadUserData() -> UserData {
// Migrate any existing stones users to pounds
if userData.weightUnit == "st" {
Copy link

Copilot AI Jun 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[nitpick] Avoid using the hardcoded literal "st". Define a legacy constant or extension to represent the old stones unit, which improves readability and reduces magic strings.

Suggested change
if userData.weightUnit == "st" {
if userData.weightUnit == WeightUnit.stones.rawValue {

Copilot uses AI. Check for mistakes.
var migratedData = userData
migratedData.weightUnit = WeightUnit.pounds.rawValue
self.userData = migratedData
Copy link

Copilot AI Jun 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The migration logic updates in-memory userData but does not persist these changes to storage. Consider calling saveUserData(migratedData) within this block to ensure the migration is saved.

Suggested change
self.userData = migratedData
saveUserData(migratedData)

Copilot uses AI. Check for mistakes.
return migratedData
}
return userData
}

Expand Down
10 changes: 2 additions & 8 deletions Dropped/ViewModels/OnboardingViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ class OnboardingViewModel: ObservableObject {
@Published var selectedGoal: TrainingGoal = .haveFun
@Published var selectedWeightUnit: WeightUnit = .pounds // Default to American units
@Published var isMetric: Bool = false
@Published var showStonesOption: Bool = false

@Published var weightError: String? = nil
@Published var ftpError: String? = nil
Expand All @@ -32,8 +31,6 @@ class OnboardingViewModel: ObservableObject {
self.selectedWeightUnit = storedUnit
// Set isMetric based on the stored unit preference
self.isMetric = (storedUnit == .kilograms)
// Set showStonesOption if stones was previously selected
self.showStonesOption = (storedUnit == .stones)
}

// Convert the stored weight (in kg) to the selected unit and format it
Expand Down Expand Up @@ -104,19 +101,16 @@ class OnboardingViewModel: ObservableObject {
if isMetric {
convertWeight(to: .kilograms)
selectedWeightUnit = .kilograms
showStonesOption = false
} else {
// If switching to imperial, use previously selected imperial unit or default to pounds
// If switching to imperial, use pounds
if selectedWeightUnit == .kilograms {
convertWeight(to: .pounds)
selectedWeightUnit = .pounds
}
// Allow showing stones option when in imperial mode
showStonesOption = true
}
}

// Handle weight unit selection within the same system (e.g., between pounds and stones)
// Handle weight unit selection within the same system (e.g., between pounds and kilograms)
func selectWeightUnit(_ unit: WeightUnit) {
if unit != selectedWeightUnit {
convertWeight(to: unit)
Expand Down
19 changes: 0 additions & 19 deletions Dropped/Views/OnboardingView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -123,25 +123,6 @@ struct OnboardingView: View {
)
}
}

// Weight unit refinement if in imperial mode
if !viewModel.isMetric && viewModel.showStonesOption {
HStack(spacing: 12) {
Text("Weight Unit:")
.font(.subheadline)
.foregroundColor(.secondary)

Picker("Imperial Unit", selection: $viewModel.selectedWeightUnit) {
Text("Pounds (lb)").tag(WeightUnit.pounds)
Text("Stones (st)").tag(WeightUnit.stones)
}
.pickerStyle(SegmentedPickerStyle())
.onChange(of: viewModel.selectedWeightUnit) { _, newUnit in
viewModel.selectWeightUnit(newUnit)
}
}
.padding(.top, 8)
}
}
.padding()
.background(
Expand Down
13 changes: 0 additions & 13 deletions Dropped/Views/SettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -104,19 +104,6 @@ struct SettingsView: View {
}
}
}

// If in imperial mode, show detailed options
if !viewModel.isMetric {
Picker("Imperial Unit", selection: $viewModel.selectedWeightUnit) {
Text("Pounds (lb)").tag(WeightUnit.pounds)
Text("Stones (st)").tag(WeightUnit.stones)
}
.pickerStyle(SegmentedPickerStyle())
.padding(.top, 8)
.onChange(of: viewModel.selectedWeightUnit) { _, newUnit in
viewModel.selectWeightUnit(newUnit)
}
}
}
.padding(.vertical, 8)
}
Expand Down
26 changes: 13 additions & 13 deletions DroppedTests/OnboardingViewModelTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -137,27 +137,27 @@ final class OnboardingViewModelTests: XCTestCase {
XCTAssertEqual(viewModel.selectedWeightUnit, .pounds, "Default unit should be pounds")
viewModel.weight = "154.0" // in pounds

// Switch to stones
viewModel.selectWeightUnit(.stones)

// Check state
XCTAssertEqual(viewModel.selectedWeightUnit, .stones, "Unit should be stones")
XCTAssertFalse(viewModel.isMetric, "Should still be imperial")

// Check weight conversion (154 lb ≈ 11 stones)
let convertedWeight = Double(viewModel.weight) ?? 0
XCTAssertEqual(convertedWeight, 11.0, accuracy: 0.1, "Weight should be converted from lb to stones")

// Switch to kilograms
viewModel.selectWeightUnit(.kilograms)

// Check state
XCTAssertEqual(viewModel.selectedWeightUnit, .kilograms, "Unit should be kilograms")
XCTAssertTrue(viewModel.isMetric, "Should be metric")

// Check weight conversion (11 stones ≈ 69.85 kg)
// Check weight conversion (154 lb ≈ 69.85 kg)
let convertedToKgWeight = Double(viewModel.weight) ?? 0
XCTAssertEqual(convertedToKgWeight, 69.9, accuracy: 0.1, "Weight should be converted from stones to kg")
XCTAssertEqual(convertedToKgWeight, 69.9, accuracy: 0.1, "Weight should be converted from lb to kg")

// Switch back to pounds
viewModel.selectWeightUnit(.pounds)

// Check state
XCTAssertEqual(viewModel.selectedWeightUnit, .pounds, "Unit should be pounds")
XCTAssertFalse(viewModel.isMetric, "Should be imperial")

// Check weight conversion (69.9 kg ≈ 154 lb)
let convertedBackToLbWeight = Double(viewModel.weight) ?? 0
XCTAssertEqual(convertedBackToLbWeight, 154.0, accuracy: 0.1, "Weight should be converted from kg back to lb")
}

func testSaveUserData() throws {
Expand Down
53 changes: 44 additions & 9 deletions DroppedTests/UserDataTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,6 @@ final class UserDataTests: XCTestCase {
let kgToPoundsResult = WeightUnit.kilograms.convert(from: 70.0, to: .pounds)
XCTAssertEqual(kgToPoundsResult, 154.324, accuracy: 0.001, "Converting 70 kg to lb should be about 154.32 lb")

// Test stones to kilograms
let stonesToKgResult = WeightUnit.stones.convert(from: 11.0, to: .kilograms)
XCTAssertEqual(stonesToKgResult, 69.85319, accuracy: 0.001, "Converting 11 st to kg should be about 69.85 kg")

// Test circular conversion (should get back to original value)
let originalValue = 75.0
let intermediate = WeightUnit.kilograms.convert(from: originalValue, to: .pounds)
Expand Down Expand Up @@ -72,17 +68,17 @@ final class UserDataTests: XCTestCase {
// Weight should be converted to pounds for display
XCTAssertEqual(poundsDisplayData.displayWeight(), 154.324, accuracy: 0.001, "70kg should display as approximately 154.32 pounds")

// Create test data with weight in kg and display unit set to stones
let stonesDisplayData = UserData(
// Create test data with weight in kg and display unit set to kg
let kgDisplayData = UserData(
weight: 70.0, // Weight in kg
weightUnit: WeightUnit.stones.rawValue,
weightUnit: WeightUnit.kilograms.rawValue,
ftp: 200,
trainingHoursPerWeek: 5,
trainingGoal: TrainingGoal.haveFun.rawValue
)

// Weight should be converted to stones for display
XCTAssertEqual(stonesDisplayData.displayWeight(), 11.023, accuracy: 0.001, "70kg should display as approximately 11.02 stones")
// Weight should remain in kg for display
XCTAssertEqual(kgDisplayData.displayWeight(), 70.0, accuracy: 0.001, "70kg should display as 70kg")
}

func testHasCompletedOnboarding() throws {
Expand All @@ -101,4 +97,43 @@ final class UserDataTests: XCTestCase {
// Clean up
UserDefaults.standard.removeObject(forKey: "com.dropped.userdata")
}

func testStonesMigrationToLbs() throws {
// Test that users with stones get migrated to pounds
let manager = UserDataManager.shared

// Create test data with stones (simulating old data)
let testDataWithStones = UserData(
weight: 70.0,
weightUnit: "st", // old stones unit
ftp: 200,
trainingHoursPerWeek: 5,
trainingGoal: TrainingGoal.haveFun.rawValue
)

// Save the stones data
manager.saveUserData(testDataWithStones)

// Load it back - should be migrated to pounds
let loadedData = manager.loadUserData()

// Should be migrated to pounds
XCTAssertEqual(loadedData.weightUnit, WeightUnit.pounds.rawValue, "Stones should be migrated to pounds")
XCTAssertEqual(loadedData.weight, 70.0, "Weight value should remain the same (in kg)")

// Clean up
manager.saveUserData(UserData.defaultData)
}

func testWeightUnitCases() throws {
// Verify we only have pounds and kilograms
let allCases = WeightUnit.allCases
XCTAssertEqual(allCases.count, 2, "Should only have 2 weight units")
XCTAssertTrue(allCases.contains(.pounds), "Should contain pounds")
XCTAssertTrue(allCases.contains(.kilograms), "Should contain kilograms")

// Verify raw values
XCTAssertEqual(WeightUnit.pounds.rawValue, "lb")
XCTAssertEqual(WeightUnit.kilograms.rawValue, "kg")
}
}