Procházet zdrojové kódy

Home: CGM sensor lifetime indicator (arc + tag) on glucose bobble

Deniz Cengiz před 3 týdny
rodič
revize
1a966cce6f

+ 121 - 118
Trio.xcodeproj/project.pbxproj

@@ -190,7 +190,6 @@
 		38E98A3725F5509500C0CED0 /* String+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E98A3625F5509500C0CED0 /* String+Extensions.swift */; };
 		38EA05DA261F6E7C0064E39B /* SimpleLogReporter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38EA05D9261F6E7C0064E39B /* SimpleLogReporter.swift */; };
 		38EA0600262091870064E39B /* BolusProgressViewStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38EA05FF262091870064E39B /* BolusProgressViewStyle.swift */; };
-		DDB0BBA02026050100000001 /* BolusProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB0BBA02026050100000002 /* BolusProgressBar.swift */; };
 		38F37828261260DC009DB701 /* Color+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38F37827261260DC009DB701 /* Color+Extensions.swift */; };
 		38F3B2EF25ED8E2A005C48AA /* TempTargetsStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38F3B2EE25ED8E2A005C48AA /* TempTargetsStorage.swift */; };
 		38FCF3D625E8FDF40078B0D1 /* MD5.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38FCF3D525E8FDF40078B0D1 /* MD5.swift */; };
@@ -254,11 +253,11 @@
 		3BD9687C2D8DDD4600899469 /* SlideButton in Frameworks */ = {isa = PBXBuildFile; productRef = 3BD9687B2D8DDD4600899469 /* SlideButton */; };
 		3BD9687F2D8DDD8800899469 /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 3BD9687E2D8DDD8800899469 /* CryptoSwift */; };
 		3BF85FE32E427312000D7351 /* IOBService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BF85FE12E427312000D7351 /* IOBService.swift */; };
-		B015AFE32E500000000D7351 /* BolusSafetyValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B015AFE12E500000000D7351 /* BolusSafetyValidator.swift */; };
 		3E28F2AB2EB5337F00FB9EEB /* ConnectIQ in Frameworks */ = {isa = PBXBuildFile; productRef = 3E28F2AA2EB5337F00FB9EEB /* ConnectIQ */; };
 		3E54EF2C2E476DA40006F54D /* MedtrumKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3E54EF2B2E476DA40006F54D /* MedtrumKit.framework */; };
 		3E54EF2D2E476DA40006F54D /* MedtrumKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3E54EF2B2E476DA40006F54D /* MedtrumKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		3E62C7822F54CC1B00433237 /* BolusDisplayThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E62C7812F54CC1600433237 /* BolusDisplayThreshold.swift */; };
+		41740E936552456AAC0EDAC3 /* SettingsSearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3919BBB515547118D684CA2 /* SettingsSearchTests.swift */; };
 		45252C95D220E796FDB3B022 /* ConfigEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */; };
 		45717281F743594AA9D87191 /* ConfigEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920DDB21E5D0EB813197500D /* ConfigEditorRootView.swift */; };
 		49090A8D2E9FE8D200D0F5DB /* GarminWatchSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 49090A8C2E9FE8D200D0F5DB /* GarminWatchSettings.swift */; };
@@ -341,18 +340,37 @@
 		9702FF92A09C53942F20D7EA /* TargetsEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4DD795BA46B193644D48138C /* TargetsEditorRootView.swift */; };
 		9825E5E923F0B8FA80C8C7C7 /* NightscoutConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = A0A48AE3AC813A49A517846A /* NightscoutConfigStateModel.swift */; };
 		98641AF4F92123DA668AB931 /* CarbRatioEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D0BDC6993C1087310EDFC428 /* CarbRatioEditorRootView.swift */; };
-		41740E936552456AAC0EDAC3 /* SettingsSearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3919BBB515547118D684CA2 /* SettingsSearchTests.swift */; };
 		A33352ED40476125EBAC6EE0 /* CarbRatioEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E22146D3DF4853786C78132 /* CarbRatioEditorDataFlow.swift */; };
+		AC19EF2C94084B5BA0175D1D /* SettingsSearchHighlight.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B83503461B4F8D97B30115 /* SettingsSearchHighlight.swift */; };
 		AD3D2CD42CD01B9EB8F26522 /* PumpConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF65DA88F972B56090AD6AC3 /* PumpConfigDataFlow.swift */; };
+		B015AFE32E500000000D7351 /* BolusSafetyValidator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B015AFE12E500000000D7351 /* BolusSafetyValidator.swift */; };
+		B015AFE52E500000000D7351 /* BolusSafetyValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B015AFE42E500000000D7351 /* BolusSafetyValidatorTests.swift */; };
 		B6E925132EB3932A0076D719 /* OmnipodKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6E925122EB3932A0076D719 /* OmnipodKit.framework */; };
 		B6E925142EB3932A0076D719 /* OmnipodKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B6E925122EB3932A0076D719 /* OmnipodKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		B7C465E9472624D8A2BE2A6A /* (null) in Sources */ = {isa = PBXBuildFile; };
 		B958F1B72BA0711600484851 /* MKRingProgressView in Frameworks */ = {isa = PBXBuildFile; productRef = B958F1B62BA0711600484851 /* MKRingProgressView */; };
 		BA00D96F7B2FF169A06FB530 /* CGMSettingsStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C018D1680307A31C9ED7120 /* CGMSettingsStateModel.swift */; };
+		BB5227A51D9D4377A1A70BA6 /* TempTargetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8F3B0E159844FD8746DFC0 /* TempTargetData.swift */; };
 		BD04ECCE2D29952A008C5FEB /* BolusProgressOverlay.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD04ECCD2D299522008C5FEB /* BolusProgressOverlay.swift */; };
 		BD0B2EF32C5998E600B3298F /* MealPresetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD0B2EF22C5998E600B3298F /* MealPresetView.swift */; };
 		BD10516D2DA986E1007C6D89 /* PulsingLogoAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD10516C2DA986DC007C6D89 /* PulsingLogoAnimation.swift */; };
+		BD11C001000000000000C001 /* CGMSensorDisplayState.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD11C000000000000000C001 /* CGMSensorDisplayState.swift */; };
+		BD11C001000000000000C003 /* SensorLifecycleArcView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD11C000000000000000C003 /* SensorLifecycleArcView.swift */; };
+		BD11C001000000000000C004 /* SensorStatusTagView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD11C000000000000000C004 /* SensorStatusTagView.swift */; };
 		BD1661312B82ADAB00256551 /* CustomProgressView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD1661302B82ADAB00256551 /* CustomProgressView.swift */; };
+		BD175EBE0000100000000001 /* HistoryDataFlow+Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000001 /* HistoryDataFlow+Models.swift */; };
+		BD175EBE0000100000000002 /* HistoryDeletionTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000002 /* HistoryDeletionTarget.swift */; };
+		BD175EBE0000100000000003 /* HistoryStateModel+Glucose.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000003 /* HistoryStateModel+Glucose.swift */; };
+		BD175EBE0000100000000004 /* HistoryStateModel+Carbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000004 /* HistoryStateModel+Carbs.swift */; };
+		BD175EBE0000100000000005 /* HistoryStateModel+Insulin.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000005 /* HistoryStateModel+Insulin.swift */; };
+		BD175EBE0000100000000006 /* HistoryStateModel+CarbEditing.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000006 /* HistoryStateModel+CarbEditing.swift */; };
+		BD175EBE0000100000000007 /* HistoryRootView+Treatments.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000007 /* HistoryRootView+Treatments.swift */; };
+		BD175EBE0000100000000008 /* HistoryRootView+Meals.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000008 /* HistoryRootView+Meals.swift */; };
+		BD175EBE0000100000000009 /* HistoryRootView+Glucose.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000009 /* HistoryRootView+Glucose.swift */; };
+		BD175EBE000010000000000A /* HistoryRootView+Adjustments.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE000010000000000A /* HistoryRootView+Adjustments.swift */; };
+		BD175EBE000010000000000B /* HistoryRootView+Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE000010000000000B /* HistoryRootView+Filters.swift */; };
+		BD175EBE000010000000000C /* HistoryRootView+AddGlucose.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE000010000000000C /* HistoryRootView+AddGlucose.swift */; };
+		BD175EBE000010000000000D /* HistoryRootView+Confirmations.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE000010000000000D /* HistoryRootView+Confirmations.swift */; };
 		BD249D862D42FBEC00412DEB /* GlucoseMetricsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249D852D42FBE600412DEB /* GlucoseMetricsView.swift */; };
 		BD249D882D42FC0000412DEB /* BolusStatsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249D872D42FBFB00412DEB /* BolusStatsView.swift */; };
 		BD249D8A2D42FC1200412DEB /* GlucosePercentileChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD249D892D42FC0E00412DEB /* GlucosePercentileChart.swift */; };
@@ -412,7 +430,6 @@
 		BD8FC0592D66189700B95AED /* TestAssembly.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD8FC0582D66189700B95AED /* TestAssembly.swift */; };
 		BD8FC05B2D6618AF00B95AED /* DeterminationStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD8FC05A2D6618AF00B95AED /* DeterminationStorageTests.swift */; };
 		BD8FC05E2D6618CE00B95AED /* BolusCalculatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD8FC05D2D6618CE00B95AED /* BolusCalculatorTests.swift */; };
-		B015AFE52E500000000D7351 /* BolusSafetyValidatorTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B015AFE42E500000000D7351 /* BolusSafetyValidatorTests.swift */; };
 		BD8FC0602D6619DB00B95AED /* CarbsStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD8FC05F2D6619DB00B95AED /* CarbsStorageTests.swift */; };
 		BD8FC0622D6619E600B95AED /* OverrideStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD8FC0612D6619E600B95AED /* OverrideStorageTests.swift */; };
 		BD8FC0642D6619EF00B95AED /* TempTargetStorageTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD8FC0632D6619EF00B95AED /* TempTargetStorageTests.swift */; };
@@ -431,7 +448,6 @@
 		BDB3C1192C03DD1000CEEAA1 /* UserDefaultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDB3C1182C03DD1000CEEAA1 /* UserDefaultsExtension.swift */; };
 		BDB899882C564509006F3298 /* ForecastChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDB899872C564509006F3298 /* ForecastChart.swift */; };
 		BDB8998A2C565D0C006F3298 /* CarbsGlucose+helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDB899892C565D0B006F3298 /* CarbsGlucose+helper.swift */; };
-		BB5227A51D9D4377A1A70BA6 /* TempTargetData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4B8F3B0E159844FD8746DFC0 /* TempTargetData.swift */; };
 		BDBAACFA2C2D439700370AAE /* OverrideData.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDBAACF92C2D439700370AAE /* OverrideData.swift */; };
 		BDC2EA452C3043B000E5BBD0 /* OverrideStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDC2EA442C3043B000E5BBD0 /* OverrideStorage.swift */; };
 		BDC2EA472C3045AD00E5BBD0 /* Override.swift in Sources */ = {isa = PBXBuildFile; fileRef = BDC2EA462C3045AD00E5BBD0 /* Override.swift */; };
