소스 검색

Merge branch 'dev' into refactor-fpu-handling

Deniz Cengiz 2 달 전
부모
커밋
267849faa1

+ 1 - 1
.github/workflows/add_identifiers.yml

@@ -12,7 +12,7 @@ jobs:
   identifiers:
   identifiers:
     name: Add Identifiers
     name: Add Identifiers
     needs: validate
     needs: validate
-    runs-on: macos-15
+    runs-on: macos-26
     steps:
     steps:
       # Checks-out the repo
       # Checks-out the repo
       - name: Checkout Repo
       - name: Checkout Repo

+ 2 - 2
.github/workflows/build_trio.yml

@@ -165,7 +165,7 @@ jobs:
   build:
   build:
     name: Build
     name: Build
     needs: [check_certs, check_status]
     needs: [check_certs, check_status]
-    runs-on: macos-15
+    runs-on: macos-26
     permissions:
     permissions:
       contents: write
       contents: write
     if:
     if:
@@ -175,7 +175,7 @@ jobs:
         (vars.SCHEDULED_SYNC != 'false' && needs.check_status.outputs.NEW_COMMITS == 'true' )
         (vars.SCHEDULED_SYNC != 'false' && needs.check_status.outputs.NEW_COMMITS == 'true' )
     steps:
     steps:
       - name: Select Xcode version
       - name: Select Xcode version
-        run: "sudo xcode-select --switch /Applications/Xcode_16.4.app/Contents/Developer"
+        run: "sudo xcode-select --switch /Applications/Xcode_26.2.app/Contents/Developer"
       
       
       - name: Checkout Repo for building
       - name: Checkout Repo for building
         uses: actions/checkout@v4
         uses: actions/checkout@v4

+ 2 - 2
.github/workflows/create_certs.yml

@@ -21,7 +21,7 @@ jobs:
   create_certs:
   create_certs:
     name: Certificates
     name: Certificates
     needs: validate
     needs: validate
-    runs-on: macos-15
+    runs-on: macos-26
     outputs:
     outputs:
       new_certificate_needed: ${{ steps.set_output.outputs.new_certificate_needed }}
       new_certificate_needed: ${{ steps.set_output.outputs.new_certificate_needed }}
 
 
@@ -90,7 +90,7 @@ jobs:
   nuke_certs:
   nuke_certs:
       name: Nuke certificates
       name: Nuke certificates
       needs: [validate, create_certs]
       needs: [validate, create_certs]
-      runs-on: macos-15
+      runs-on: macos-26
       if: ${{ (needs.create_certs.outputs.new_certificate_needed == 'true' && vars.ENABLE_NUKE_CERTS == 'true') || vars.FORCE_NUKE_CERTS == 'true' }}
       if: ${{ (needs.create_certs.outputs.new_certificate_needed == 'true' && vars.ENABLE_NUKE_CERTS == 'true') || vars.FORCE_NUKE_CERTS == 'true' }}
       steps:
       steps:
         - name: Output from step id 'check_certs'
         - name: Output from step id 'check_certs'

+ 4 - 4
.github/workflows/unit_tests.yml

@@ -23,12 +23,12 @@ on:
 jobs:
 jobs:
   test:
   test:
     name: Run Unit Tests
     name: Run Unit Tests
-    runs-on: macos-15
+    runs-on: macos-26
     if: github.repository_owner == 'nightscout'
     if: github.repository_owner == 'nightscout'
 
 
     steps:
     steps:
       - name: Select Xcode version
       - name: Select Xcode version
-        run: sudo xcode-select -s /Applications/Xcode_16.4.app/Contents/Developer
+        run: sudo xcode-select -s /Applications/Xcode_26.2.app/Contents/Developer
 
 
       - name: Checkout code
       - name: Checkout code
         uses: actions/checkout@v4
         uses: actions/checkout@v4
@@ -64,7 +64,7 @@ jobs:
           time xcodebuild build-for-testing \
           time xcodebuild build-for-testing \
             -workspace Trio.xcworkspace \
             -workspace Trio.xcworkspace \
             -scheme "Trio Tests" \
             -scheme "Trio Tests" \
-            -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.5' \
+            -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.2' \
 
 
       - name: Check for uncommitted changes
       - name: Check for uncommitted changes
         run: |
         run: |
