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

Cleanup, adjust paddings, scroll to top on back/next tap

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

+ 8 - 4
Trio.xcodeproj/project.pbxproj

@@ -355,7 +355,7 @@
 		BD432CA12D2F4E3600D1EB79 /* WatchMessageKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD432CA02D2F4E3300D1EB79 /* WatchMessageKeys.swift */; };
 		BD432CA22D2F4E4000D1EB79 /* WatchMessageKeys.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD432CA02D2F4E3300D1EB79 /* WatchMessageKeys.swift */; };
 		BD47FD132D88AA700043966B /* OnboardingManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD47FD122D88AA6B0043966B /* OnboardingManager.swift */; };
-		BD47FD172D88AAF50043966B /* OnboardingStepViews.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD47FD162D88AAEF0043966B /* OnboardingStepViews.swift */; };
+		BD47FD172D88AAF50043966B /* CompletedStepView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD47FD162D88AAEF0043966B /* CompletedStepView.swift */; };
 		BD47FD192D88AAFE0043966B /* OnboardingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD47FD182D88AAF90043966B /* OnboardingView.swift */; };
 		BD47FD1B2D88AB4F0043966B /* OnboardingStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD47FD1A2D88AB4A0043966B /* OnboardingStateModel.swift */; };
 		BD47FDD72D8B64D20043966B /* CarbRatioStepView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD47FDD62D8B64CC0043966B /* CarbRatioStepView.swift */; };
@@ -639,6 +639,7 @@
 		DDEBB05C2D89E9050032305D /* TimeInRangeType.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDEBB05B2D89E9050032305D /* TimeInRangeType.swift */; };
 		DDF68FFC2D9ECF7F008BF16C /* OnboardingStateModel+Nightscout.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF68FFB2D9ECF77008BF16C /* OnboardingStateModel+Nightscout.swift */; };
 		DDF6902C2DA028D3008BF16C /* DiagnosticsStepView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF6902B2DA028D3008BF16C /* DiagnosticsStepView.swift */; };
+		DDF6905C2DA0AFC5008BF16C /* WelcomeStepView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF6905B2DA0AFC5008BF16C /* WelcomeStepView.swift */; };
 		DDF847DD2C5C28720049BB3B /* LiveActivitySettingsDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF847DC2C5C28720049BB3B /* LiveActivitySettingsDataFlow.swift */; };
 		DDF847DF2C5C28780049BB3B /* LiveActivitySettingsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF847DE2C5C28780049BB3B /* LiveActivitySettingsProvider.swift */; };
 		DDF847E12C5C287F0049BB3B /* LiveActivitySettingsStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDF847E02C5C287F0049BB3B /* LiveActivitySettingsStateModel.swift */; };