@@ -547,7 +563,6 @@
 		DD1745242C55526000211FAC /* SMBSettingsStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745232C55526000211FAC /* SMBSettingsStateModel.swift */; };
 		DD1745262C55526F00211FAC /* SMBSettingsRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745252C55526F00211FAC /* SMBSettingsRootView.swift */; };
 		DD1745292C55642100211FAC /* SettingInputSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD1745282C55642100211FAC /* SettingInputSection.swift */; };
-		AC19EF2C94084B5BA0175D1D /* SettingsSearchHighlight.swift in Sources */ = {isa = PBXBuildFile; fileRef = 48B83503461B4F8D97B30115 /* SettingsSearchHighlight.swift */; };
 		DD17452B2C556E8100211FAC /* SettingInputHintView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD17452A2C556E8100211FAC /* SettingInputHintView.swift */; };
 		DD17452E2C55AE4800211FAC /* TargetBehavoirDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD17452D2C55AE4800211FAC /* TargetBehavoirDataFlow.swift */; };
 		DD1745302C55AE5300211FAC /* TargetBehaviorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD17452F2C55AE5300211FAC /* TargetBehaviorProvider.swift */; };
@@ -618,16 +633,16 @@
 		DD6D67E42C9C253500660C9B /* ColorSchemeOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6D67E32C9C253500660C9B /* ColorSchemeOption.swift */; };
 		DD6F63CC2D27F615007D94CF /* TreatmentMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD6F63CB2D27F606007D94CF /* TreatmentMenuView.swift */; };
 		DD73FA0F2D74F58E00D19D1E /* BackgroundTask+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD73FA0E2D74F57300D19D1E /* BackgroundTask+Helper.swift */; };
-		DD8262CB2D289297009F6F62 /* BolusConfirmationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8262CA2D289297009F6F62 /* BolusConfirmationView.swift */; };
-		DD82D4B82DCAB2BA00BAFC77 /* PropertyPersistentFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD82D4B72DCAB2BA00BAFC77 /* PropertyPersistentFlags.swift */; };
 		DD7E1E300000000000000002 /* TelemetryClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7E1E300000000000000001 /* TelemetryClient.swift */; };
-		DD7E1E300000000000000014 /* TelemetryAttestor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7E1E300000000000000013 /* TelemetryAttestor.swift */; };
 		DD7E1E300000000000000004 /* TelemetryPreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7E1E300000000000000003 /* TelemetryPreviewView.swift */; };
 		DD7E1E300000000000000006 /* TelemetryPrivacyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7E1E300000000000000005 /* TelemetryPrivacyView.swift */; };
 		DD7E1E300000000000000008 /* TelemetryMigrationSheetView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7E1E300000000000000007 /* TelemetryMigrationSheetView.swift */; };
 		DD7E1E30000000000000000E /* TelemetryDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7E1E30000000000000000D /* TelemetryDataFlow.swift */; };
 		DD7E1E300000000000000010 /* TelemetryProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7E1E30000000000000000F /* TelemetryProvider.swift */; };
 		DD7E1E300000000000000012 /* TelemetryStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7E1E300000000000000011 /* TelemetryStateModel.swift */; };
+		DD7E1E300000000000000014 /* TelemetryAttestor.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD7E1E300000000000000013 /* TelemetryAttestor.swift */; };
+		DD8262CB2D289297009F6F62 /* BolusConfirmationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD8262CA2D289297009F6F62 /* BolusConfirmationView.swift */; };
+		DD82D4B82DCAB2BA00BAFC77 /* PropertyPersistentFlags.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD82D4B72DCAB2BA00BAFC77 /* PropertyPersistentFlags.swift */; };
 		DD868FD82E381A54005D3308 /* APNSJWTClaims.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD868FD72E381A54005D3308 /* APNSJWTClaims.swift */; };
 		DD88C8E22C50420800F2D558 /* DefinitionRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD88C8E12C50420800F2D558 /* DefinitionRow.swift */; };
 		DD906BF42EA6AA0100262772 /* NightscoutUploadPipeline.swift in Sources */ = {isa = PBXBuildFile; fileRef = DD906BF32EA6AA0100262772 /* NightscoutUploadPipeline.swift */; };
@@ -650,6 +665,7 @@
 		DDA9AC092D672CF100E6F1A9 /* AppVersionChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDA9AC082D672CEB00E6F1A9 /* AppVersionChecker.swift */; };
 		DDAA29832D2D1D93006546A1 /* AdjustmentsRootView+Overrides.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAA29822D2D1D7B006546A1 /* AdjustmentsRootView+Overrides.swift */; };
 		DDAA29852D2D1D9E006546A1 /* AdjustmentsRootView+TempTargets.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDAA29842D2D1D98006546A1 /* AdjustmentsRootView+TempTargets.swift */; };
+		DDB0BBA02026050100000001 /* BolusProgressBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB0BBA02026050100000002 /* BolusProgressBar.swift */; };
 		DDB0E3742DB1BAC1004B826F /* LogoBurstSplash.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB0E3732DB1BAC1004B826F /* LogoBurstSplash.swift */; };
 		DDB37CC52D05048F00D99BF4 /* ContactImageStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB37CC42D05048F00D99BF4 /* ContactImageStorage.swift */; };
 		DDB37CC72D05127500D99BF4 /* FontExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = DDB37CC62D05127500D99BF4 /* FontExtensions.swift */; };
@@ -754,19 +770,6 @@
 		FE41E4D629463EE20047FD55 /* NightscoutPreferences.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE41E4D529463EE20047FD55 /* NightscoutPreferences.swift */; };
 		FE66D16B291F74F8005D6F77 /* Bundle+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE66D16A291F74F8005D6F77 /* Bundle+Extensions.swift */; };
 		FEFFA7A22929FE49007B8193 /* UIDevice+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEFFA7A12929FE49007B8193 /* UIDevice+Extensions.swift */; };
