Просмотр исходного кода

Add unit and pump selection; add delivery limits WIP

Deniz Cengiz 1 год назад
Родитель
Сommit
cfec2e900b

+ 8 - 0
Trio.xcodeproj/project.pbxproj

@@ -550,6 +550,8 @@
 		DD32CFA22CC824E2003686D6 /* TrioRemoteControl+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD32CFA12CC824E1003686D6 /* TrioRemoteControl+Helpers.swift */; };
 		DD3A3CE72D29C93F00AE478E /* Helper+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3A3CE62D29C93F00AE478E /* Helper+Extensions.swift */; };
 		DD3A3CE92D29C97800AE478E /* Helper+ButtonStyles.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3A3CE82D29C97800AE478E /* Helper+ButtonStyles.swift */; };
+		DD3F1F832D9DC78800DCE7B3 /* UnitSelectionStepView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3F1F822D9DC78300DCE7B3 /* UnitSelectionStepView.swift */; };
+		DD3F1F852D9DD84000DCE7B3 /* DeliveryLimitsStepView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD3F1F842D9DD83B00DCE7B3 /* DeliveryLimitsStepView.swift */; };
 		DD498F2B2D692BEA00AAEA30 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 8A9134292D63D9A1007F8874 /* Localizable.xcstrings */; };
 		DD498F2C2D692BEA00AAEA30 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 8A9134292D63D9A1007F8874 /* Localizable.xcstrings */; };
 		DD498F2D2D692BEA00AAEA30 /* Localizable.xcstrings in Resources */ = {isa = PBXBuildFile; fileRef = 8A9134292D63D9A1007F8874 /* Localizable.xcstrings */; };
@@ -1327,6 +1329,8 @@
 		DD32CFA12CC824E1003686D6 /* TrioRemoteControl+Helpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TrioRemoteControl+Helpers.swift"; sourceTree = "<group>"; };
 		DD3A3CE62D29C93F00AE478E /* Helper+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Helper+Extensions.swift"; sourceTree = "<group>"; };
 		DD3A3CE82D29C97800AE478E /* Helper+ButtonStyles.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Helper+ButtonStyles.swift"; sourceTree = "<group>"; };
+		DD3F1F822D9DC78300DCE7B3 /* UnitSelectionStepView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UnitSelectionStepView.swift; sourceTree = "<group>"; };
+		DD3F1F842D9DD83B00DCE7B3 /* DeliveryLimitsStepView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeliveryLimitsStepView.swift; sourceTree = "<group>"; };
 		DD4C57A72D73ADEA001BFF2C /* RestartLiveActivityIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestartLiveActivityIntent.swift; sourceTree = "<group>"; };
 		DD4C57A92D73B3D9001BFF2C /* RestartLiveActivityIntentRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RestartLiveActivityIntentRequest.swift; sourceTree = "<group>"; };
 		DD4C581E2D73C43D001BFF2C /* LoopStatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoopStatsView.swift; sourceTree = "<group>"; };
@@ -2733,6 +2737,8 @@
 		BD47FDD52D8B64AE0043966B /* OnboardingSteps */ = {
 			isa = PBXGroup;
 			children = (
+				DD3F1F842D9DD83B00DCE7B3 /* DeliveryLimitsStepView.swift */,
+				DD3F1F822D9DC78300DCE7B3 /* UnitSelectionStepView.swift */,
 				BD47FD162D88AAEF0043966B /* OnboardingStepViews.swift */,
 				BD47FDDC2D8B65AD0043966B /* GlucoseTargetStepView.swift */,
 				BD47FDDA2D8B65960043966B /* BasalProfileStepView.swift */,
@@ -4317,6 +4323,7 @@
 				0D9A5E34A899219C5C4CDFAF /* DataTableStateModel.swift in Sources */,
 				6BCF84DD2B16843A003AD46E /* LiveActitiyAttributes.swift in Sources */,
 				195D80B92AF697F700D25097 /* DynamicSettingsProvider.swift in Sources */,
+				DD3F1F832D9DC78800DCE7B3 /* UnitSelectionStepView.swift in Sources */,
 				DD09D47D2C5986DA003FEA5D /* CalendarEventSettingsProvider.swift in Sources */,
 				DD09D47B2C5986D1003FEA5D /* CalendarEventSettingsDataFlow.swift in Sources */,
 				DD1745202C55523E00211FAC /* SMBSettingsDataFlow.swift in Sources */,
@@ -4359,6 +4366,7 @@
 				BDDAF9EF2D00554500B34E7A /* SelectionPopoverView.swift in Sources */,
 				DDE1795F2C910127003CDDB7 /* PumpEventStored+CoreDataProperties.swift in Sources */,
 				DDE179602C910127003CDDB7 /* StatsData+CoreDataClass.swift in Sources */,
+				DD3F1F852D9DD84000DCE7B3 /* DeliveryLimitsStepView.swift in Sources */,
 				DDE179612C910127003CDDB7 /* StatsData+CoreDataProperties.swift in Sources */,
 				DDE179622C910127003CDDB7 /* Forecast+CoreDataClass.swift in Sources */,
 				DDE179632C910127003CDDB7 /* Forecast+CoreDataProperties.swift in Sources */,

+ 6 - 6
Trio/Sources/Localizations/Main/Localizable.xcstrings

@@ -17113,9 +17113,6 @@
     "75th Percentile" : {
 
     },
-    "80" : {
-
-    },
     "90%:" : {
 
     },
@@ -17322,9 +17319,6 @@
         }
       }
     },