@@ -107,7 +107,7 @@ jobs:
           time xcodebuild test-without-building \
           time xcodebuild test-without-building \
             -workspace Trio.xcworkspace \
             -workspace Trio.xcworkspace \
             -scheme "Trio Tests" \
             -scheme "Trio Tests" \
-            -destination 'platform=iOS Simulator,name=iPhone 16,OS=18.5' \
+            -destination 'platform=iOS Simulator,name=iPhone 17,OS=26.2' \
             $([ "$ENABLE_PARALLEL_TESTING" = "true" ] && echo "-parallel-testing-enabled YES") \
             $([ "$ENABLE_PARALLEL_TESTING" = "true" ] && echo "-parallel-testing-enabled YES") \
             2>&1 | tee xcodebuild.log
             2>&1 | tee xcodebuild.log
 
 

+ 1 - 1
.github/workflows/validate_secrets.yml

@@ -105,7 +105,7 @@ jobs:
   validate-fastlane-secrets:
   validate-fastlane-secrets:
     name: Fastlane
     name: Fastlane
     needs: [validate-access-token]
     needs: [validate-access-token]
-    runs-on: macos-15
+    runs-on: macos-26
     env:
     env:
       GH_PAT: ${{ secrets.GH_PAT }}
       GH_PAT: ${{ secrets.GH_PAT }}
       GH_TOKEN: ${{ secrets.GH_PAT }}
       GH_TOKEN: ${{ secrets.GH_PAT }}

+ 1 - 1
Config.xcconfig

@@ -19,7 +19,7 @@ TRIO_APP_GROUP_ID = group.org.nightscout.$(DEVELOPMENT_TEAM).trio.trio-app-group
 
 
 // The developers set the version numbers, please leave them alone
 // The developers set the version numbers, please leave them alone
 APP_VERSION = 0.6.0
 APP_VERSION = 0.6.0
-APP_DEV_VERSION = 0.6.0.53
+APP_DEV_VERSION = 0.6.0.56
 APP_BUILD_NUMBER = 1
 APP_BUILD_NUMBER = 1
 COPYRIGHT_NOTICE =
 COPYRIGHT_NOTICE =
 
 

+ 4 - 0
Trio.xcodeproj/project.pbxproj

@@ -260,6 +260,7 @@
 		3BD9687F2D8DDD8800899469 /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 3BD9687E2D8DDD8800899469 /* CryptoSwift */; };
 		3BD9687F2D8DDD8800899469 /* CryptoSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 3BD9687E2D8DDD8800899469 /* CryptoSwift */; };
 		3BF85FE32E427312000D7351 /* IOBService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BF85FE12E427312000D7351 /* IOBService.swift */; };
 		3BF85FE32E427312000D7351 /* IOBService.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3BF85FE12E427312000D7351 /* IOBService.swift */; };
 		3E28F2AB2EB5337F00FB9EEB /* ConnectIQ in Frameworks */ = {isa = PBXBuildFile; productRef = 3E28F2AA2EB5337F00FB9EEB /* ConnectIQ */; };
 		3E28F2AB2EB5337F00FB9EEB /* ConnectIQ in Frameworks */ = {isa = PBXBuildFile; productRef = 3E28F2AA2EB5337F00FB9EEB /* ConnectIQ */; };
+		3E62C7822F54CC1B00433237 /* BolusDisplayThreshold.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E62C7812F54CC1600433237 /* BolusDisplayThreshold.swift */; };
 		45252C95D220E796FDB3B022 /* ConfigEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */; };
 		45252C95D220E796FDB3B022 /* ConfigEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3F8A87AA037BD079BA3528BA /* ConfigEditorDataFlow.swift */; };
 		45717281F743594AA9D87191 /* ConfigEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920DDB21E5D0EB813197500D /* ConfigEditorRootView.swift */; };
 		45717281F743594AA9D87191 /* ConfigEditorRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 920DDB21E5D0EB813197500D /* ConfigEditorRootView.swift */; };
 		491D6FBD2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FBC2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift */; };
 		491D6FBD2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift in Sources */ = {isa = PBXBuildFile; fileRef = 491D6FBC2D56741C00C49F67 /* TempTargetStored+CoreDataProperties.swift */; };