-		BD175EBE0000100000000001 /* HistoryDataFlow+Models.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000001 /* HistoryDataFlow+Models.swift */; };
-		BD175EBE0000100000000002 /* HistoryDeletionTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000002 /* HistoryDeletionTarget.swift */; };
-		BD175EBE0000100000000003 /* HistoryStateModel+Glucose.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000003 /* HistoryStateModel+Glucose.swift */; };
-		BD175EBE0000100000000004 /* HistoryStateModel+Carbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000004 /* HistoryStateModel+Carbs.swift */; };
-		BD175EBE0000100000000005 /* HistoryStateModel+Insulin.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000005 /* HistoryStateModel+Insulin.swift */; };
-		BD175EBE0000100000000006 /* HistoryStateModel+CarbEditing.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000006 /* HistoryStateModel+CarbEditing.swift */; };
-		BD175EBE0000100000000007 /* HistoryRootView+Treatments.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000007 /* HistoryRootView+Treatments.swift */; };
-		BD175EBE0000100000000008 /* HistoryRootView+Meals.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000008 /* HistoryRootView+Meals.swift */; };
-		BD175EBE0000100000000009 /* HistoryRootView+Glucose.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE0000100000000009 /* HistoryRootView+Glucose.swift */; };
-		BD175EBE000010000000000A /* HistoryRootView+Adjustments.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE000010000000000A /* HistoryRootView+Adjustments.swift */; };
-		BD175EBE000010000000000B /* HistoryRootView+Filters.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE000010000000000B /* HistoryRootView+Filters.swift */; };
-		BD175EBE000010000000000C /* HistoryRootView+AddGlucose.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE000010000000000C /* HistoryRootView+AddGlucose.swift */; };
-		BD175EBE000010000000000D /* HistoryRootView+Confirmations.swift in Sources */ = {isa = PBXBuildFile; fileRef = BD175EFE000010000000000D /* HistoryRootView+Confirmations.swift */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
@@ -1070,7 +1073,6 @@
 		38E98A3625F5509500C0CED0 /* String+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "String+Extensions.swift"; sourceTree = "<group>"; };
 		38EA05D9261F6E7C0064E39B /* SimpleLogReporter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SimpleLogReporter.swift; sourceTree = "<group>"; };
 		38EA05FF262091870064E39B /* BolusProgressViewStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusProgressViewStyle.swift; sourceTree = "<group>"; };
-		DDB0BBA02026050100000002 /* BolusProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusProgressBar.swift; sourceTree = "<group>"; };
 		38F37827261260DC009DB701 /* Color+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Extensions.swift"; sourceTree = "<group>"; };
 		38F3783A2613555C009DB701 /* Config.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Config.xcconfig; sourceTree = "<group>"; };
 		38F3B2EE25ED8E2A005C48AA /* TempTargetsStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TempTargetsStorage.swift; sourceTree = "<group>"; };
@@ -1118,13 +1120,13 @@
 		3BDEA2DC60EDE0A3CA54DC73 /* TargetsEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetsEditorProvider.swift; sourceTree = "<group>"; };
 		3BF768BD6264FF7D71D66767 /* NightscoutConfigProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NightscoutConfigProvider.swift; sourceTree = "<group>"; };
 		3BF85FE12E427312000D7351 /* IOBService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IOBService.swift; sourceTree = "<group>"; };
-		B015AFE12E500000000D7351 /* BolusSafetyValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusSafetyValidator.swift; sourceTree = "<group>"; };
 		3E54EF2B2E476DA40006F54D /* MedtrumKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MedtrumKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		3E62C7812F54CC1600433237 /* BolusDisplayThreshold.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusDisplayThreshold.swift; sourceTree = "<group>"; };
 		3F60E97100041040446F44E7 /* PumpConfigStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PumpConfigStateModel.swift; sourceTree = "<group>"; };
 		3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorDataFlow.swift; sourceTree = "<group>"; };
 		42369F66CF91F30624C0B3A6 /* BasalProfileEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorProvider.swift; sourceTree = "<group>"; };
 		44080E4709E3AE4B73054563 /* ConfigEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ConfigEditorProvider.swift; sourceTree = "<group>"; };
+		48B83503461B4F8D97B30115 /* SettingsSearchHighlight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSearchHighlight.swift; sourceTree = "<group>"; };
 		49090A8C2E9FE8D200D0F5DB /* GarminWatchSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GarminWatchSettings.swift; sourceTree = "<group>"; };
 		491D6FB92D56741C00C49F67 /* TempTargetRunStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetRunStored+CoreDataClass.swift"; sourceTree = "<group>"; };
 		491D6FBA2D56741C00C49F67 /* TempTargetRunStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "TempTargetRunStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
@@ -1134,6 +1136,7 @@
 		4984D1D32EA2939E00263E83 /* WatchConfigGarminAppConfigView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchConfigGarminAppConfigView.swift; sourceTree = "<group>"; };
 		49B9B57E2D5768D2009C6B59 /* AdjustmentStored+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AdjustmentStored+Helper.swift"; sourceTree = "<group>"; };
 		49C782A62F73D9870062B0DD /* AlertEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlertEntry.swift; sourceTree = "<group>"; };
+		4B8F3B0E159844FD8746DFC0 /* TempTargetData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TempTargetData.swift; sourceTree = "<group>"; };
 		4DD795BA46B193644D48138C /* TargetsEditorRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetsEditorRootView.swift; sourceTree = "<group>"; };
 		505E09DC17A0C3D0AF4B66FE /* ISFEditorStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ISFEditorStateModel.swift; sourceTree = "<group>"; };
 		581516A32BCED84A00BF67D7 /* DebuggingIdentifiers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DebuggingIdentifiers.swift; sourceTree = "<group>"; };
@@ -1207,6 +1210,9 @@
 		A8630D58BDAD6D9C650B9B39 /* PumpConfigProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PumpConfigProvider.swift; sourceTree = "<group>"; };
 		AAFF91130F2FCCC7EBBA11AD /* BasalProfileEditorStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorStateModel.swift; sourceTree = "<group>"; };
 		AF65DA88F972B56090AD6AC3 /* PumpConfigDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PumpConfigDataFlow.swift; sourceTree = "<group>"; };
+		B015AFE12E500000000D7351 /* BolusSafetyValidator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusSafetyValidator.swift; sourceTree = "<group>"; };
+		B015AFE42E500000000D7351 /* BolusSafetyValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusSafetyValidatorTests.swift; sourceTree = "<group>"; };
+		B3919BBB515547118D684CA2 /* SettingsSearchTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SettingsSearchTests.swift; sourceTree = "<group>"; };
 		B5822B15939E719628E9FF7C /* SnoozeRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SnoozeRootView.swift; sourceTree = "<group>"; };
 		B6E925122EB3932A0076D719 /* OmnipodKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = OmnipodKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		B9B5C0607505A38F256BF99A /* CGMSettingsDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CGMSettingsDataFlow.swift; sourceTree = "<group>"; };
@@ -1214,7 +1220,23 @@
 		BD04ECCD2D299522008C5FEB /* BolusProgressOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusProgressOverlay.swift; sourceTree = "<group>"; };
 		BD0B2EF22C5998E600B3298F /* MealPresetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MealPresetView.swift; sourceTree = "<group>"; };
 		BD10516C2DA986DC007C6D89 /* PulsingLogoAnimation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PulsingLogoAnimation.swift; sourceTree = "<group>"; };
+		BD11C000000000000000C001 /* CGMSensorDisplayState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGMSensorDisplayState.swift; sourceTree = "<group>"; };
+		BD11C000000000000000C003 /* SensorLifecycleArcView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorLifecycleArcView.swift; sourceTree = "<group>"; };
+		BD11C000000000000000C004 /* SensorStatusTagView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorStatusTagView.swift; sourceTree = "<group>"; };
 		BD1661302B82ADAB00256551 /* CustomProgressView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CustomProgressView.swift; sourceTree = "<group>"; };
+		BD175EFE0000100000000001 /* HistoryDataFlow+Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryDataFlow+Models.swift"; sourceTree = "<group>"; };
+		BD175EFE0000100000000002 /* HistoryDeletionTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryDeletionTarget.swift; sourceTree = "<group>"; };
+		BD175EFE0000100000000003 /* HistoryStateModel+Glucose.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryStateModel+Glucose.swift"; sourceTree = "<group>"; };
+		BD175EFE0000100000000004 /* HistoryStateModel+Carbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryStateModel+Carbs.swift"; sourceTree = "<group>"; };
+		BD175EFE0000100000000005 /* HistoryStateModel+Insulin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryStateModel+Insulin.swift"; sourceTree = "<group>"; };
+		BD175EFE0000100000000006 /* HistoryStateModel+CarbEditing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryStateModel+CarbEditing.swift"; sourceTree = "<group>"; };
+		BD175EFE0000100000000007 /* HistoryRootView+Treatments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryRootView+Treatments.swift"; sourceTree = "<group>"; };
+		BD175EFE0000100000000008 /* HistoryRootView+Meals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryRootView+Meals.swift"; sourceTree = "<group>"; };
+		BD175EFE0000100000000009 /* HistoryRootView+Glucose.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryRootView+Glucose.swift"; sourceTree = "<group>"; };
+		BD175EFE000010000000000A /* HistoryRootView+Adjustments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryRootView+Adjustments.swift"; sourceTree = "<group>"; };
+		BD175EFE000010000000000B /* HistoryRootView+Filters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryRootView+Filters.swift"; sourceTree = "<group>"; };
+		BD175EFE000010000000000C /* HistoryRootView+AddGlucose.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryRootView+AddGlucose.swift"; sourceTree = "<group>"; };
+		BD175EFE000010000000000D /* HistoryRootView+Confirmations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryRootView+Confirmations.swift"; sourceTree = "<group>"; };
 		BD1CF8B72C1A4A8400CB930A /* ConfigOverride.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = ConfigOverride.xcconfig; sourceTree = "<group>"; };
 		BD249D852D42FBE600412DEB /* GlucoseMetricsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseMetricsView.swift; sourceTree = "<group>"; };
 		BD249D872D42FBFB00412DEB /* BolusStatsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusStatsView.swift; sourceTree = "<group>"; };
@@ -1269,7 +1291,6 @@
 		BD8FC0582D66189700B95AED /* TestAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TestAssembly.swift; sourceTree = "<group>"; };
 		BD8FC05A2D6618AF00B95AED /* DeterminationStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeterminationStorageTests.swift; sourceTree = "<group>"; };
 		BD8FC05D2D6618CE00B95AED /* BolusCalculatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusCalculatorTests.swift; sourceTree = "<group>"; };
-		B015AFE42E500000000D7351 /* BolusSafetyValidatorTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusSafetyValidatorTests.swift; sourceTree = "<group>"; };
 		BD8FC05F2D6619DB00B95AED /* CarbsStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbsStorageTests.swift; sourceTree = "<group>"; };
 		BD8FC0612D6619E600B95AED /* OverrideStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideStorageTests.swift; sourceTree = "<group>"; };
 		BD8FC0632D6619EF00B95AED /* TempTargetStorageTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TempTargetStorageTests.swift; sourceTree = "<group>"; };
@@ -1288,7 +1309,6 @@
 		BDB3C1182C03DD1000CEEAA1 /* UserDefaultsExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsExtension.swift; sourceTree = "<group>"; };
 		BDB899872C564509006F3298 /* ForecastChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ForecastChart.swift; sourceTree = "<group>"; };
 		BDB899892C565D0B006F3298 /* CarbsGlucose+helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CarbsGlucose+helper.swift"; sourceTree = "<group>"; };
-		4B8F3B0E159844FD8746DFC0 /* TempTargetData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TempTargetData.swift; sourceTree = "<group>"; };
 		BDBAACF92C2D439700370AAE /* OverrideData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideData.swift; sourceTree = "<group>"; };
 		BDC2EA442C3043B000E5BBD0 /* OverrideStorage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideStorage.swift; sourceTree = "<group>"; };
 		BDC2EA462C3045AD00E5BBD0 /* Override.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Override.swift; sourceTree = "<group>"; };
@@ -1411,7 +1431,6 @@
 		DD1745232C55526000211FAC /* SMBSettingsStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMBSettingsStateModel.swift; sourceTree = "<group>"; };
 		DD1745252C55526F00211FAC /* SMBSettingsRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SMBSettingsRootView.swift; sourceTree = "<group>"; };
 		DD1745282C55642100211FAC /* SettingInputSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingInputSection.swift; sourceTree = "<group>"; };
-		48B83503461B4F8D97B30115 /* SettingsSearchHighlight.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSearchHighlight.swift; sourceTree = "<group>"; };
 		DD17452A2C556E8100211FAC /* SettingInputHintView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingInputHintView.swift; sourceTree = "<group>"; };
 		DD17452D2C55AE4800211FAC /* TargetBehavoirDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetBehavoirDataFlow.swift; sourceTree = "<group>"; };
 		DD17452F2C55AE5300211FAC /* TargetBehaviorProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TargetBehaviorProvider.swift; sourceTree = "<group>"; };
@@ -1478,16 +1497,16 @@
 		DD6D67E32C9C253500660C9B /* ColorSchemeOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorSchemeOption.swift; sourceTree = "<group>"; };
 		DD6F63CB2D27F606007D94CF /* TreatmentMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TreatmentMenuView.swift; sourceTree = "<group>"; };
 		DD73FA0E2D74F57300D19D1E /* BackgroundTask+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BackgroundTask+Helper.swift"; sourceTree = "<group>"; };
-		DD8262CA2D289297009F6F62 /* BolusConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusConfirmationView.swift; sourceTree = "<group>"; };
-		DD82D4B72DCAB2BA00BAFC77 /* PropertyPersistentFlags.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PropertyPersistentFlags.swift; sourceTree = "<group>"; };
 		DD7E1E300000000000000001 /* TelemetryClient.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryClient.swift; sourceTree = "<group>"; };
-		DD7E1E300000000000000013 /* TelemetryAttestor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryAttestor.swift; sourceTree = "<group>"; };
 		DD7E1E300000000000000003 /* TelemetryPreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryPreviewView.swift; sourceTree = "<group>"; };
 		DD7E1E300000000000000005 /* TelemetryPrivacyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryPrivacyView.swift; sourceTree = "<group>"; };
 		DD7E1E300000000000000007 /* TelemetryMigrationSheetView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryMigrationSheetView.swift; sourceTree = "<group>"; };
 		DD7E1E30000000000000000D /* TelemetryDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryDataFlow.swift; sourceTree = "<group>"; };
 		DD7E1E30000000000000000F /* TelemetryProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryProvider.swift; sourceTree = "<group>"; };
 		DD7E1E300000000000000011 /* TelemetryStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryStateModel.swift; sourceTree = "<group>"; };
+		DD7E1E300000000000000013 /* TelemetryAttestor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TelemetryAttestor.swift; sourceTree = "<group>"; };
+		DD8262CA2D289297009F6F62 /* BolusConfirmationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusConfirmationView.swift; sourceTree = "<group>"; };
+		DD82D4B72DCAB2BA00BAFC77 /* PropertyPersistentFlags.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PropertyPersistentFlags.swift; sourceTree = "<group>"; };
 		DD868FD72E381A54005D3308 /* APNSJWTClaims.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APNSJWTClaims.swift; sourceTree = "<group>"; };
 		DD88C8E12C50420800F2D558 /* DefinitionRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefinitionRow.swift; sourceTree = "<group>"; };
 		DD906BF32EA6AA0100262772 /* NightscoutUploadPipeline.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NightscoutUploadPipeline.swift; sourceTree = "<group>"; };
@@ -1511,6 +1530,7 @@
 		DDA9AC0A2D678DAD00E6F1A9 /* blacklisted-versions.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "blacklisted-versions.json"; sourceTree = "<group>"; };
 		DDAA29822D2D1D7B006546A1 /* AdjustmentsRootView+Overrides.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AdjustmentsRootView+Overrides.swift"; sourceTree = "<group>"; };
 		DDAA29842D2D1D98006546A1 /* AdjustmentsRootView+TempTargets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "AdjustmentsRootView+TempTargets.swift"; sourceTree = "<group>"; };
+		DDB0BBA02026050100000002 /* BolusProgressBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusProgressBar.swift; sourceTree = "<group>"; };
 		DDB0E3732DB1BAC1004B826F /* LogoBurstSplash.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogoBurstSplash.swift; sourceTree = "<group>"; };
 		DDB37CC22D05044D00D99BF4 /* ContactTrickEntryStored+CoreDataClass.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactTrickEntryStored+CoreDataClass.swift"; sourceTree = "<group>"; };
 		DDB37CC32D05044D00D99BF4 /* ContactTrickEntryStored+CoreDataProperties.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ContactTrickEntryStored+CoreDataProperties.swift"; sourceTree = "<group>"; };
@@ -1602,7 +1622,6 @@
 		E592A3742CEEC038009A472C /* ContactImageProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactImageProvider.swift; sourceTree = "<group>"; };
 		E592A3752CEEC038009A472C /* ContactImageStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactImageStateModel.swift; sourceTree = "<group>"; };
 		E625985B47742D498CB1681A /* GlucoseNotificationSettingsProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = GlucoseNotificationSettingsProvider.swift; sourceTree = "<group>"; };
-		B3919BBB515547118D684CA2 /* SettingsSearchTests.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SettingsSearchTests.swift; sourceTree = "<group>"; };
 		F816825D28DB441200054060 /* HeartBeatManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HeartBeatManager.swift; sourceTree = "<group>"; };
 		F816825F28DB441800054060 /* BluetoothTransmitter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BluetoothTransmitter.swift; sourceTree = "<group>"; };
 		F90692A9274B7AAE0037068D /* HealthKitManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HealthKitManager.swift; sourceTree = "<group>"; };
@@ -1614,19 +1633,6 @@
 		FE41E4D529463EE20047FD55 /* NightscoutPreferences.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NightscoutPreferences.swift; sourceTree = "<group>"; };
 		FE66D16A291F74F8005D6F77 /* Bundle+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bundle+Extensions.swift"; sourceTree = "<group>"; };
 		FEFFA7A12929FE49007B8193 /* UIDevice+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Extensions.swift"; sourceTree = "<group>"; };
-		BD175EFE0000100000000001 /* HistoryDataFlow+Models.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryDataFlow+Models.swift"; sourceTree = "<group>"; };
-		BD175EFE0000100000000002 /* HistoryDeletionTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HistoryDeletionTarget.swift; sourceTree = "<group>"; };
-		BD175EFE0000100000000003 /* HistoryStateModel+Glucose.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryStateModel+Glucose.swift"; sourceTree = "<group>"; };
-		BD175EFE0000100000000004 /* HistoryStateModel+Carbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryStateModel+Carbs.swift"; sourceTree = "<group>"; };
-		BD175EFE0000100000000005 /* HistoryStateModel+Insulin.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryStateModel+Insulin.swift"; sourceTree = "<group>"; };
-		BD175EFE0000100000000006 /* HistoryStateModel+CarbEditing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryStateModel+CarbEditing.swift"; sourceTree = "<group>"; };
-		BD175EFE0000100000000007 /* HistoryRootView+Treatments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryRootView+Treatments.swift"; sourceTree = "<group>"; };
-		BD175EFE0000100000000008 /* HistoryRootView+Meals.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryRootView+Meals.swift"; sourceTree = "<group>"; };
-		BD175EFE0000100000000009 /* HistoryRootView+Glucose.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryRootView+Glucose.swift"; sourceTree = "<group>"; };
-		BD175EFE000010000000000A /* HistoryRootView+Adjustments.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryRootView+Adjustments.swift"; sourceTree = "<group>"; };
-		BD175EFE000010000000000B /* HistoryRootView+Filters.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryRootView+Filters.swift"; sourceTree = "<group>"; };
-		BD175EFE000010000000000C /* HistoryRootView+AddGlucose.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryRootView+AddGlucose.swift"; sourceTree = "<group>"; };
-		BD175EFE000010000000000D /* HistoryRootView+Confirmations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HistoryRootView+Confirmations.swift"; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFileSystemSynchronizedRootGroup section */
@@ -2138,36 +2144,6 @@
 			path = Services;
 			sourceTree = "<group>";
 		};