-    "120" : {
-
-    },
     "123" : {
       "localizations" : {
         "bg" : {
@@ -125911,6 +125905,9 @@
         }
       }
     },
+    "Note: Choosing your pump model determines which increments for setting up your basal rates (0.1 or 0.05) are available. You will pair your actual pump after finishing the onboarding process through Trio's main screen, the Home View." : {
+
+    },
     "Note: If enabled, the smoothed values you see in Trio may differ from what is shown in your CGM app." : {
       "localizations" : {
         "bg" : {
@@ -134759,6 +134756,9 @@
         }
       }
     },
+    "Please choose from the options below." : {
+
+    },
     "Please make sure that your Libre 2 sensor is already activated and finished warming up. If you have other apps connecting to the sensor via bluetooth, these need to be shut down or uninstalled. \n\n You can only have one app communicating with the sensor via bluetooth. Then press the \"pariring and connection\" button below to start the process. Please note that the bluetooth connection might take up to a couple of minutes before it starts working." : {
       "extractionState" : "manual",
       "localizations" : {

+ 3 - 1
Trio/Sources/Models/BloodGlucose.swift

@@ -157,11 +157,13 @@ struct BloodGlucose: JSON, Identifiable, Hashable, Codable {
     }
 }
 
-enum GlucoseUnits: String, JSON, Equatable {
+enum GlucoseUnits: String, JSON, Equatable, CaseIterable, Identifiable {
     case mgdL = "mg/dL"
     case mmolL = "mmol/L"
 
     static let exchangeRate: Decimal = 0.0555
+
+    var id: String { rawValue }
 }
 
 extension Int {

+ 50 - 1
Trio/Sources/Modules/Onboarding/OnboardingStateModel.swift

@@ -7,10 +7,12 @@ import SwiftUI
 /// Represents the different steps in the onboarding process.
 enum OnboardingStep: Int, CaseIterable, Identifiable {
     case welcome
+    case unitSelection
     case glucoseTarget
     case basalProfile
     case carbRatio
     case insulinSensitivity
+    case deliveryLimits
     case completed
 
     var id: Int { rawValue }
@@ -20,6 +22,8 @@ enum OnboardingStep: Int, CaseIterable, Identifiable {
         switch self {
         case .welcome:
             return "Welcome to Trio"
+        case .unitSelection:
+            return "Units & Pump"
         case .glucoseTarget:
             return "Glucose Target"
         case .basalProfile:
@@ -28,6 +32,8 @@ enum OnboardingStep: Int, CaseIterable, Identifiable {
             return "Carbohydrate Ratio"
         case .insulinSensitivity:
             return "Insulin Sensitivity"
+        case .deliveryLimits:
+            return "Delivery Limits"
         case .completed:
             return "All Set!"
         }
@@ -38,6 +44,8 @@ enum OnboardingStep: Int, CaseIterable, Identifiable {
         switch self {
         case .welcome:
             return "Trio is a powerful app that helps you manage your diabetes. Let's get started by setting up a few important parameters that will help Trio work effectively for you."
+        case .unitSelection:
+            return "Before you can begin with configuring your therapy settigns, Trio needs to know which units you use for your glucose and insulin measurements (based on your pump model)."
         case .glucoseTarget:
             return "Your glucose target is the blood glucose level you aim to maintain. Trio will use this to calculate insulin doses and provide recommendations."
         case .basalProfile:
@@ -46,6 +54,8 @@ enum OnboardingStep: Int, CaseIterable, Identifiable {
             return "Your carb ratio tells how many grams of carbohydrates one unit of insulin will cover. This is essential for accurate meal bolus calculations."
         case .insulinSensitivity:
             return "Your insulin sensitivity factor (ISF) indicates how much one unit of insulin will lower your blood glucose. This helps calculate correction boluses."
+        case .deliveryLimits:
+            return "Trio offers various delivery limits which represent the maximum amount of insulin it can deliver at a time. This helps ensure safe and effective experience."
         case .completed:
             return "Great job! You've completed the initial setup of Trio. You can always adjust these settings later in the app."
         }
@@ -56,6 +66,8 @@ enum OnboardingStep: Int, CaseIterable, Identifiable {
         switch self {
         case .welcome:
             return "hand.wave.fill"
+        case .unitSelection:
+            return "numbers.rectangle"
         case .glucoseTarget:
             return "target"
         case .basalProfile:
@@ -64,6 +76,8 @@ enum OnboardingStep: Int, CaseIterable, Identifiable {
             return "fork.knife"
         case .insulinSensitivity:
             return "drop.fill"
+        case .deliveryLimits:
+            return "slider.horizontal.3"
         case .completed:
             return "checkmark.circle.fill"
         }
@@ -90,6 +104,8 @@ enum OnboardingStep: Int, CaseIterable, Identifiable {
         switch self {
         case .welcome:
             return Color.blue
+        case .unitSelection:
+            return Color.blue
         case .glucoseTarget:
             return Color.green
         case .basalProfile:
@@ -104,6 +120,28 @@ enum OnboardingStep: Int, CaseIterable, Identifiable {
     }
 }
 
+enum PumpOptionsForOnboardingUnits: String, Equatable, CaseIterable, Identifiable {
+    case minimed
+    case omnipodEros
+    case omnipodDash
+    case dana
+
+    var id: String { rawValue }
+
+    var displayName: String {
+        switch self {
+        case .minimed:
+            return "Medtronic 5xx / 7xx"
+        case .omnipodEros:
+            return "Omnipod Eros"
+        case .omnipodDash:
+            return "Omnipod Dash"
+        case .dana:
+            return "Dana (RS/-i)"
+        }
+    }
+}
+
 /// Model that holds the data collected during onboarding.
 extension Onboarding {
     @Observable final class StateModel: BaseStateModel<Provider> {
@@ -120,7 +158,16 @@ extension Onboarding {
         var initialBasalProfileItems: [BasalProfileEditor.Item] = []
         var basalProfileItems: [BasalProfileEditor.Item] = []
         let basalProfileTimeValues = stride(from: 0.0, to: 1.days.timeInterval, by: 30.minutes.timeInterval).map { $0 }
-        var basalProfileRateValues: [Decimal] = stride(from: 0.05, to: 3.05, by: 0.05).map { Decimal($0) }
+        var basalProfileRateValues: [Decimal] {
+            switch pumpModel {
+            case .dana,
+                 .minimed:
+                return stride(from: 0.1, to: 30.0, by: 0.1).map { Decimal($0) }
+            case .omnipodDash,
+                 .omnipodEros:
+                return stride(from: 0.05, to: 30.0, by: 0.05).map { Decimal($0) }
+            }
+        }
 
         // ISF related
         var isfItems: [ISFEditor.Item] = []
@@ -159,6 +206,8 @@ extension Onboarding {
         // Blood Glucose Units
         var units: GlucoseUnits = .mgdL
 
+        var pumpModel: PumpOptionsForOnboardingUnits = .omnipodDash
+
         struct BasalRateEntry: Identifiable {
             var id = UUID()
             var startTime: Int // Minutes from midnight

+ 1 - 1
Trio/Sources/Modules/Onboarding/View/OnboardingSteps/BasalProfileStepView.swift

@@ -33,7 +33,7 @@ struct BasalProfileStepView: View {
     }
 
     var body: some View {
-        ScrollView {
+        LazyVStack {
             VStack(alignment: .leading, spacing: 0) {
                 // Chart visualization
                 if !state.basalProfileItems.isEmpty {

+ 1 - 1
Trio/Sources/Modules/Onboarding/View/OnboardingSteps/CarbRatioStepView.swift

@@ -33,7 +33,7 @@ struct CarbRatioStepView: View {
     }
 
     var body: some View {
-        ScrollView {
+        LazyVStack {
             VStack(alignment: .leading, spacing: 0) {
                 // Chart visualization
                 if !state.carbRatioItems.isEmpty {

+ 21 - 0
Trio/Sources/Modules/Onboarding/View/OnboardingSteps/DeliveryLimitsStepView.swift

@@ -0,0 +1,21 @@
+//
+//  DeliveryLimitsStepView.swift
+//  Trio
+//
+//  Created by Cengiz Deniz on 02.04.25.
+//
+
+import SwiftUI
+
+struct DeliveryLimitsStepView: View {
+    @Bindable var state: Onboarding.StateModel
+
+    var body: some View {
+        VStack(alignment: .leading, spacing: 8) {
+            Text("Max IOB")
+            Text("Max Bolus")
+            Text("Max Basal")
+            Text("Max COB")
+        }
+    }
+}

+ 1 - 1
Trio/Sources/Modules/Onboarding/View/OnboardingSteps/GlucoseTargetStepView.swift

@@ -34,7 +34,7 @@ struct GlucoseTargetStepView: View {
         .date(from: DateComponents(year: 2001, month: 01, day: 01, hour: 0, minute: 0, second: 0))
 
     var body: some View {
-        ScrollView {
+        LazyVStack {
             VStack(alignment: .leading, spacing: 0) {
                 // Chart visualization
                 if !state.targetItems.isEmpty {

+ 1 - 1
Trio/Sources/Modules/Onboarding/View/OnboardingSteps/InsulinSensitivityStepView.swift

@@ -33,7 +33,7 @@ struct InsulinSensitivityStepView: View {
     }
 
     var body: some View {
-        ScrollView {
+        LazyVStack {
             VStack(alignment: .leading, spacing: 0) {
                 // Chart visualization
                 if !state.isfItems.isEmpty {

+ 47 - 0
Trio/Sources/Modules/Onboarding/View/OnboardingSteps/UnitSelectionStepView.swift

@@ -0,0 +1,47 @@
+import SwiftUI
+
+struct UnitSelectionStepView: View {
+    @Bindable var state: Onboarding.StateModel
+
+    var body: some View {
+        VStack(alignment: .leading, spacing: 8) {
+            Text("Please choose from the options below.")
+                .font(.headline)
+
+            Spacer(minLength: 20)
+
+            HStack {
+                Text("Glucose Units")
+                Spacer()
+                Picker("Glucose Units", selection: $state.units) {
+                    ForEach(GlucoseUnits.allCases, id: \.self) { unit in
+                        Text(unit.rawValue).tag(unit)
+                    }
+                }
+            }
+            .padding()
+            .background(Color.chart.opacity(0.45))
+            .cornerRadius(10)
+
+            HStack {
+                Text("Pump Model")
+                Spacer()
+                Picker("Pump Model", selection: $state.pumpModel) {
+                    ForEach(PumpOptionsForOnboardingUnits.allCases, id: \.self) { pumpModel in
+                        Text(pumpModel.displayName).tag(pumpModel)
+                    }
+                }
+            }
+            .padding()
+            .background(Color.chart.opacity(0.45))
+            .cornerRadius(10)
+
+            Text(
+                "Note: Choosing your pump model determines which increments for setting up your basal rates are available. You will pair your actual pump after finishing the onboarding process."
+            )
+            .padding(.vertical)
+            .font(.footnote)
+            .foregroundStyle(Color.secondary)
+        }
+    }
+}

+ 236 - 232
Trio/Sources/Modules/Onboarding/View/OnboardingView.swift

@@ -82,6 +82,8 @@ extension Onboarding {
                                     switch currentStep {
                                     case .welcome:
                                         WelcomeStepView()
+                                    case .unitSelection:
+                                        UnitSelectionStepView(state: state)
                                     case .glucoseTarget:
                                         GlucoseTargetStepView(state: state)
                                     case .basalProfile:
@@ -90,6 +92,8 @@ extension Onboarding {
                                         CarbRatioStepView(state: state)
                                     case .insulinSensitivity:
                                         InsulinSensitivityStepView(state: state)
+                                    case .deliveryLimits:
+                                        DeliveryLimitsStepView(state: state)
                                     case .completed:
                                         CompletedStepView()
                                     }
@@ -195,238 +199,238 @@ struct OnboardingProgressBar: View {
     }
 }
 
-/// A simple animated placeholder for each step
-struct AnimationPlaceholder: View {
-    let step: OnboardingStep
-    @State private var animationValue: Double = 0
-
-    init(for step: OnboardingStep) {
-        self.step = step
-    }
-
-    var body: some View {
-        VStack {
-            Group {
-                switch step {
-                case .welcome:
-                    welcomeAnimation
-                case .glucoseTarget:
-                    glucoseTargetAnimation
-                case .basalProfile:
-                    basalProfileAnimation
-                case .carbRatio:
-                    carbRatioAnimation
-                case .insulinSensitivity:
-                    insulinSensitivityAnimation
-                case .completed:
-                    completedAnimation
-                }
-            }
-            .frame(height: 180)
-        }
-        .onAppear {
-            withAnimation(Animation.easeInOut(duration: 2).repeatForever(autoreverses: true)) {
-                animationValue = 1.0
-            }
-        }
-    }
-
-    // Custom animated views for each step
-    var welcomeAnimation: some View {
-        ZStack {
-            ForEach(0 ..< 5) { index in
-                Image(systemName: "heart.fill")
-                    .font(.system(size: 40))
-                    .foregroundColor(step.accentColor.opacity(0.8 - Double(index) * 0.15))
-                    .offset(x: CGFloat.random(in: -100 ... 100), y: CGFloat.random(in: -60 ... 60))
-                    .scaleEffect(1.0 + animationValue * 0.3)
-                    .rotationEffect(.degrees(animationValue * Double.random(in: -30 ... 30)))
-            }
-
-            Image(systemName: "syringe.fill")
-                .font(.system(size: 80))
-                .foregroundColor(step.accentColor)
-                .scaleEffect(1.0 + animationValue * 0.2)
-                .shadow(color: step.accentColor.opacity(0.5), radius: 10 * animationValue, x: 0, y: 0)
-        }
-    }
-
-    var glucoseTargetAnimation: some View {
-        ZStack {
-            // Target rings
-            ForEach(0 ..< 3) { index in
-                Circle()
-                    .stroke(step.accentColor.opacity(Double(3 - index) * 0.3), lineWidth: 8)
-                    .frame(width: 120 + CGFloat(index * 40))
-                    .scaleEffect(1.0 + animationValue * 0.05)
-            }
-
-            // Arrow
-            Image(systemName: "arrow.down.to.line")
-                .font(.system(size: 50))
-                .foregroundColor(step.accentColor)
-                .offset(y: -10 + animationValue * 20)
-                .rotationEffect(.degrees(animationValue * 360))
-        }
-    }
-
-    var basalProfileAnimation: some View {
-        ZStack {
-            // Line graph representation
-            Path { path in
-                let width: CGFloat = 300
-                let height: CGFloat = 100
-
-                path.move(to: CGPoint(x: 0, y: height * 0.5))
-
-                for i in 0 ..< 8 {
-                    let x = width * CGFloat(i) / 7
-                    let y = height * (0.5 + (sin(Double(i) * .pi / 3) * 0.4))
-
-                    if i == 0 {
-                        path.move(to: CGPoint(x: x, y: y))
-                    } else {
-                        path.addLine(to: CGPoint(x: x, y: y))
-                    }
-                }
-            }
-            .trim(from: 0, to: animationValue)
-            .stroke(step.accentColor, style: StrokeStyle(lineWidth: 5, lineCap: .round, lineJoin: .round))
-            .frame(width: 300, height: 100)
-
-            // Clock symbols to represent time
-            HStack(spacing: 50) {
-                Image(systemName: "clock")
-                    .font(.system(size: 20))
-                    .foregroundColor(step.accentColor)
-                    .opacity(animationValue)
-
-                Image(systemName: "clock.fill")
-                    .font(.system(size: 20))
-                    .foregroundColor(step.accentColor)
-                    .opacity(animationValue)
-
-                Image(systemName: "clock")
-                    .font(.system(size: 20))
-                    .foregroundColor(step.accentColor)
-                    .opacity(animationValue)
-            }
-            .offset(y: 70)
-        }
-    }
-
-    var carbRatioAnimation: some View {
-        ZStack {
-            // Plate
-            Circle()
-                .fill(Color.gray.opacity(0.1))
-                .frame(width: 150)
-
-            // Food items
-            ForEach(0 ..< 5) { index in
-                Image(systemName: [
-                    "carrot.fill",
-                    "fork.knife",
-                    "takeoutbag.and.cup.and.straw.fill",
-                    "wallet.pass.fill",
-                    "cup.and.saucer.fill"
-                ][index % 5])
-                    .font(.system(size: 25))
-                    .foregroundColor(step.accentColor)
-                    .offset(
-                        x: cos(Double(index) * .pi * 2 / 5) * 50 * animationValue,
-                        y: sin(Double(index) * .pi * 2 / 5) * 50 * animationValue
-                    )
-                    .rotationEffect(.degrees(animationValue * 360))
-            }
-
-            // Insulin
-            Image(systemName: "drop.fill")
-                .font(.system(size: 40))
-                .foregroundColor(.blue)
-                .scaleEffect(0.8 + animationValue * 0.3)
-                .shadow(color: .blue.opacity(0.5), radius: 5, x: 0, y: 0)
-        }
-    }
-
-    var insulinSensitivityAnimation: some View {
-        ZStack {
-            // Glucose meter
-            RoundedRectangle(cornerRadius: 20)
-                .fill(Color.gray.opacity(0.1))
-                .frame(width: 120, height: 200)
-
-            // Display screen
-            RoundedRectangle(cornerRadius: 10)
-                .fill(Color.black.opacity(0.1))
-                .frame(width: 100, height: 60)
-                .offset(y: -60)
-
-            // Value on screen
-            Text("120")
-                .font(.system(size: 24, weight: .bold, design: .monospaced))
-                .foregroundColor(step.accentColor)
-                .offset(y: -60)
-                .opacity(animationValue)
-
-            // Insulin drop
-            Image(systemName: "drop.fill")
-                .font(.system(size: 30))
-                .foregroundColor(.blue)
-                .offset(y: 20)
-                .opacity(1)
-
-            // Arrow showing decrease
-            Image(systemName: "arrow.down")
-                .font(.system(size: 30))
-                .foregroundColor(step.accentColor)
-                .offset(y: 60)
-                .opacity(animationValue)
-                .scaleEffect(1.0 + animationValue * 0.5)
-
-            // Lower value
-            Text("80")
-                .font(.system(size: 24, weight: .bold, design: .monospaced))
-                .foregroundColor(step.accentColor)
-                .offset(y: 100)
-                .opacity(animationValue)
-        }
-    }
-
-    var completedAnimation: some View {
-        ZStack {
-            // Success checkmark
-            Circle()
-                .fill(step.accentColor.opacity(0.2))
-                .frame(width: 150)
-                .scaleEffect(animationValue)
-
-            Circle()
-                .stroke(step.accentColor, lineWidth: 5)
-                .frame(width: 150)
-                .scaleEffect(animationValue)
-
-            Image(systemName: "checkmark")
-                .font(.system(size: 80, weight: .bold))
-                .foregroundColor(step.accentColor)
-                .offset(y: animationValue * 5)
-                .scaleEffect(animationValue)
-
-            // Celebrate particles
-            ForEach(0 ..< 8) { index in
-                Image(systemName: "star.fill")
-                    .font(.system(size: 20))
-                    .foregroundColor(step.accentColor)
-                    .offset(
-                        x: cos(Double(index) * .pi / 4) * 100 * animationValue,
-                        y: sin(Double(index) * .pi / 4) * 100 * animationValue
-                    )
-                    .opacity(animationValue)
-                    .scaleEffect(animationValue)
-            }
-        }
-    }
-}
+///// A simple animated placeholder for each step
+// struct AnimationPlaceholder: View {
+//    let step: OnboardingStep
+//    @State private var animationValue: Double = 0
+//
+//    init(for step: OnboardingStep) {
+//        self.step = step
+//    }
+//
+//    var body: some View {
+//        VStack {
+//            Group {
+//                switch step {
+//                case .welcome:
+//                    welcomeAnimation
+//                case .glucoseTarget:
+//                    glucoseTargetAnimation
+//                case .basalProfile:
+//                    basalProfileAnimation
+//                case .carbRatio:
+//                    carbRatioAnimation
+//                case .insulinSensitivity:
+//                    insulinSensitivityAnimation
+//                case .completed:
+//                    completedAnimation
+//                }
+//            }
+//            .frame(height: 180)
+//        }
+//        .onAppear {
+//            withAnimation(Animation.easeInOut(duration: 2).repeatForever(autoreverses: true)) {
+//                animationValue = 1.0
+//            }
+//        }
+//    }
+//
+//    // Custom animated views for each step
+//    var welcomeAnimation: some View {
+//        ZStack {
+//            ForEach(0 ..< 5) { index in
+//                Image(systemName: "heart.fill")
+//                    .font(.system(size: 40))
+//                    .foregroundColor(step.accentColor.opacity(0.8 - Double(index) * 0.15))
+//                    .offset(x: CGFloat.random(in: -100 ... 100), y: CGFloat.random(in: -60 ... 60))
+//                    .scaleEffect(1.0 + animationValue * 0.3)
+//                    .rotationEffect(.degrees(animationValue * Double.random(in: -30 ... 30)))
+//            }
+//
+//            Image(systemName: "syringe.fill")
+//                .font(.system(size: 80))
+//                .foregroundColor(step.accentColor)
+//                .scaleEffect(1.0 + animationValue * 0.2)
+//                .shadow(color: step.accentColor.opacity(0.5), radius: 10 * animationValue, x: 0, y: 0)
+//        }
+//    }
+//
+//    var glucoseTargetAnimation: some View {
+//        ZStack {
+//            // Target rings
+//            ForEach(0 ..< 3) { index in
+//                Circle()
+//                    .stroke(step.accentColor.opacity(Double(3 - index) * 0.3), lineWidth: 8)
+//                    .frame(width: 120 + CGFloat(index * 40))
+//                    .scaleEffect(1.0 + animationValue * 0.05)
+//            }
+//
+//            // Arrow
+//            Image(systemName: "arrow.down.to.line")
+//                .font(.system(size: 50))
+//                .foregroundColor(step.accentColor)
+//                .offset(y: -10 + animationValue * 20)
+//                .rotationEffect(.degrees(animationValue * 360))
+//        }
+//    }
+//
+//    var basalProfileAnimation: some View {
+//        ZStack {
+//            // Line graph representation
+//            Path { path in
+//                let width: CGFloat = 300
+//                let height: CGFloat = 100
+//
+//                path.move(to: CGPoint(x: 0, y: height * 0.5))
+//
+//                for i in 0 ..< 8 {
+//                    let x = width * CGFloat(i) / 7
+//                    let y = height * (0.5 + (sin(Double(i) * .pi / 3) * 0.4))
+//
+//                    if i == 0 {
+//                        path.move(to: CGPoint(x: x, y: y))
+//                    } else {
+//                        path.addLine(to: CGPoint(x: x, y: y))
+//                    }
+//                }
+//            }
+//            .trim(from: 0, to: animationValue)
+//            .stroke(step.accentColor, style: StrokeStyle(lineWidth: 5, lineCap: .round, lineJoin: .round))
+//            .frame(width: 300, height: 100)
+//
+//            // Clock symbols to represent time
+//            HStack(spacing: 50) {
+//                Image(systemName: "clock")
+//                    .font(.system(size: 20))
+//                    .foregroundColor(step.accentColor)
+//                    .opacity(animationValue)
+//
+//                Image(systemName: "clock.fill")
+//                    .font(.system(size: 20))
+//                    .foregroundColor(step.accentColor)
+//                    .opacity(animationValue)
+//
+//                Image(systemName: "clock")
+//                    .font(.system(size: 20))
+//                    .foregroundColor(step.accentColor)
+//                    .opacity(animationValue)
+//            }
+//            .offset(y: 70)
+//        }
+//    }
+//
+//    var carbRatioAnimation: some View {
+//        ZStack {
+//            // Plate
+//            Circle()
+//                .fill(Color.gray.opacity(0.1))
+//                .frame(width: 150)
+//
+//            // Food items
+//            ForEach(0 ..< 5) { index in
+//                Image(systemName: [
+//                    "carrot.fill",
+//                    "fork.knife",
+//                    "takeoutbag.and.cup.and.straw.fill",
+//                    "wallet.pass.fill",
+//                    "cup.and.saucer.fill"
+//                ][index % 5])
+//                    .font(.system(size: 25))
+//                    .foregroundColor(step.accentColor)
+//                    .offset(
+//                        x: cos(Double(index) * .pi * 2 / 5) * 50 * animationValue,
+//                        y: sin(Double(index) * .pi * 2 / 5) * 50 * animationValue
+//                    )
+//                    .rotationEffect(.degrees(animationValue * 360))
+//            }
+//
+//            // Insulin
+//            Image(systemName: "drop.fill")
+//                .font(.system(size: 40))
+//                .foregroundColor(.blue)
+//                .scaleEffect(0.8 + animationValue * 0.3)
+//                .shadow(color: .blue.opacity(0.5), radius: 5, x: 0, y: 0)
+//        }
+//    }
+//
+//    var insulinSensitivityAnimation: some View {
+//        ZStack {
+//            // Glucose meter
+//            RoundedRectangle(cornerRadius: 20)
+//                .fill(Color.gray.opacity(0.1))
+//                .frame(width: 120, height: 200)
+//
+//            // Display screen
+//            RoundedRectangle(cornerRadius: 10)
+//                .fill(Color.black.opacity(0.1))
+//                .frame(width: 100, height: 60)
+//                .offset(y: -60)
+//
+//            // Value on screen
+//            Text("120")
+//                .font(.system(size: 24, weight: .bold, design: .monospaced))
+//                .foregroundColor(step.accentColor)
+//                .offset(y: -60)
+//                .opacity(animationValue)
+//
+//            // Insulin drop
+//            Image(systemName: "drop.fill")
+//                .font(.system(size: 30))
+//                .foregroundColor(.blue)
+//                .offset(y: 20)
+//                .opacity(1)
+//
+//            // Arrow showing decrease
+//            Image(systemName: "arrow.down")
+//                .font(.system(size: 30))
+//                .foregroundColor(step.accentColor)
+//                .offset(y: 60)
+//                .opacity(animationValue)
+//                .scaleEffect(1.0 + animationValue * 0.5)
+//
+//            // Lower value
+//            Text("80")
+//                .font(.system(size: 24, weight: .bold, design: .monospaced))
+//                .foregroundColor(step.accentColor)
+//                .offset(y: 100)
+//                .opacity(animationValue)
+//        }
+//    }
+//
+//    var completedAnimation: some View {
+//        ZStack {
+//            // Success checkmark
+//            Circle()
+//                .fill(step.accentColor.opacity(0.2))
+//                .frame(width: 150)
+//                .scaleEffect(animationValue)
+//
+//            Circle()
+//                .stroke(step.accentColor, lineWidth: 5)
+//                .frame(width: 150)
+//                .scaleEffect(animationValue)
+//
+//            Image(systemName: "checkmark")
+//                .font(.system(size: 80, weight: .bold))
+//                .foregroundColor(step.accentColor)
+//                .offset(y: animationValue * 5)
+//                .scaleEffect(animationValue)
+//
+//            // Celebrate particles
+//            ForEach(0 ..< 8) { index in
+//                Image(systemName: "star.fill")
+//                    .font(.system(size: 20))
+//                    .foregroundColor(step.accentColor)
+//                    .offset(
+//                        x: cos(Double(index) * .pi / 4) * 100 * animationValue,
+//                        y: sin(Double(index) * .pi / 4) * 100 * animationValue
+//                    )
+//                    .opacity(animationValue)
+//                    .scaleEffect(animationValue)
+//            }
+//        }
+//    }
+// }
 
 struct Onboarding_Preview: PreviewProvider {
     static var previews: some View {