@@ -1090,6 +1091,7 @@
 		3BDEA2DC60EDE0A3CA54DC73 /* TargetsEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetsEditorProvider.swift; sourceTree = "<group>"; };
 		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>"; };
 		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>"; };
 		3BF85FE12E427312000D7351 /* IOBService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IOBService.swift; sourceTree = "<group>"; };
+		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>"; };
 		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>"; };
 		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>"; };
 		42369F66CF91F30624C0B3A6 /* BasalProfileEditorProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorProvider.swift; sourceTree = "<group>"; };
@@ -2369,6 +2371,7 @@
 		388E5A5925B6F0250019842D /* Models */ = {
 		388E5A5925B6F0250019842D /* Models */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				3E62C7812F54CC1600433237 /* BolusDisplayThreshold.swift */,
 				DD3D60302F0377350021A33B /* ExportSetting.swift */,
 				DD3D60302F0377350021A33B /* ExportSetting.swift */,
 				DDFF204F2DB2C11900AB8A96 /* WatchStateSnapshot.swift */,
 				DDFF204F2DB2C11900AB8A96 /* WatchStateSnapshot.swift */,
 				DDEBB05B2D89E9050032305D /* TimeInRangeType.swift */,
 				DDEBB05B2D89E9050032305D /* TimeInRangeType.swift */,
@@ -4360,6 +4363,7 @@
 				CEE9A6592BBB418300EB5194 /* CalibrationsDataFlow.swift in Sources */,
 				CEE9A6592BBB418300EB5194 /* CalibrationsDataFlow.swift in Sources */,
 				3811DE3525C9D49500A708ED /* HomeRootView.swift in Sources */,
 				3811DE3525C9D49500A708ED /* HomeRootView.swift in Sources */,
 				38E98A2925F52C9300C0CED0 /* Error+Extensions.swift in Sources */,
 				38E98A2925F52C9300C0CED0 /* Error+Extensions.swift in Sources */,
+				3E62C7822F54CC1B00433237 /* BolusDisplayThreshold.swift in Sources */,
 				38EA05DA261F6E7C0064E39B /* SimpleLogReporter.swift in Sources */,
 				38EA05DA261F6E7C0064E39B /* SimpleLogReporter.swift in Sources */,
 				3811DE6125C9D4D500A708ED /* ViewModifiers.swift in Sources */,
 				3811DE6125C9D4D500A708ED /* ViewModifiers.swift in Sources */,
 				3811DEAC25C9D88300A708ED /* NightscoutManager.swift in Sources */,
 				3811DEAC25C9D88300A708ED /* NightscoutManager.swift in Sources */,

+ 25 - 0
Trio/Sources/Localizations/Main/Localizable.xcstrings

@@ -10179,6 +10179,7 @@
       }
       }
     },
     },
     "%lld h" : {
     "%lld h" : {
+      "extractionState" : "stale",
       "localizations" : {
       "localizations" : {
         "bg" : {
         "bg" : {
           "stringUnit" : {
           "stringUnit" : {
@@ -19986,6 +19987,18 @@
         }
         }
       }
       }
     },
     },
+    "0.1 U and over" : {
+      "comment" : "Display name for the \"0.1 U and over\" option in the bolus display threshold settings.",
+      "isCommentAutoGenerated" : true
+    },
+    "0.5 U and over" : {
+      "comment" : "Display name for the \"0. 5U and over\" option in the bolus display threshold settings.",
+      "isCommentAutoGenerated" : true
+    },
+    "1 U and over" : {
+      "comment" : "Name for the \"1 U and over\" option in the bolus display threshold settings.",
+      "isCommentAutoGenerated" : true
+    },
     "1. Open the Settings app on your iOS device." : {
     "1. Open the Settings app on your iOS device." : {
       "localizations" : {
       "localizations" : {
         "bg" : {
         "bg" : {
@@ -55582,6 +55595,9 @@
         }
         }
       }
       }
     },
     },
+    "Bolus Display Threshold" : {
+
+    },
     "Bolus Distribution" : {
     "Bolus Distribution" : {
       "localizations" : {
       "localizations" : {
         "bg" : {
         "bg" : {
@@ -66527,6 +66543,9 @@
         }
         }
       }
       }
     },
     },
+    "Choose to hide small bolus amounts. See hint for more details." : {
+
+    },
     "Choose Trio's appearance. See hint for more details." : {
     "Choose Trio's appearance. See hint for more details." : {
       "localizations" : {
       "localizations" : {
         "bg" : {
         "bg" : {
@@ -208276,6 +208295,9 @@
         }
         }
       }
       }
     },
     },
+    "Show All" : {
+
+    },
     "Show carbs required as a red icon on the main graph icon." : {
     "Show carbs required as a red icon on the main graph icon." : {
       "localizations" : {
       "localizations" : {
         "bg" : {
         "bg" : {
@@ -238898,6 +238920,9 @@
         }
         }
       }
       }
     },
     },
+    "This setting controls which bolus amount labels are shown on Trio’s main chart. Boluses appear as blue upside-down triangles, with a number showing the amount. Depending on the option you choose, only boluses at or above that amount will show a label. For example, if you choose ‘0.5 U and over’, only boluses of 0.5 U or more will show a label." : {
+
+    },
     "This setting defines the maximum amount of Carbs On Board (COB) at any given time for Trio to use in dosing calculations. If more carbs are entered than allowed by this limit, Trio will cap the current COB in calculations to Max COB and remain at max until all remaining carbs have shown to be absorbed." : {
     "This setting defines the maximum amount of Carbs On Board (COB) at any given time for Trio to use in dosing calculations. If more carbs are entered than allowed by this limit, Trio will cap the current COB in calculations to Max COB and remain at max until all remaining carbs have shown to be absorbed." : {
       "localizations" : {
       "localizations" : {
         "bg" : {
         "bg" : {

+ 22 - 0
Trio/Sources/Models/BolusDisplayThreshold.swift

@@ -0,0 +1,22 @@
+import Foundation
+
+enum BolusDisplayThreshold: Decimal, CaseIterable, Encodable, Identifiable {
+    public var id: Decimal { rawValue }
+    case oneUnit = 1
+    case halfUnit = 0.5
+    case pointOneUnit = 0.1
+    case allUnits = 0.01
+
+    var displayName: String {
+        switch self {
+        case .oneUnit:
+            return String(localized: "1 U and over")
+        case .halfUnit:
+            return String(localized: "0.5 U and over")
+        case .pointOneUnit:
+            return String(localized: "0.1 U and over")
+        case .allUnits:
+            return String(localized: "Show All")
+        }
+    }
+}

+ 1 - 0
Trio/Sources/Models/TrioSettings.swift

@@ -54,6 +54,7 @@ struct TrioSettings: JSON, Equatable {
     var xGridLines: Bool = true
     var xGridLines: Bool = true
     var yGridLines: Bool = true
     var yGridLines: Bool = true
     var rulerMarks: Bool = true
     var rulerMarks: Bool = true
+    var bolusDisplayThreshold: BolusDisplayThreshold = .allUnits
     var forecastDisplayType: ForecastDisplayType = .cone
     var forecastDisplayType: ForecastDisplayType = .cone
     var maxCarbs: Decimal = 250
     var maxCarbs: Decimal = 250
     var maxFat: Decimal = 250
     var maxFat: Decimal = 250

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

@@ -76,6 +76,7 @@ extension Home {
         var displayXgridLines: Bool = false
         var displayXgridLines: Bool = false
         var displayYgridLines: Bool = false
         var displayYgridLines: Bool = false
         var thresholdLines: Bool = false
         var thresholdLines: Bool = false
+        var bolusDisplayThreshold: BolusDisplayThreshold = .allUnits
         var hours: Int16 = 6
         var hours: Int16 = 6
         var totalBolus: Decimal = 0
         var totalBolus: Decimal = 0
         var isLoopStatusPresented: Bool = false
         var isLoopStatusPresented: Bool = false
@@ -404,6 +405,7 @@ extension Home {
             eA1cDisplayUnit = settingsManager.settings.eA1cDisplayUnit
             eA1cDisplayUnit = settingsManager.settings.eA1cDisplayUnit
             displayXgridLines = settingsManager.settings.xGridLines
             displayXgridLines = settingsManager.settings.xGridLines
             displayYgridLines = settingsManager.settings.yGridLines
             displayYgridLines = settingsManager.settings.yGridLines
+            bolusDisplayThreshold = settingsManager.settings.bolusDisplayThreshold
             thresholdLines = settingsManager.settings.rulerMarks
             thresholdLines = settingsManager.settings.rulerMarks
             showCarbsRequiredBadge = settingsManager.settings.showCarbsRequiredBadge
             showCarbsRequiredBadge = settingsManager.settings.showCarbsRequiredBadge
             forecastDisplayType = settingsManager.settings.forecastDisplayType
             forecastDisplayType = settingsManager.settings.forecastDisplayType
@@ -668,6 +670,7 @@ extension Home.StateModel:
         displayXgridLines = settingsManager.settings.xGridLines
         displayXgridLines = settingsManager.settings.xGridLines
         displayYgridLines = settingsManager.settings.yGridLines
         displayYgridLines = settingsManager.settings.yGridLines
         thresholdLines = settingsManager.settings.rulerMarks
         thresholdLines = settingsManager.settings.rulerMarks
+        bolusDisplayThreshold = settingsManager.settings.bolusDisplayThreshold
         showCarbsRequiredBadge = settingsManager.settings.showCarbsRequiredBadge
         showCarbsRequiredBadge = settingsManager.settings.showCarbsRequiredBadge
         forecastDisplayType = settingsManager.settings.forecastDisplayType
         forecastDisplayType = settingsManager.settings.forecastDisplayType
         cgmAvailable = (fetchGlucoseManager.cgmGlucoseSourceType != CGMType.none)
         cgmAvailable = (fetchGlucoseManager.cgmGlucoseSourceType != CGMType.none)

+ 6 - 3
Trio/Sources/Modules/Home/View/Chart/ChartElements/InsulinView.swift

@@ -6,6 +6,7 @@ struct InsulinView: ChartContent {
     let glucoseData: [GlucoseStored]
     let glucoseData: [GlucoseStored]
     let insulinData: [PumpEventStored]
     let insulinData: [PumpEventStored]
     let units: GlucoseUnits
     let units: GlucoseUnits
+    let bolusDisplayThreshold: BolusDisplayThreshold
 
 
     var body: some ChartContent {
     var body: some ChartContent {
         drawBoluses()
         drawBoluses()
@@ -32,9 +33,11 @@ struct InsulinView: ChartContent {
                     Image(systemName: "arrowtriangle.down.fill").font(.system(size: size)).foregroundStyle(Color.insulin)
                     Image(systemName: "arrowtriangle.down.fill").font(.system(size: size)).foregroundStyle(Color.insulin)
                 }
                 }
                 .annotation(position: .top) {
                 .annotation(position: .top) {
-                    Text(Formatter.bolusFormatter.string(from: amount) ?? "")
-                        .font(.caption2)
-                        .foregroundStyle(Color.primary)
+                    if amount as Decimal >= bolusDisplayThreshold.rawValue {
+                        Text(Formatter.bolusFormatter.string(from: amount) ?? "")
+                            .font(.caption2)
+                            .foregroundStyle(Color.primary)
+                    }
                 }
                 }
             }
             }
         }
         }

+ 2 - 1
Trio/Sources/Modules/Home/View/Chart/MainChartView.swift

@@ -149,7 +149,8 @@ extension MainChartView {
                 InsulinView(
                 InsulinView(
                     glucoseData: state.glucoseFromPersistence,
                     glucoseData: state.glucoseFromPersistence,
                     insulinData: state.insulinFromPersistence,
                     insulinData: state.insulinFromPersistence,
-                    units: state.units
+                    units: state.units,
+                    bolusDisplayThreshold: state.bolusDisplayThreshold
                 )
                 )
 
 
                 CarbView(
                 CarbView(

+ 1 - 0
Trio/Sources/Modules/Settings/SettingItems.swift

@@ -230,6 +230,7 @@ enum SettingItems {
                 "Show Carbs Required Badge",
                 "Show Carbs Required Badge",
                 "Carbs Required Threshold",
                 "Carbs Required Threshold",
                 "Forecast Display Type",
                 "Forecast Display Type",
+                "Bolus Display Threshold",
                 "Cone",
                 "Cone",
                 "Lines",
                 "Lines",
                 "Dark Mode",
                 "Dark Mode",

+ 2 - 0
Trio/Sources/Modules/UserInterfaceSettings/UserInterfaceSettingsStateModel.swift

@@ -7,6 +7,7 @@ extension UserInterfaceSettings {
         @Published var xGridLines = false
         @Published var xGridLines = false
         @Published var yGridLines: Bool = false
         @Published var yGridLines: Bool = false
         @Published var rulerMarks: Bool = true
         @Published var rulerMarks: Bool = true
+        @Published var bolusDisplayThreshold: BolusDisplayThreshold = .allUnits
         @Published var forecastDisplayType: ForecastDisplayType = .cone
         @Published var forecastDisplayType: ForecastDisplayType = .cone
         @Published var showCarbsRequiredBadge: Bool = true
         @Published var showCarbsRequiredBadge: Bool = true
         @Published var carbsRequiredThreshold: Decimal = 0
         @Published var carbsRequiredThreshold: Decimal = 0
@@ -23,6 +24,7 @@ extension UserInterfaceSettings {
             subscribeSetting(\.xGridLines, on: $xGridLines) { xGridLines = $0 }
             subscribeSetting(\.xGridLines, on: $xGridLines) { xGridLines = $0 }
             subscribeSetting(\.yGridLines, on: $yGridLines) { yGridLines = $0 }
             subscribeSetting(\.yGridLines, on: $yGridLines) { yGridLines = $0 }
             subscribeSetting(\.rulerMarks, on: $rulerMarks) { rulerMarks = $0 }
             subscribeSetting(\.rulerMarks, on: $rulerMarks) { rulerMarks = $0 }
+            subscribeSetting(\.bolusDisplayThreshold, on: $bolusDisplayThreshold) { bolusDisplayThreshold = $0 }
 
 
             subscribeSetting(\.forecastDisplayType, on: $forecastDisplayType) { forecastDisplayType = $0 }
             subscribeSetting(\.forecastDisplayType, on: $forecastDisplayType) { forecastDisplayType = $0 }
 
 

+ 42 - 0
Trio/Sources/Modules/UserInterfaceSettings/View/UserInterfaceSettingsRootView.swift

@@ -376,6 +376,48 @@ extension UserInterfaceSettings {
                     }.padding(.bottom)
                     }.padding(.bottom)
                 }.listRowBackground(Color.chart)
                 }.listRowBackground(Color.chart)
 
 
+                Section {
+                    VStack {
+                        Picker(
+                            selection: $state.bolusDisplayThreshold,
+                            label: Text("Bolus Display Threshold")
+                        ) {
+                            ForEach(BolusDisplayThreshold.allCases) { selection in
+                                Text(selection.displayName).tag(selection)
+                            }
+                        }.padding(.top)
+
+                        HStack(alignment: .center) {
+                            Text(
+                                "Choose to hide small bolus amounts. See hint for more details."
+                            )
+                            .font(.footnote)
+                            .foregroundColor(.secondary)
+                            .lineLimit(nil)
+                            Spacer()
+                            Button(
+                                action: {
+                                    hintLabel = String(localized: "Bolus Display Threshold")
+                                    selectedVerboseHint =
+                                        AnyView(
+                                            VStack(alignment: .leading) {
+                                                Text(
+                                                    "This setting controls which bolus amount labels are shown on Trio’s main chart. Boluses appear as blue upside-down triangles, with a number showing the amount. Depending on the option you choose, only boluses at or above that amount will show a label. For example, if you choose ‘0.5 U and over’, only boluses of 0.5 U or more will show a label."
+                                                )
+                                            }
+                                        )
+                                    shouldDisplayHint.toggle()
+                                },
+                                label: {
+                                    HStack {
+                                        Image(systemName: "questionmark.circle")
+                                    }
+                                }
+                            ).buttonStyle(BorderlessButtonStyle())
+                        }.padding(.top)
+                    }.padding(.bottom)
+                }.listRowBackground(Color.chart)
+
                 Section(
                 Section(
                     header: Text("Trio Statistics"),
                     header: Text("Trio Statistics"),
                     content: {
                     content: {