-		DD7E1E30000000000000000A /* Telemetry */ = {
-			isa = PBXGroup;
-			children = (
-				DD7E1E300000000000000013 /* TelemetryAttestor.swift */,
-				DD7E1E300000000000000001 /* TelemetryClient.swift */,
-			);
-			path = Telemetry;
-			sourceTree = "<group>";
-		};
-		DD7E1E30000000000000000B /* Telemetry */ = {
-			isa = PBXGroup;
-			children = (
-				DD7E1E30000000000000000D /* TelemetryDataFlow.swift */,
-				DD7E1E30000000000000000F /* TelemetryProvider.swift */,
-				DD7E1E300000000000000011 /* TelemetryStateModel.swift */,
-				DD7E1E30000000000000000C /* View */,
-			);
-			path = Telemetry;
-			sourceTree = "<group>";
-		};
-		DD7E1E30000000000000000C /* View */ = {
-			isa = PBXGroup;
-			children = (
-				DD7E1E300000000000000003 /* TelemetryPreviewView.swift */,
-				DD7E1E300000000000000005 /* TelemetryPrivacyView.swift */,
-				DD7E1E300000000000000007 /* TelemetryMigrationSheetView.swift */,
-			);
-			path = View;
-			sourceTree = "<group>";
-		};
 		3811DE9225C9D88200A708ED /* Appearance */ = {
 			isa = PBXGroup;
 			children = (
@@ -2358,6 +2334,7 @@
 				DDA6E2842D2361F800C2988C /* LoopStatusView.swift */,
 				383420D525FFE38C002D46C1 /* LoopView.swift */,
 				38AAF85425FFF846004AF583 /* CurrentGlucoseView.swift */,
+				BD11C002000000000000C000 /* SensorLifecycle */,
 				38DAB27F260CBB7F00F74C1A /* PumpView.swift */,
 			);
 			path = Header;
@@ -2474,43 +2451,27 @@
 				3870FF4225EC13F40088248F /* BloodGlucose.swift */,
 				38A9260425F012D8009E3739 /* CarbRatios.swift */,
 				38D0B3D825EC07C400CB6E88 /* CarbsEntry.swift */,
-				19D4E4EA29FC6A9F00351451 /* Charts.swift */,
 				DD6D67E32C9C253500660C9B /* ColorSchemeOption.swift */,
-				DD9ECB692CA99F6C00AA7C45 /* CommandPayload.swift */,
 				E592A36F2CEEC01E009A472C /* ContactTrickEntry.swift */,
 				3811DF0125CA9FEA00A708ED /* Credentials.swift */,
-				19A910352A24D6D700C8951B /* DateFilter.swift */,
-				DD21FCB42C6952AD00AF2C25 /* DecimalPickerSettings.swift */,
-				583684072BD195A700070A60 /* Determination.swift */,
-				DDD6D4D22CDE90720029439A /* EstimatedA1cDisplayUnit.swift */,
 				DD3D60302F0377350021A33B /* ExportSetting.swift */,
-				DD6B7CB32C7B71F700B75029 /* ForecastDisplayType.swift */,
 				DD3078692D42F94000DE0490 /* GarminDevice.swift */,
 				49090A8C2E9FE8D200D0F5DB /* GarminWatchSettings.swift */,
 				DD4FFF322D458EE600B6CFF9 /* GarminWatchState.swift */,
 				DD940BA92CA7585D000830A5 /* GlucoseColorScheme.swift */,
 				715120D12D3C2B84005D9FB6 /* GlucoseNotificationsOption.swift */,
 				E0D4F80427513ECF00BDF1FE /* HealthKitSample.swift */,
-				1967DFBD29D052C200759F30 /* Icons.swift */,
 				382C133625F13A1E00715CE1 /* InsulinSensitivities.swift */,
 				38887CCD25F5725200944304 /* IOBEntry.swift */,
-				BDF530D72B40F8AC002CAF43 /* LockScreenView.swift */,
-				193F6CDC2A512C8F001240FD /* Loops.swift */,
-				19012CDB291D2CB900FB8210 /* LoopStats.swift */,
 				DD68889C2C386E17006E3C44 /* NightscoutExercise.swift */,
-				FE41E4D529463EE20047FD55 /* NightscoutPreferences.swift */,
-				191F62672AD6B05A004D7911 /* NightscoutSettings.swift */,
 				385CEA8125F23DFD002D6D5B /* NightscoutStatus.swift */,
 				389442CA25F65F7100FA1F27 /* NightscoutTreatment.swift */,
-				BDC2EA462C3045AD00E5BBD0 /* Override.swift */,
 				BD54A95A2D28087700F9C1EE /* OverridePresetWatch.swift */,
 				3895E4C525B9E00D00214B37 /* Preferences.swift */,
 				38A13D3125E28B4B00EAA382 /* PumpHistoryEvent.swift */,
 				3883583325EEB38000E024B2 /* PumpSettings.swift */,
 				38E989DC25F5021400C0CED0 /* PumpStatus.swift */,
-				CC6C406D2ACDD69E009B8058 /* RawFetchedProfile.swift */,
 				38BF021C25E7E3AF00579895 /* Reservoir.swift */,
-				19B0EF2028F6D66200069496 /* Statistics.swift */,
 				3B2F77852D7E52ED005ED9FA /* TDD.swift */,
 				38A0364125ED069400FCBB52 /* TempBasal.swift */,
 				3871F39B25ED892B0013ECB5 /* TempTarget.swift */,
@@ -2523,7 +2484,6 @@
 				BD432CA02D2F4E3300D1EB79 /* WatchMessageKeys.swift */,
 				BDA25EFC2D261BF200035F34 /* WatchState.swift */,
 				DDFF204F2DB2C11900AB8A96 /* WatchStateSnapshot.swift */,
-				CE82E02628E869DF00473A9C /* AlertEntry.swift */,
 				19B0EF2028F6D66200069496 /* Statistics.swift */,
 				19012CDB291D2CB900FB8210 /* LoopStats.swift */,
 				FE41E4D529463EE20047FD55 /* NightscoutPreferences.swift */,
@@ -2765,14 +2725,6 @@
 			path = IOB;
 			sourceTree = "<group>";
 		};