@@ -1134,7 +1135,7 @@
 		BD4064D02C4ED26900582F43 /* CoreDataObserver.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CoreDataObserver.swift; sourceTree = "<group>"; };
 		BD432CA02D2F4E3300D1EB79 /* WatchMessageKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchMessageKeys.swift; sourceTree = "<group>"; };
 		BD47FD122D88AA6B0043966B /* OnboardingManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingManager.swift; sourceTree = "<group>"; };
-		BD47FD162D88AAEF0043966B /* OnboardingStepViews.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingStepViews.swift; sourceTree = "<group>"; };
+		BD47FD162D88AAEF0043966B /* CompletedStepView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompletedStepView.swift; sourceTree = "<group>"; };
 		BD47FD182D88AAF90043966B /* OnboardingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingView.swift; sourceTree = "<group>"; };
 		BD47FD1A2D88AB4A0043966B /* OnboardingStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingStateModel.swift; sourceTree = "<group>"; };
 		BD47FDD62D8B64CC0043966B /* CarbRatioStepView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbRatioStepView.swift; sourceTree = "<group>"; };
@@ -1423,6 +1424,7 @@
 		DDEBB05B2D89E9050032305D /* TimeInRangeType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimeInRangeType.swift; sourceTree = "<group>"; };
 		DDF68FFB2D9ECF77008BF16C /* OnboardingStateModel+Nightscout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "OnboardingStateModel+Nightscout.swift"; sourceTree = "<group>"; };
 		DDF6902B2DA028D3008BF16C /* DiagnosticsStepView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DiagnosticsStepView.swift; sourceTree = "<group>"; };
+		DDF6905B2DA0AFC5008BF16C /* WelcomeStepView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WelcomeStepView.swift; sourceTree = "<group>"; };
 		DDF847DC2C5C28720049BB3B /* LiveActivitySettingsDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveActivitySettingsDataFlow.swift; sourceTree = "<group>"; };
 		DDF847DE2C5C28780049BB3B /* LiveActivitySettingsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveActivitySettingsProvider.swift; sourceTree = "<group>"; };
 		DDF847E02C5C287F0049BB3B /* LiveActivitySettingsStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveActivitySettingsStateModel.swift; sourceTree = "<group>"; };
@@ -2749,11 +2751,12 @@
 		BD47FDD52D8B64AE0043966B /* OnboardingSteps */ = {
 			isa = PBXGroup;
 			children = (
+				DDF6905B2DA0AFC5008BF16C /* WelcomeStepView.swift */,
 				DDF6902B2DA028D3008BF16C /* DiagnosticsStepView.swift */,
 				DD3F1F8E2D9E151200DCE7B3 /* Nightscout */,
 				DD3F1F842D9DD83B00DCE7B3 /* DeliveryLimitsStepView.swift */,
 				DD3F1F822D9DC78300DCE7B3 /* UnitSelectionStepView.swift */,
-				BD47FD162D88AAEF0043966B /* OnboardingStepViews.swift */,
+				BD47FD162D88AAEF0043966B /* CompletedStepView.swift */,
 				BD47FDDC2D8B65AD0043966B /* GlucoseTargetStepView.swift */,
 				BD47FDDA2D8B65960043966B /* BasalProfileStepView.swift */,
 				BD47FDD82D8B65730043966B /* InsulinSensitivityStepView.swift */,
@@ -4261,7 +4264,7 @@
 				CE7CA3542A064973004BE681 /* TempPresetsIntentRequest.swift in Sources */,
 				58A3D5442C96DE11003F90FC /* TempTargetStored+Helper.swift in Sources */,
 				DD6B7CB42C7B71F700B75029 /* ForecastDisplayType.swift in Sources */,
-				BD47FD172D88AAF50043966B /* OnboardingStepViews.swift in Sources */,
+				BD47FD172D88AAF50043966B /* CompletedStepView.swift in Sources */,
 				DDEBB05C2D89E9050032305D /* TimeInRangeType.swift in Sources */,
 				DD5DC9F32CF3D9DD00AB8703 /* AdjustmentsStateModel+TempTargets.swift in Sources */,
 				BD47FDDB2D8B659B0043966B /* BasalProfileStepView.swift in Sources */,
@@ -4308,6 +4311,7 @@
 				DD9ECB682CA99F4500AA7C45 /* TrioRemoteControl.swift in Sources */,
 				38569353270B5E350002C50D /* CGMRootView.swift in Sources */,
 				69A31254F2451C20361D172F /* TreatmentsStateModel.swift in Sources */,
+				DDF6905C2DA0AFC5008BF16C /* WelcomeStepView.swift in Sources */,
 				1967DFC029D053AC00759F30 /* IconSelection.swift in Sources */,
 				19D4E4EB29FC6A9F00351451 /* Charts.swift in Sources */,
 				BDC531162D10629000088832 /* ContactPicture.swift in Sources */,

+ 2 - 40
Trio/Sources/Modules/Onboarding/View/OnboardingSteps/OnboardingStepViews.swift

@@ -1,42 +1,5 @@
 import SwiftUI
 
-/// Welcome step view shown at the beginning of onboarding.
-struct WelcomeStepView: View {
-    var body: some View {
-        VStack(alignment: .center, spacing: 20) {
-            Image("trioCircledNoBackground")
-                .resizable()
-                .scaledToFit()
-                .frame(height: 100)
-                .padding()
-
-            Text("Hi there!")
-                .font(.title2)
-                .fontWeight(.bold)
-                .multilineTextAlignment(.center)
-
-            Text(
-                "Welcome to Trio - an automated insulin delivery system for iOS based on the OpenAPS algorithm with adaptations."
-            )
-            .multilineTextAlignment(.center)
-            .foregroundColor(.secondary)
-
-            Text(
-                "Trio is designed to help manage your diabetes efficiently. To get the most out of the app, we'll guide you through setting up some essential parameters."
-            )
-            .multilineTextAlignment(.center)
-            .foregroundColor(.secondary)
-
-            Text("Let's go through a few quick steps to ensure Trio works optimally for you.")
-                .multilineTextAlignment(.center)
-                .foregroundColor(.primary)
-                .bold()
-        }
-        .padding()
-        .frame(maxWidth: .infinity)
-    }
-}
-
 /// Completed step view shown at the end of onboarding.
 struct CompletedStepView: View {
     var body: some View {
@@ -66,10 +29,9 @@ struct CompletedStepView: View {
             .cornerRadius(12)
 
             Text("Remember, you can adjust these settings at any time in the app settings if needed.")
-                .font(.caption)
-                .foregroundColor(.secondary)
                 .multilineTextAlignment(.center)
-                .padding(.top)
+                .foregroundColor(.primary)
+                .bold()
         }
         .padding()
         .frame(maxWidth: .infinity)

+ 2 - 0
Trio/Sources/Modules/Onboarding/View/OnboardingSteps/DiagnosticsStepView.swift

@@ -7,6 +7,7 @@ struct DiagnosticsStepView: View {
         VStack(alignment: .leading, spacing: 20) {
             Text("If you prefer not to share this anonymized data, you can opt-out of data sharing.")
                 .font(.headline)
+                .padding(.horizontal)
 
             ForEach(DiagnostisSharingOption.allCases, id: \.self) { option in
                 Button(action: {
@@ -41,6 +42,7 @@ struct DiagnosticsStepView: View {
                     "Trio diagnostic data is sent to a Google Firebase Crashlytics project, which is securely maintained and accessed only by the Trio team."
                 )
             }
+            .padding(.horizontal)
             .font(.footnote)
             .foregroundStyle(Color.secondary)
         }

+ 3 - 4
Trio/Sources/Modules/Onboarding/View/OnboardingSteps/UnitSelectionStepView.swift

@@ -4,11 +4,10 @@ struct UnitSelectionStepView: View {
     @Bindable var state: Onboarding.StateModel
 
     var body: some View {
-        VStack(alignment: .leading, spacing: 8) {
+        VStack(alignment: .leading, spacing: 20) {
             Text("Please choose from the options below.")
                 .font(.headline)
-
-            Spacer(minLength: 20)
+                .padding(.horizontal)
 
             HStack {
                 Text("Glucose Units")
@@ -39,7 +38,7 @@ struct UnitSelectionStepView: View {
             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)
+            .padding(.horizontal)
             .font(.footnote)
             .foregroundStyle(Color.secondary)
         }

+ 38 - 0
Trio/Sources/Modules/Onboarding/View/OnboardingSteps/WelcomeStepView.swift

@@ -0,0 +1,38 @@
+import SwiftUI
+
+/// Welcome step view shown at the beginning of onboarding.
+struct WelcomeStepView: View {
+    var body: some View {
+        VStack(alignment: .center, spacing: 20) {
+            Image("trioCircledNoBackground")
+                .resizable()
+                .scaledToFit()
+                .frame(height: 100)
+                .padding()
+
+            Text("Hi there!")
+                .font(.title2)
+                .fontWeight(.bold)
+                .multilineTextAlignment(.center)
+
+            Text(
+                "Welcome to Trio - an automated insulin delivery system for iOS based on the OpenAPS algorithm with adaptations."
+            )
+            .multilineTextAlignment(.center)
+            .foregroundColor(.secondary)
+
+            Text(
+                "Trio is designed to help manage your diabetes efficiently. To get the most out of the app, we'll guide you through setting up some essential parameters."
+            )
+            .multilineTextAlignment(.center)
+            .foregroundColor(.secondary)
+
+            Text("Let's go through a few quick steps to ensure Trio works optimally for you.")
+                .multilineTextAlignment(.center)
+                .foregroundColor(.primary)
+                .bold()
+        }
+        .padding()
+        .frame(maxWidth: .infinity)
+    }
+}

+ 1 - 1
Trio/Sources/Modules/Onboarding/View/OnboardingView+Util.swift

@@ -1,7 +1,7 @@
 import SwiftUI
 
 /// Represents the different steps in the onboarding process.
-enum OnboardingStep: Int, CaseIterable, Identifiable {
+enum OnboardingStep: Int, CaseIterable, Identifiable, Equatable {
     case welcome
     case diagnostics
     case nightscout

+ 89 - 78
Trio/Sources/Modules/Onboarding/View/OnboardingView.swift

@@ -61,94 +61,104 @@ extension Onboarding {
                         .padding(.top)
 
                         // Step content
-                        ScrollView {
-                            VStack(alignment: .leading, spacing: 20) {
-                                // Header
-                                if currentStep != .welcome && currentStep != .completed {
-                                    HStack {
-                                        if currentStep == .nightscout {
-                                            Image(currentStep.iconName)
-                                                .resizable()
-                                                .scaledToFit()
-                                                .frame(width: 60, height: 60)
+                        ScrollViewReader { scrollProxy in
+                            ScrollView {
+                                VStack(alignment: .leading, spacing: 20) {
+                                    // Scroll position marker at top
+                                    Color.clear.frame(height: 0).id("top")
 
-                                        } else {
-                                            Image(systemName: currentStep.iconName)
-                                                .font(.system(size: 40))
-                                                .foregroundColor(currentStep.accentColor)
-                                                .frame(width: 60, height: 60)
-                                                .background(
-                                                    Circle()
-                                                        .fill(currentStep.accentColor.opacity(0.2))
-                                                )
-                                        }
+                                    // Header
+                                    if currentStep != .welcome && currentStep != .completed {
+                                        HStack {
+                                            if currentStep == .nightscout {
+                                                Image(currentStep.iconName)
+                                                    .resizable()
+                                                    .scaledToFit()
+                                                    .frame(width: 60, height: 60)
+
+                                            } else {
+                                                Image(systemName: currentStep.iconName)
+                                                    .font(.system(size: 40))
+                                                    .foregroundColor(currentStep.accentColor)
+                                                    .frame(width: 60, height: 60)
+                                                    .background(
+                                                        Circle()
+                                                            .fill(currentStep.accentColor.opacity(0.2))
+                                                    )
+                                            }
 
-                                        VStack(alignment: .leading) {
-                                            Text(currentStep.title)
-                                                .font(.largeTitle)
-                                                .fontWeight(.bold)
-                                                .foregroundColor(.primary)
+                                            VStack(alignment: .leading) {
+                                                Text(currentStep.title)
+                                                    .font(.largeTitle)
+                                                    .fontWeight(.bold)
+                                                    .foregroundColor(.primary)
 
-                                            Text(currentStep.description)
-                                                .font(.subheadline)
-                                                .foregroundColor(.secondary)
-                                                .fixedSize(horizontal: false, vertical: true)
+                                                Text(currentStep.description)
+                                                    .font(.subheadline)
+                                                    .foregroundColor(.secondary)
+                                                    .fixedSize(horizontal: false, vertical: true)
+                                            }
                                         }
+                                        .padding([.horizontal, .top])
                                     }
-                                    .padding([.horizontal, .top])
-                                }
 
-                                // Animation container (for steps that include animations)
-//                                AnimationPlaceholder(for: currentStep)
-//                                    .padding()
-//                                    .scaleEffect(animationScale)
-//                                    .opacity(animationOpacity)
-//                                    .onAppear {
-//                                        withAnimation(.easeInOut(duration: 0.7)) {
-//                                            animationOpacity = 1
-//                                            animationScale = 1.0
-//                                        }
-//                                        // Start pulse animation
-//                                        isAnimating = true
-//                                    }
+                                    // Animation container (for steps that include animations)
+                                    //                                AnimationPlaceholder(for: currentStep)
+                                    //                                    .padding()
+                                    //                                    .scaleEffect(animationScale)
+                                    //                                    .opacity(animationOpacity)
+                                    //                                    .onAppear {
+                                    //                                        withAnimation(.easeInOut(duration: 0.7)) {
+                                    //                                            animationOpacity = 1
+                                    //                                            animationScale = 1.0
+                                    //                                        }
+                                    //                                        // Start pulse animation
+                                    //                                        isAnimating = true
+                                    //                                    }
 
-                                // Step-specific content
-                                Group {
-                                    switch currentStep {
-                                    case .welcome:
-                                        WelcomeStepView()
-                                    case .diagnostics:
-                                        DiagnosticsStepView(state: state)
-                                    case .nightscout:
-                                        switch currentNightscoutSubstep {
-                                        case .setupSelection:
-                                            NightscoutStepView(state: state)
-                                        case .connectToNightscout:
-                                            NightscoutLoginStepView(state: state)
-                                        case .importFromNightscout:
-                                            NightscoutImportStepView(state: state)
+                                    // Step-specific content
+                                    Group {
+                                        switch currentStep {
+                                        case .welcome:
+                                            WelcomeStepView()
+                                        case .diagnostics:
+                                            DiagnosticsStepView(state: state)
+                                        case .nightscout:
+                                            switch currentNightscoutSubstep {
+                                            case .setupSelection:
+                                                NightscoutStepView(state: state)
+                                            case .connectToNightscout:
+                                                NightscoutLoginStepView(state: state)
+                                            case .importFromNightscout:
+                                                NightscoutImportStepView(state: state)
+                                            }
+                                        case .unitSelection:
+                                            UnitSelectionStepView(state: state)
+                                        case .glucoseTarget:
+                                            GlucoseTargetStepView(state: state)
+                                        case .basalProfile:
+                                            BasalProfileStepView(state: state)
+                                        case .carbRatio:
+                                            CarbRatioStepView(state: state)
+                                        case .insulinSensitivity:
+                                            InsulinSensitivityStepView(state: state)
+                                        case .deliveryLimits:
+                                            DeliveryLimitsStepView(state: state, substep: currentDeliverySubstep)
+                                        case .completed:
+                                            CompletedStepView()
                                         }
-                                    case .unitSelection:
-                                        UnitSelectionStepView(state: state)
-                                    case .glucoseTarget:
-                                        GlucoseTargetStepView(state: state)
-                                    case .basalProfile:
-                                        BasalProfileStepView(state: state)
-                                    case .carbRatio:
-                                        CarbRatioStepView(state: state)
-                                    case .insulinSensitivity:
-                                        InsulinSensitivityStepView(state: state)
-                                    case .deliveryLimits:
-                                        DeliveryLimitsStepView(state: state, substep: currentDeliverySubstep)
-                                    case .completed:
-                                        CompletedStepView()
                                     }
+                                    .transition(.asymmetric(insertion: .move(edge: .trailing), removal: .move(edge: .leading)))
+                                    .padding(.horizontal)
+                                    .id(currentStep.id) // Force view recreation when step changes
+                                }
+                                .padding(.bottom, 80) // Make room for buttons at bottom
+                            }
+                            .onChange(of: currentStep) { _, _ in
+                                withAnimation {
+                                    scrollProxy.scrollTo("top", anchor: .top)
                                 }
-                                .transition(.asymmetric(insertion: .move(edge: .trailing), removal: .move(edge: .leading)))
-                                .padding(.horizontal)
-                                .id(currentStep.id) // Force view recreation when step changes
                             }
-                            .padding(.bottom, 80) // Make room for buttons at bottom
                         }
 
                         Spacer()
@@ -161,7 +171,8 @@ extension Onboarding {
                                     withAnimation {
                                         if currentStep == .completed {
                                             currentStep = .deliveryLimits
-                                            currentDeliverySubstep = .maxCOB // ensure we land on the last substep visually
+                                            currentDeliverySubstep =
+                                                .minimumSafetyThreshold // ensure we land on the last substep visually
                                         } else if currentStep == .nightscout {
                                             if currentNightscoutSubstep == .setupSelection {
                                                 // First substep: go to previous main step