-		B015AFE22E500000000D7351 /* BolusSafety */ = {
-			isa = PBXGroup;
-			children = (
-				B015AFE12E500000000D7351 /* BolusSafetyValidator.swift */,
-			);
-			path = BolusSafety;
-			sourceTree = "<group>";
-		};
 		4E8C7B59F8065047ECE20965 /* View */ = {
 			isa = PBXGroup;
 			children = (
@@ -2946,17 +2898,6 @@
 			path = History;
 			sourceTree = "<group>";
 		};
-		BD175EC00000100000000001 /* HistoryStateModel+Deletion */ = {
-			isa = PBXGroup;
-			children = (
-				BD175EFE0000100000000003 /* HistoryStateModel+Glucose.swift */,
-				BD175EFE0000100000000004 /* HistoryStateModel+Carbs.swift */,
-				BD175EFE0000100000000005 /* HistoryStateModel+Insulin.swift */,
-				BD175EFE0000100000000006 /* HistoryStateModel+CarbEditing.swift */,
-			);
-			path = "HistoryStateModel+Deletion";
-			sourceTree = "<group>";
-		};
 		A42F1FEDFFD0DDE00AAD54D3 /* BasalProfileEditor */ = {
 			isa = PBXGroup;
 			children = (
@@ -2968,6 +2909,22 @@
 			path = BasalProfileEditor;
 			sourceTree = "<group>";
 		};
+		B015AFE22E500000000D7351 /* BolusSafety */ = {
+			isa = PBXGroup;
+			children = (
+				B015AFE12E500000000D7351 /* BolusSafetyValidator.swift */,
+			);
+			path = BolusSafety;
+			sourceTree = "<group>";
+		};
+		B015AFE62E500000000D7351 /* BolusSafetyTests */ = {
+			isa = PBXGroup;
+			children = (
+				B015AFE42E500000000D7351 /* BolusSafetyValidatorTests.swift */,
+			);
+			path = BolusSafetyTests;
+			sourceTree = "<group>";
+		};
 		B9488883C59C31550E0B4CEC /* View */ = {
 			isa = PBXGroup;
 			children = (
@@ -2979,6 +2936,27 @@
 			path = View;
 			sourceTree = "<group>";
 		};
+		BD11C002000000000000C000 /* SensorLifecycle */ = {
+			isa = PBXGroup;
+			children = (
+				BD11C000000000000000C001 /* CGMSensorDisplayState.swift */,
+				BD11C000000000000000C003 /* SensorLifecycleArcView.swift */,
+				BD11C000000000000000C004 /* SensorStatusTagView.swift */,
+			);
+			path = SensorLifecycle;
+			sourceTree = "<group>";
+		};
+		BD175EC00000100000000001 /* HistoryStateModel+Deletion */ = {
+			isa = PBXGroup;
+			children = (
+				BD175EFE0000100000000003 /* HistoryStateModel+Glucose.swift */,
+				BD175EFE0000100000000004 /* HistoryStateModel+Carbs.swift */,
+				BD175EFE0000100000000005 /* HistoryStateModel+Insulin.swift */,
+				BD175EFE0000100000000006 /* HistoryStateModel+CarbEditing.swift */,
+			);
+			path = "HistoryStateModel+Deletion";
+			sourceTree = "<group>";
+		};
 		BD249D842D42FBD200412DEB /* ViewElements */ = {
 			isa = PBXGroup;
 			children = (
@@ -3127,14 +3105,6 @@
 			path = BolusCalculatorTests;
 			sourceTree = "<group>";
 		};
-		B015AFE62E500000000D7351 /* BolusSafetyTests */ = {
-			isa = PBXGroup;
-			children = (
-				B015AFE42E500000000D7351 /* BolusSafetyValidatorTests.swift */,
-			);
-			path = BolusSafetyTests;
-			sourceTree = "<group>";
-		};
 		BDA25F1A2D26BCE800035F34 /* Views */ = {
 			isa = PBXGroup;
 			children = (
@@ -3603,6 +3573,36 @@
 			path = StartupGuide;
 			sourceTree = "<group>";
 		};
+		DD7E1E30000000000000000A /* Telemetry */ = {
+			isa = PBXGroup;
+			children = (
+				DD7E1E300000000000000013 /* TelemetryAttestor.swift */,
+				DD7E1E300000000000000001 /* TelemetryClient.swift */,
+			);
+			path = Telemetry;
+			sourceTree = "<group>";
+		};
+		DD7E1E30000000000000000B /* Telemetry */ = {
+			isa = PBXGroup;
+			children = (
+				DD7E1E30000000000000000D /* TelemetryDataFlow.swift */,
+				DD7E1E30000000000000000F /* TelemetryProvider.swift */,
+				DD7E1E300000000000000011 /* TelemetryStateModel.swift */,
+				DD7E1E30000000000000000C /* View */,
+			);
+			path = Telemetry;
+			sourceTree = "<group>";
+		};
+		DD7E1E30000000000000000C /* View */ = {
+			isa = PBXGroup;
+			children = (
+				DD7E1E300000000000000003 /* TelemetryPreviewView.swift */,
+				DD7E1E300000000000000005 /* TelemetryPrivacyView.swift */,
+				DD7E1E300000000000000007 /* TelemetryMigrationSheetView.swift */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
 		DD9ECB662CA99EFE00AA7C45 /* RemoteControl */ = {
 			isa = PBXGroup;
 			children = (
@@ -4790,6 +4790,9 @@
 				BDF34F932C10D0E100D51995 /* LiveActivityAttributes+Helper.swift in Sources */,
 				E0D4F80527513ECF00BDF1FE /* HealthKitSample.swift in Sources */,
 				38AAF85525FFF846004AF583 /* CurrentGlucoseView.swift in Sources */,
+				BD11C001000000000000C001 /* CGMSensorDisplayState.swift in Sources */,
+				BD11C001000000000000C003 /* SensorLifecycleArcView.swift in Sources */,
+				BD11C001000000000000C004 /* SensorStatusTagView.swift in Sources */,
 				041D1E995A6AE92E9289DC49 /* TreatmentsDataFlow.swift in Sources */,
 				DD32CF9E2CC824C5003686D6 /* TrioRemoteControl+Override.swift in Sources */,
 				BD249D922D42FC5300412DEB /* GlucoseSectorChart.swift in Sources */,

+ 3 - 0
Trio/Sources/APS/CGM/AppGroupSource.swift

@@ -30,6 +30,9 @@ struct AppGroupSource: GlucoseSource {
     let from: String
     var cgmType: CGMType
 
+    let cgmDisplayState = CurrentValueSubject<CgmDisplayState?, Never>(nil)
+    let cgmProgressHighlight = CurrentValueSubject<LoopKit.DeviceLifecycleProgress?, Never>(nil)
+
     func fetch(_ heartbeat: DispatchTimer?) -> AnyPublisher<[BloodGlucose], Never> {
         guard let suiteName = Bundle.main.appGroupSuiteName,
               let sharedDefaults = UserDefaults(suiteName: suiteName)

+ 171 - 0
Trio/Sources/APS/CGM/GlucoseSimulatorSource.swift

@@ -14,6 +14,7 @@
 
 import Combine
 import Foundation
+import LoopKit
 import LoopKitUI
 
 // MARK: - Glucose simulator
@@ -25,6 +26,9 @@ final class GlucoseSimulatorSource: GlucoseSource {
     var cgmManager: CGMManagerUI?
     var glucoseManager: FetchGlucoseManager?
 
+    let cgmDisplayState = CurrentValueSubject<CgmDisplayState?, Never>(nil)
+    let cgmProgressHighlight = CurrentValueSubject<DeviceLifecycleProgress?, Never>(nil)
+
     private enum Config {
         /// Minimum time period between data publications (in seconds)
         static let workInterval: TimeInterval = 300
@@ -49,6 +53,26 @@ final class GlucoseSimulatorSource: GlucoseSource {
             }
             lastFetchDate = lastDate
         }
+        publishSimulatedState()
+    }
+
+    /// Republishes synthetic lifecycle/highlight from `simulatedScenario`.
+    func publishSimulatedState() {
+        cgmProgressHighlight.value = cgmLifecycleProgress
+        if let highlight = cgmStatusHighlight {
+            cgmDisplayState.value = CgmDisplayState(
+                localizedMessage: highlight.localizedMessage,
+                status: CgmDisplayStatus.from(highlight.state)
+            )
+        } else {
+            cgmDisplayState.value = nil
+        }
+    }
+
+    /// Picker entry point — change scenario + propagate immediately.
+    func applySimulatedScenario(_ scenario: SimulatedSensorScenario) {
+        simulatedScenario = scenario
+        publishSimulatedState()
     }
 
     /// The glucose generator used to create simulated values
@@ -94,6 +118,153 @@ final class GlucoseSimulatorSource: GlucoseSource {
     func fetchIfNeeded() -> AnyPublisher<[BloodGlucose], Never> {
         fetch(nil)
     }
+
+    // MARK: - Simulated sensor lifecycle / status (dev-only)
+
+    //
+    // The simulator doesn't own a real `CGMManagerUI`, so `cgmStatusHighlight`
+    // and `cgmLifecycleProgress` would be nil on the home screen. To make the
+    // outer arc + tag indicator actually exercisable without Libre/Dexcom
+    // hardware, the simulator exposes synthetic values driven by
+    // `simulatedScenario`. Flip the persisted enum at runtime (debug menu or
+    // by editing the default below) and the home view picks up the change on
+    // its next 5-second refresh tick.
+
+    /// Which pre-canned sensor state the simulator should advertise. Plain
+    /// `UserDefaults` string access (not `@Persisted`) so the CGM-settings
+    /// picker — which writes via `UserDefaults.standard.set(_:forKey:)` — and
+    /// the read here use the same encoding. `@Persisted` stores values as
+    /// JSON-wrapped `Data`, which would silently break the picker round-trip.
+    static let simulatedScenarioKey = "GlucoseSimulator.simulatedScenario"
+
+    var simulatedScenario: SimulatedSensorScenario {
+        get {
+            let raw = UserDefaults.standard.string(forKey: Self.simulatedScenarioKey)
+            return raw.flatMap(SimulatedSensorScenario.init(rawValue:)) ?? .runningNormally
+        }
+        set {
+            UserDefaults.standard.set(newValue.rawValue, forKey: Self.simulatedScenarioKey)
+        }
+    }
+
+    /// Synthetic expiration date that mirrors what a real CGM would expose.
+    /// Picked so the remaining-time label matches the scenario's
+    /// `percentComplete` against a 10-day total (Dexcom-like).
+    var simulatedSensorExpiresAt: Date? {
+        guard let progress = cgmLifecycleProgress else { return nil }
+        let totalLifetime: TimeInterval = 10 * 24 * 60 * 60
+        let remaining = (1.0 - progress.percentComplete) * totalLifetime
+        return Date().addingTimeInterval(remaining)
+    }
+
+    /// Synthetic outer-arc data — nil for scenarios where lifetime is moot
+    /// (warmup, hardware fault). Matches the production `DeviceLifecycleProgress`
+    /// shape so the home state model can treat both sources identically.
+    var cgmLifecycleProgress: DeviceLifecycleProgress? {
+        switch simulatedScenario {
+        case .runningNormally:
+            return SimulatedLifecycleProgress(percentComplete: 0.45, progressState: .normalCGM)
+        case .expiringSoon:
+            return SimulatedLifecycleProgress(percentComplete: 0.94, progressState: .warning)
+        case .warmup:
+            return nil
+        case .calibrationRequired:
+            return SimulatedLifecycleProgress(percentComplete: 0.30, progressState: .normalCGM)
+        case .expired:
+            return SimulatedLifecycleProgress(percentComplete: 1.0, progressState: .critical)
+        case .sensorFailed:
+            return nil
+        }
+    }
+
+    /// Synthetic status highlight. nil for `.runningNormally` and
+    /// `.expiringSoon` (those run off lifecycle only).
+    var cgmStatusHighlight: DeviceStatusHighlight? {
+        switch simulatedScenario {
+        case .expiringSoon,
+             .runningNormally:
+            return nil
+        case .warmup:
+            return SimulatedStatusHighlight(
+                localizedMessage: "Sensor warming up",
+                imageName: "hourglass",
+                state: .warning
+            )
+        case .calibrationRequired:
+            return SimulatedStatusHighlight(
+                localizedMessage: "Calibrate",
+                imageName: "drop.fill",
+                state: .warning
+            )
+        case .expired:
+            return SimulatedStatusHighlight(
+                localizedMessage: "Sensor expired",
+                imageName: "exclamationmark.circle.fill",
+                state: .critical
+            )
+        case .sensorFailed:
+            return SimulatedStatusHighlight(
+                localizedMessage: "Replace Sensor",
+                imageName: "exclamationmark.triangle.fill",
+                state: .critical
+            )
+        }
+    }
+}
+
+/// Pre-canned sensor scenarios surfaced by `GlucoseSimulatorSource`. One per
+/// home-screen state so flipping this drives the indicator
+/// through every visual state.
+enum SimulatedSensorScenario: String, CaseIterable, Identifiable {
+    case runningNormally
+    case expiringSoon
+    case warmup
+    case calibrationRequired
+    case expired
+    case sensorFailed
+
+    var id: String { rawValue }
+
+    var displayName: String {
+        switch self {
+        case .runningNormally: return "Running normally"
+        case .expiringSoon: return "Expiring soon"
+        case .warmup: return "Warmup"
+        case .calibrationRequired: return "Calibration required"
+        case .expired: return "Expired"
+        case .sensorFailed: return "Sensor failed"
+        }
+    }
+
+    /// Short blurb shown under the picker so dev users know what each
+    /// scenario renders on the home screen.
+    var devNotes: String {
+        switch self {
+        case .runningNormally:
+            return "Teal outer ring at ~45%, tag shows time remaining."
+        case .expiringSoon:
+            return "Amber outer ring at ~94%, tag shows time remaining with \"left\" suffix."
+        case .warmup:
+            return "Arc hidden, pulsing amber tag, glucose shown as \"– –\"."
+        case .calibrationRequired:
+            return "Arc visible, amber tag with \"Calibrate\" message, glucose still shown."
+        case .expired:
+            return "Red full ring, red tag \"sensor expired\", glucose shown as \"– –\"."
+        case .sensorFailed:
+            return "Arc hidden, pulsing red tag, glucose shown as \"– –\"."
+        }
+    }
+}
+
+private struct SimulatedLifecycleProgress: DeviceLifecycleProgress {
+    let percentComplete: Double
+    let progressState: DeviceLifecycleProgressState
+}
+
+private struct SimulatedStatusHighlight: DeviceStatusHighlight {
+    let localizedMessage: String
+    let imageName: String
+    let state: DeviceStatusHighlightState
 }
 
 // MARK: - Glucose generator

+ 4 - 0
Trio/Sources/APS/CGM/GlucoseSource.swift

@@ -11,6 +11,10 @@ protocol GlucoseSource: SourceInfoProvider {
     func fetchIfNeeded() -> AnyPublisher<[BloodGlucose], Never>
     var glucoseManager: FetchGlucoseManager? { get set }
     var cgmManager: CGMManagerUI? { get set }
+    /// Mirrors `CGMManagerUI.cgmStatusHighlight`; republished on manager change.
+    var cgmDisplayState: CurrentValueSubject<CgmDisplayState?, Never> { get }
+    /// Mirrors `CGMManagerUI.cgmLifecycleProgress`.
+    var cgmProgressHighlight: CurrentValueSubject<LoopKit.DeviceLifecycleProgress?, Never> { get }
 }
 
 extension GlucoseSource {

+ 24 - 1
Trio/Sources/APS/CGM/PluginSource.swift

@@ -11,7 +11,12 @@ final class PluginSource: GlucoseSource {
     private let glucoseStorage: GlucoseStorage!
     var glucoseManager: FetchGlucoseManager?
 
-    var cgmManager: CGMManagerUI?
+    let cgmDisplayState = CurrentValueSubject<CgmDisplayState?, Never>(nil)
+    let cgmProgressHighlight = CurrentValueSubject<DeviceLifecycleProgress?, Never>(nil)
+
+    var cgmManager: CGMManagerUI? {
+        didSet { publishCGMStatus() }
+    }
 
     var cgmHasValidSensorSession: Bool = false
 
@@ -24,6 +29,20 @@ final class PluginSource: GlucoseSource {
         cgmManager?.cgmManagerDelegate = self
     }
 
+    /// Republishes the manager's lifecycle/highlight to the subjects.
+    /// Called from `cgmManager.didSet` and after delegate state updates.
+    func publishCGMStatus() {
+        if let highlight = cgmManager?.cgmStatusHighlight {
+            cgmDisplayState.value = CgmDisplayState(
+                localizedMessage: highlight.localizedMessage,
+                status: CgmDisplayStatus.from(highlight.state)
+            )
+        } else {
+            cgmDisplayState.value = nil
+        }
+        cgmProgressHighlight.value = cgmManager?.cgmLifecycleProgress
+    }
+
     /// Function that fetches blood glucose data
     /// This function combines two data fetching mechanisms (`callBLEFetch` and `fetchIfNeeded`) into a single publisher.
     /// It returns the first non-empty result from either of the sources within a 5-minute timeout period.
@@ -170,6 +189,10 @@ extension PluginSource: CGMManagerDelegate {
                 cgmGlucosePluginId: fetchGlucoseManager.settingsManager.settings.cgmPluginIdentifier,
                 newManager: cgmManager as? CGMManagerUI
             )
+
+            // Pick up manager-internal state changes (sensor swap, warmup,
+            // expiry crossover) when the instance itself stays the same.
+            self.publishCGMStatus()
         }
     }
 

+ 3 - 0
Trio/Sources/APS/DeviceDataManager.swift

@@ -321,6 +321,9 @@ final class BaseDeviceDataManager: DeviceDataManager, Injectable {
     var cgmManager: CGMManagerUI?
     var cgmType: CGMType = .enlite
 
+    let cgmDisplayState = CurrentValueSubject<CgmDisplayState?, Never>(nil)
+    let cgmProgressHighlight = CurrentValueSubject<DeviceLifecycleProgress?, Never>(nil)
+
     func fetchIfNeeded() -> AnyPublisher<[BloodGlucose], Never> {
         fetch(nil)
     }

+ 23 - 1
Trio/Sources/APS/FetchGlucoseManager.swift

@@ -19,6 +19,8 @@ protocol FetchGlucoseManager: SourceInfoProvider {
     var cgmGlucosePluginId: String { get }
     var settingsManager: SettingsManager! { get }
     var shouldSyncToRemoteService: Bool { get }
+    var cgmDisplayState: CurrentValueSubject<CgmDisplayState?, Never> { get }
+    var cgmProgressHighlight: CurrentValueSubject<DeviceLifecycleProgress?, Never> { get }
 }
 
 extension FetchGlucoseManager {
@@ -148,7 +150,27 @@ final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
         }
     }
 
-    var glucoseSource: GlucoseSource?
+    let cgmDisplayState = CurrentValueSubject<CgmDisplayState?, Never>(nil)
+    let cgmProgressHighlight = CurrentValueSubject<DeviceLifecycleProgress?, Never>(nil)
+    private var cgmStatusSubscriptions = Set<AnyCancellable>()
+
+    var glucoseSource: GlucoseSource? {
+        didSet {
+            // Drop prior subscriptions so source swaps don't dupe emissions.
+            cgmStatusSubscriptions.removeAll()
+            cgmDisplayState.value = glucoseSource?.cgmDisplayState.value
+            cgmProgressHighlight.value = glucoseSource?.cgmProgressHighlight.value
+            guard let glucoseSource else { return }
+            glucoseSource.cgmDisplayState
+                .receive(on: DispatchQueue.main)
+                .sink { [weak self] state in self?.cgmDisplayState.value = state }
+                .store(in: &cgmStatusSubscriptions)
+            glucoseSource.cgmProgressHighlight
+                .receive(on: DispatchQueue.main)
+                .sink { [weak self] progress in self?.cgmProgressHighlight.value = progress }
+                .store(in: &cgmStatusSubscriptions)
+        }
+    }
 
     func removeCalibrations() {
         calibrationService.removeAllCalibrations()

+ 35 - 0
Trio/Sources/Modules/CGMSettings/CGMSettingsDataFlow.swift

@@ -1,5 +1,40 @@
+import LoopKit
+import SwiftUI
+
 enum CGMSettings {
     enum Config {}
 }
 
 protocol CGMSettingsProvider: Provider {}
+
+/// `cgmStatusHighlight` reduced to message + tier — what the home UI needs.
+struct CgmDisplayState: Equatable {
+    let localizedMessage: String
+    let status: CgmDisplayStatus
+}
+
+enum CgmDisplayStatus {
+    case normal
+    case warning
+    case critical
+
+    var color: Color {
+        switch self {
+        case .critical: return .critical
+        case .warning: return .warning
+        case .normal: return .loopAccent
+        }
+    }
+
+    static func from(_ state: LoopKit.DeviceStatusHighlightState) -> CgmDisplayStatus {
+        switch state {
+        case .normalCGM,
+             .normalPump:
+            return .normal
+        case .warning:
+            return .warning
+        case .critical:
+            return .critical
+        }
+    }
+}

+ 35 - 0
Trio/Sources/Modules/CGMSettings/View/CustomCGMOptionsView.swift

@@ -22,6 +22,10 @@ extension CGMSettings {
         @State private var noiseAmplitude: Double = UserDefaults.standard.double(forKey: "GlucoseSimulator_NoiseAmplitude")
         @State private var produceStaleValues: Bool = UserDefaults.standard.bool(forKey: "GlucoseSimulator_ProduceStaleValues")
 
+        /// Drives the synthetic `cgmStatusHighlight`
+        @State private var simulatedScenarioRaw: String = UserDefaults.standard
+            .string(forKey: "GlucoseSimulator.simulatedScenario") ?? SimulatedSensorScenario.runningNormally.rawValue
+
         // Initialize state variables with defaults if needed
         private func initializeSimulatorSettings() {
             if centerValue == 0 {
@@ -261,6 +265,37 @@ extension CGMSettings {
                     }
                 }.listRowBackground(Color.chart)
 
+                Section(
+                    header: Text("Sensor Lifecycle Scenario"),
+                    footer: Text(
+                        "Drives the outer-ring + tag on the home screen's glucose bobble."
+                    )
+                ) {
+                    Picker("Scenario", selection: $simulatedScenarioRaw) {
+                        ForEach(SimulatedSensorScenario.allCases) { scenario in
+                            Text(scenario.displayName).tag(scenario.rawValue)
+                        }
+                    }
+                    .pickerStyle(.menu)
+                    .onChange(of: simulatedScenarioRaw) { _, newValue in
+                        UserDefaults.standard.set(newValue, forKey: "GlucoseSimulator.simulatedScenario")
+                        // Push the change through the active simulator
+                        // instance so subjects emit immediately.
+                        if let scenario = SimulatedSensorScenario(rawValue: newValue),
+                           let sim = resolver.resolve(FetchGlucoseManager.self)?.glucoseSource as? GlucoseSimulatorSource
+                        {
+                            sim.applySimulatedScenario(scenario)
+                        }
+                    }
+
+                    if let scenario = SimulatedSensorScenario(rawValue: simulatedScenarioRaw) {
+                        Text(scenario.devNotes)
+                            .font(.footnote)
+                            .foregroundStyle(Color.secondary)
+                            .lineLimit(nil)
+                    }
+                }.listRowBackground(Color.chart)
+
                 if !produceStaleValues {
                     Section {
                         VStack(alignment: .leading, spacing: 10) {

+ 68 - 0
Trio/Sources/Modules/Home/HomeStateModel.swift

@@ -1,7 +1,10 @@
+import CGMBLEKit
 import CGMBLEKitUI
 import Combine
 import CoreData
 import Foundation
+import G7SensorKit
+import LibreTransmitter
 import LoopKit
 import LoopKitUI
 import Observation
@@ -107,6 +110,9 @@ extension Home {
         var pumpStatusBadgeImage: UIImage?
         var pumpStatusBadgeColor: Color?
         var cgmAvailable: Bool = false
+        var cgmDisplayState: CgmDisplayState?
+        var cgmProgressHighlight: DeviceLifecycleProgress?
+        var cgmSensorExpiresAt: Date?
         var listOfCGM: [CGMModel] = []
         var cgmCurrent = cgmDefaultModel
         var pumpInitialSettings = PumpConfig.PumpInitialSettings.default
@@ -326,6 +332,23 @@ extension Home {
             }
             timer.resume()
 
+            fetchGlucoseManager.cgmDisplayState
+                .receive(on: DispatchQueue.main)
+                .sink { [weak self] state in self?.cgmDisplayState = state }
+                .store(in: &lifetime)
+            fetchGlucoseManager.cgmProgressHighlight
+                .receive(on: DispatchQueue.main)
+                .sink { [weak self] progress in
+                    guard let self else { return }
+                    self.cgmProgressHighlight = progress
+                    self.cgmSensorExpiresAt = Self.resolveSensorExpiresAt(
+                        manager: self.fetchGlucoseManager.cgmManager,
+                        glucoseSource: self.fetchGlucoseManager.glucoseSource,
+                        lifecycle: progress
+                    )
+                }
+                .store(in: &lifetime)
+
             apsManager.isLooping
                 .receive(on: DispatchQueue.main)
                 .weakAssign(to: \.isLooping, on: self)
@@ -642,6 +665,51 @@ extension Home {
                 }
             }
         }
+
+        /// Pulls `cgmStatusHighlight` + `cgmLifecycleProgress` off the active
+        /// `CGMManagerUI` and derives the bobble's outer-arc/tag display state.
+        /// Called from the home timer (every 5s) and on subscribe. Cheap — both
+        /// LoopKit properties are computed accessors backed by the manager's
+        /// in-memory sensor state.
+        ///
+        /// Falls back to `GlucoseSimulatorSource`'s synthetic values when no
+        /// real `CGMManagerUI` is active — lets the lifecycle indicator be
+        /// exercised end-to-end without Libre/Dexcom hardware.
+        /// G7 exposes `sensorExpiresAt` directly; for everyone else we reverse-
+        /// derive it from `activatedAt + percentComplete`. Falls through to
+        /// nil if neither is available — UI then drops the time label.
+        private static func resolveSensorExpiresAt(
+            manager: CGMManagerUI?,
+            glucoseSource: GlucoseSource?,
+            lifecycle: DeviceLifecycleProgress?
+        ) -> Date? {
+            if let sim = glucoseSource as? GlucoseSimulatorSource {
+                return sim.simulatedSensorExpiresAt
+            }
+            guard let manager else { return nil }
+            if let g7 = manager as? G7CGMManager, let exp = g7.sensorExpiresAt { return exp }
+
+            let activatedAt: Date?
+            if let g7 = manager as? G7CGMManager {
+                activatedAt = g7.sensorActivatedAt
+            } else if let g6 = manager as? G6CGMManager {
+                activatedAt = g6.latestReading?.activationDate ?? g6.latestReading?.sessionStartDate
+            } else if let g5 = manager as? G5CGMManager {
+                activatedAt = g5.latestReading?.activationDate ?? g5.latestReading?.sessionStartDate
+            } else if let libre = manager as? LibreTransmitterManagerV3 {
+                activatedAt = libre.sensorInfoObservable.activatedAt
+            } else {
+                activatedAt = nil
+            }
+
+            guard let activatedAt,
+                  let lifecycle,
+                  lifecycle.percentComplete > 0.001
+            else { return nil }
+            let elapsed = Date().timeIntervalSince(activatedAt)
+            guard elapsed > 0 else { return nil }
+            return activatedAt.addingTimeInterval(elapsed / lifecycle.percentComplete)
+        }
     }
 }
 

+ 136 - 71
Trio/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift

@@ -1,4 +1,5 @@
 import CoreData
+import LoopKit
 import SwiftUI
 
 struct CurrentGlucoseView: View {
@@ -11,6 +12,14 @@ struct CurrentGlucoseView: View {
     var currentGlucoseTarget: Decimal
     let glucoseColorScheme: GlucoseColorScheme
     let glucose: [GlucoseStored] // This contains the last two glucose values, no matter if its manual or a cgm reading
+
+    /// Drives the outer ring.
+    var cgmProgress: DeviceLifecycleProgress?
+    /// CGM status highlight, rendered verbatim.
+    var cgmStatus: CgmDisplayState?
+    /// Sensor expiration — fallback tag when `cgmStatus` is nil.
+    var cgmSensorExpiresAt: Date?
+
     @State private var rotationDegrees: Double = 0.0
     @State private var angularGradient = AngularGradient(colors: [
         Color(red: 0.7215686275, green: 0.3411764706, blue: 1),
@@ -42,81 +51,53 @@ struct CurrentGlucoseView: View {
         let triangleColor = Color(red: 0.262745098, green: 0.7333333333, blue: 0.9137254902)
 
         if cgmAvailable {
-            ZStack {
-                TrendShape(gradient: angularGradient, color: triangleColor)
-                    .rotationEffect(.degrees(rotationDegrees))
-
-                VStack(alignment: .center) {
-                    HStack {
-                        if let glucoseValue = glucose.last?.glucose {
-                            let displayGlucose = units == .mgdL ? Decimal(glucoseValue).description : Decimal(glucoseValue)
-                                .formattedAsMmolL
-
-                            var glucoseDisplayColor = Color.primary
-
-                            // TODO: workaround for now: set low value to 55, to have dynamic color shades between 55 and user-set low (approx. 70); same for high glucose
-                            let hardCodedLow = Decimal(55)
-                            let hardCodedHigh = Decimal(220)
-                            let isDynamicColorScheme = glucoseColorScheme == .dynamicColor
-
-                            if Decimal(glucoseValue) <= lowGlucose || Decimal(glucoseValue) >= highGlucose {
-                                glucoseDisplayColor = Trio.getDynamicGlucoseColor(
-                                    glucoseValue: Decimal(glucoseValue),
-                                    highGlucoseColorValue: isDynamicColorScheme ? hardCodedHigh : highGlucose,
-                                    lowGlucoseColorValue: isDynamicColorScheme ? hardCodedLow : lowGlucose,
-                                    targetGlucose: currentGlucoseTarget,
-                                    glucoseColorScheme: glucoseColorScheme
-                                )
-                            }
-
-                            return Text(
-                                glucoseValue == 400 ? "HIGH" : displayGlucose
-                            )
-                            .font(.system(size: 40, weight: .bold, design: .rounded))
-                            .foregroundStyle(glucoseDisplayColor)
-                        } else {
-                            return Text("--")
-                                .font(.system(size: 40, weight: .bold, design: .rounded))
-                                .foregroundStyle(.secondary)
-                        }
+            VStack(spacing: 0) {
+                ZStack {
+                    if let progress = cgmProgress {
+                        SensorLifecycleArcView(
+                            progress: progress.percentComplete,
+                            progressState: progress.progressState
+                        )
                     }
-                    HStack {
-                        let minutesAgoString = TimeAgoFormatter.minutesAgo(from: glucose.last?.date)
-                        Group {
-                            Text(minutesAgoString)
-                            Text(delta)
-                        }
-                        .font(.callout).fontWeight(.bold)
-                        .foregroundStyle(colorScheme == .dark ? Color.white.opacity(0.9) : Color.secondary)
+
+                    TrendShape(gradient: angularGradient, color: triangleColor, showArrow: true)
+                        .rotationEffect(.degrees(rotationDegrees))
+
+                    VStack(alignment: .center) {
+                        bobbleContent()
                     }
-                    .frame(alignment: .top)
                 }
-            }
-            .onChange(of: glucose.last?.directionEnum) {
-                withAnimation {
-                    switch glucose.last?.directionEnum {
-                    case .doubleUp,
-                         .singleUp,
-                         .tripleUp:
-                        rotationDegrees = -90
-                    case .fortyFiveUp:
-                        rotationDegrees = -45
-                    case .flat:
-                        rotationDegrees = 0
-                    case .fortyFiveDown:
-                        rotationDegrees = 45
-                    case .doubleDown,
-                         .singleDown,
-                         .tripleDown:
-                        rotationDegrees = 90
-                    case nil,
-                         .notComputable,
-                         .rateOutOfRange:
-                        rotationDegrees = 0
-                    default:
-                        rotationDegrees = 0
+                .onChange(of: glucose.last?.directionEnum) {
+                    withAnimation {
+                        switch glucose.last?.directionEnum {
+                        case .doubleUp,
+                             .singleUp,
+                             .tripleUp:
+                            rotationDegrees = -90
+                        case .fortyFiveUp:
+                            rotationDegrees = -45
+                        case .flat:
+                            rotationDegrees = 0
+                        case .fortyFiveDown:
+                            rotationDegrees = 45
+                        case .doubleDown,
+                             .singleDown,
+                             .tripleDown:
+                            rotationDegrees = 90
+                        case nil,
+                             .notComputable,
+                             .rateOutOfRange:
+                            rotationDegrees = 0
+                        default:
+                            rotationDegrees = 0
+                        }
                     }
                 }
+
+                if let tag = tagLabel {
+                    SensorStatusTagView(text: tag.text, theme: tag.theme)
+                        .zIndex(1)
+                }
             }
         } else {
             VStack(alignment: .center, spacing: 12) {
@@ -146,6 +127,87 @@ struct CurrentGlucoseView: View {
         let delta = lastGlucose - secondLastGlucose
         return deltaFormatter.string(from: delta as NSNumber) ?? "--"
     }
+
+    @ViewBuilder private func bobbleContent() -> some View {
+        HStack {
+            if let glucoseValue = glucose.last?.glucose, isReadingFresh {
+                let displayGlucose = units == .mgdL
+                    ? Decimal(glucoseValue).description
+                    : Decimal(glucoseValue).formattedAsMmolL
+                Text(glucoseValue == 400 ? "HIGH" : displayGlucose)
+                    .font(.system(size: 40, weight: .bold, design: .rounded))
+                    .foregroundStyle(glucoseColor(for: glucoseValue))
+            } else {
+                Text("– –")
+                    .font(.system(size: 40, weight: .bold, design: .rounded))
+                    .foregroundStyle(.secondary)
+            }
+        }
+        if isReadingFresh {
+            HStack {
+                let minutesAgoString = TimeAgoFormatter.minutesAgo(from: glucose.last?.date)
+                Group {
+                    Text(minutesAgoString)
+                    Text(delta)
+                }
+                .font(.callout).fontWeight(.bold)
+                .foregroundStyle(colorScheme == .dark ? Color.white.opacity(0.9) : Color.secondary)
+            }
+            .frame(alignment: .top)
+        }
+    }
+
+    /// Matches `APSManager`'s loop-input freshness gate — readings older than
+    /// 12 minutes (one missed CGM transmission on a 5-min schedule) get
+    /// masked to dashes. Handles warmup + sensor failure naturally: no
+    /// fresh data → no number on the bobble.
+    private var isReadingFresh: Bool {
+        guard let date = glucose.last?.date else { return false }
+        return Date().timeIntervalSince(date) < 12 * 60
+    }
+
+    /// Status highlight wins; otherwise fall back to remaining-time.
+    private var tagLabel: (text: String, theme: SensorStatusTagTheme)? {
+        if let status = cgmStatus {
+            return (status.localizedMessage, theme(for: status.status))
+        }
+        if let expiresAt = cgmSensorExpiresAt {
+            let text = SensorRemainingTimeFormatter.format(until: expiresAt)
+            let theme: SensorStatusTagTheme
+            switch cgmProgress?.progressState {
+            case .critical: theme = .red
+            case .warning: theme = .orange
+            default: theme = .green
+            }
+            return (text, theme)
+        }
+        return nil
+    }
+
+    private func theme(for status: CgmDisplayStatus) -> SensorStatusTagTheme {
+        switch status {
+        case .critical: return .red
+        case .warning: return .orange
+        case .normal: return .secondary
+        }
+    }
+
+    private func glucoseColor(for glucoseValue: Int16) -> Color {
+        // TODO: workaround for now: set low value to 55, to have dynamic color shades between 55 and user-set low (approx. 70); same for high glucose
+        let hardCodedLow = Decimal(55)
+        let hardCodedHigh = Decimal(220)
+        let isDynamicColorScheme = glucoseColorScheme == .dynamicColor
+        guard Decimal(glucoseValue) <= lowGlucose || Decimal(glucoseValue) >= highGlucose else {
+            return Color.primary
+        }
+        return Trio.getDynamicGlucoseColor(
+            glucoseValue: Decimal(glucoseValue),
+            highGlucoseColorValue: isDynamicColorScheme ? hardCodedHigh : highGlucose,
+            lowGlucoseColorValue: isDynamicColorScheme ? hardCodedLow : lowGlucose,
+            targetGlucose: currentGlucoseTarget,
+            glucoseColorScheme: glucoseColorScheme
+        )
+    }
 }
 
 struct Triangle: Shape {
@@ -168,13 +230,16 @@ struct TrendShape: View {
 
     let gradient: AngularGradient
     let color: Color
+    var showArrow: Bool = true
 
     var body: some View {
         HStack(alignment: .center) {
             ZStack {
                 Group {
                     CircleShape(gradient: gradient)
-                    TriangleShape(color: color)
+                    if showArrow {
+                        TriangleShape(color: color)
+                    }
                 }.shadow(color: Color.black.opacity(colorScheme == .dark ? 0.75 : 0.33), radius: colorScheme == .dark ? 5 : 3)
                 CircleShape(gradient: gradient)
             }

+ 18 - 0
Trio/Sources/Modules/Home/View/Header/SensorLifecycle/CGMSensorDisplayState.swift

@@ -0,0 +1,18 @@
+import Foundation
+
+/// Compact `5d 14h` / `22h` / `45m` remaining-time formatter. Used as a
+/// fallback tag label when the CGM doesn't surface a `cgmStatusHighlight`
+/// but the lifecycle progress lets us derive an expiration date.
+enum SensorRemainingTimeFormatter {
+    static func format(until expiresAt: Date, now: Date = Date()) -> String {
+        let remaining = max(0, expiresAt.timeIntervalSince(now))
+        let totalMinutes = Int(remaining / 60)
+        let days = totalMinutes / (60 * 24)
+        let hours = (totalMinutes / 60) % 24
+        let minutes = totalMinutes % 60
+        if days > 0, hours > 0 { return "\(days)d \(hours)h" }
+        if days > 0 { return "\(days)d" }
+        if hours > 0 { return "\(hours)h" }
+        return "\(minutes)m"
+    }
+}

+ 55 - 0
Trio/Sources/Modules/Home/View/Header/SensorLifecycle/SensorLifecycleArcView.swift

@@ -0,0 +1,55 @@
+import LoopKit
+import LoopKitUI
+import SwiftUI
+
+/// Concentric outer ring around the glucose bobble that drains clockwise from
+/// 12 o'clock as the sensor session ages. Always renders a faint track behind
+/// the fill so the indicator's footprint is visible even at `progress == 0`.
+struct SensorLifecycleArcView: View {
+    let progress: Double
+    let progressState: DeviceLifecycleProgressState
+
+    /// Outer diameter — bobble is ~130pt; arc sits 10pt outside the ring stroke.
+    static let diameter: CGFloat = 146
+    static let strokeWidth: CGFloat = 4
+
+    private var arcColor: Color {
+        switch progressState {
+        case .critical:
+            return Color.loopRed
+        case .warning:
+            return Color.orange
+        case .dimmed,
+             .normalCGM,
+             .normalPump:
+            return Color.loopGreen
+        }
+    }
+
+    var body: some View {
+        ZStack {
+            Circle()
+                .stroke(Color.secondary.opacity(0.4), lineWidth: Self.strokeWidth)
+
+            Circle()
+                .trim(from: 0, to: max(0, min(1, progress)))
+                .stroke(arcColor, style: StrokeStyle(lineWidth: Self.strokeWidth, lineCap: .round))
+                .rotationEffect(.degrees(-90))
+                .animation(.easeInOut(duration: 0.25), value: progress)
+        }
+        .frame(width: Self.diameter, height: Self.diameter)
+        .allowsHitTesting(false)
+    }
+}
+
+#Preview("Arc — progress states") {
+    VStack(spacing: 24) {
+        SensorLifecycleArcView(progress: 0.15, progressState: .normalCGM)
+        SensorLifecycleArcView(progress: 0.55, progressState: .normalCGM)
+        SensorLifecycleArcView(progress: 0.92, progressState: .warning)
+        SensorLifecycleArcView(progress: 1.0, progressState: .critical)
+    }
+    .padding(40)
+    .background(Color.black)
+    .preferredColorScheme(.dark)
+}

+ 50 - 0
Trio/Sources/Modules/Home/View/Header/SensorLifecycle/SensorStatusTagView.swift

@@ -0,0 +1,50 @@
+import SwiftUI
+
+/// Status badge below the glucose bobble — text-only, no fill or border.
+struct SensorStatusTagView: View {
+    let text: String
+    let theme: SensorStatusTagTheme
+
+    var body: some View {
+        HStack {
+            Text(text)
+                .font(.callout)
+                .fontWeight(.bold)
+                .fontDesign(.rounded)
+                .foregroundStyle(theme.textColor)
+                .lineLimit(1)
+        }
+        .padding(.vertical, 5)
+        .padding(.horizontal, 10)
+    }
+}
+
+enum SensorStatusTagTheme {
+    case green
+    case orange
+    case red
+    case secondary
+
+    var textColor: Color {
+        switch self {
+        case .green: return Color.loopGreen
+        case .orange: return Color.orange
+        case .red: return Color.loopRed
+        case .secondary: return Color.secondary
+        }
+    }
+}
+
+#Preview("Tag — all themes") {
+    VStack(spacing: 12) {
+        SensorStatusTagView(text: "5d 14h", theme: .green)
+        SensorStatusTagView(text: "22h left", theme: .orange)
+        SensorStatusTagView(text: "warming up", theme: .secondary)
+        SensorStatusTagView(text: "calibrate", theme: .secondary)
+        SensorStatusTagView(text: "sensor expired", theme: .red)
+        SensorStatusTagView(text: "sensor error", theme: .red)
+    }
+    .padding(40)
+    .background(Color.black)
+    .preferredColorScheme(.dark)
+}

+ 4 - 1
Trio/Sources/Modules/Home/View/HomeRootView.swift

@@ -133,7 +133,10 @@ extension Home {
                 cgmAvailable: state.cgmAvailable,
                 currentGlucoseTarget: state.currentGlucoseTarget,
                 glucoseColorScheme: state.glucoseColorScheme,
-                glucose: state.latestTwoGlucoseValues
+                glucose: state.latestTwoGlucoseValues,
+                cgmProgress: state.cgmProgressHighlight,
+                cgmStatus: state.cgmDisplayState,
+                cgmSensorExpiresAt: state.cgmSensorExpiresAt
             ).scaleEffect(0.9)
                 .onTapGesture {
                     if !state.cgmAvailable {

+ 4 - 0
Trio/Sources/Services/Network/Nightscout/NightscoutManager.swift

@@ -1,6 +1,7 @@
 import Combine
 import CoreData
 import Foundation
+import LoopKit
 import LoopKitUI
 import Swinject
 import UIKit
@@ -265,6 +266,9 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
     var glucoseManager: FetchGlucoseManager?
     var cgmManager: CGMManagerUI?
 
+    let cgmDisplayState = CurrentValueSubject<CgmDisplayState?, Never>(nil)
+    let cgmProgressHighlight = CurrentValueSubject<DeviceLifecycleProgress?, Never>(nil)
+
     func fetch(_: DispatchTimer?) -> AnyPublisher<[BloodGlucose], Never> {
         Future { promise in
             Task {