Quellcode durchsuchen

Merge branch 'dev' into Crowdin

Jon B.M vor 2 Jahren
Ursprung
Commit
9697dd35b1
58 geänderte Dateien mit 299 neuen und 149 gelöschten Zeilen
  1. 1 1
      .github/FUNDING.yml
  2. 2 1
      Config.xcconfig
  3. 2 2
      FreeAPS.xcodeproj/project.pbxproj
  4. 1 0
      FreeAPS/Resources/Info.plist
  5. 1 1
      FreeAPS/Resources/javascript/bundle/determine-basal.js
  6. 1 1
      FreeAPS/Resources/javascript/bundle/profile.js
  7. 2 2
      FreeAPS/Resources/javascript/prepare/autotune-prep.js
  8. 1 1
      FreeAPS/Resources/javascript/prepare/meal.js
  9. 44 40
      FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json
  10. 53 0
      FreeAPS/Resources/json/defaults/preferences.json
  11. 1 1
      FreeAPS/Resources/json/defaults/settings/bg_targets.json
  12. 28 18
      FreeAPS/Sources/APS/CGM/DexcomSourceG6.swift
  13. 3 2
      FreeAPS/Sources/APS/Storage/PumpHistoryStorage.swift
  14. 1 1
      FreeAPS/Sources/Localizations/Main/ar.lproj/Localizable.strings
  15. 1 1
      FreeAPS/Sources/Localizations/Main/ca.lproj/Localizable.strings
  16. 1 1
      FreeAPS/Sources/Localizations/Main/da.lproj/Localizable.strings
  17. 1 1
      FreeAPS/Sources/Localizations/Main/de.lproj/Localizable.strings
  18. 4 1
      FreeAPS/Sources/Localizations/Main/en.lproj/Localizable.strings
  19. 1 1
      FreeAPS/Sources/Localizations/Main/es.lproj/Localizable.strings
  20. 1 1
      FreeAPS/Sources/Localizations/Main/fi.lproj/Localizable.strings
  21. 1 1
      FreeAPS/Sources/Localizations/Main/fr.lproj/Localizable.strings
  22. 1 1
      FreeAPS/Sources/Localizations/Main/he.lproj/Localizable.strings
  23. 1 1
      FreeAPS/Sources/Localizations/Main/it.lproj/Localizable.strings
  24. 1 1
      FreeAPS/Sources/Localizations/Main/nb.lproj/Localizable.strings
  25. 1 1
      FreeAPS/Sources/Localizations/Main/nl.lproj/Localizable.strings
  26. 1 1
      FreeAPS/Sources/Localizations/Main/pl.lproj/Localizable.strings
  27. 1 1
      FreeAPS/Sources/Localizations/Main/pt-BR.lproj/Localizable.strings
  28. 1 1
      FreeAPS/Sources/Localizations/Main/pt-PT.lproj/Localizable.strings
  29. 1 1
      FreeAPS/Sources/Localizations/Main/ru.lproj/Localizable.strings
  30. 1 1
      FreeAPS/Sources/Localizations/Main/sk.lproj/Localizable.strings
  31. 2 2
      FreeAPS/Sources/Localizations/Main/sv.lproj/Localizable.strings
  32. 1 1
      FreeAPS/Sources/Localizations/Main/tr.lproj/Localizable.strings
  33. 1 1
      FreeAPS/Sources/Localizations/Main/uk.lproj/Localizable.strings
  34. 1 1
      FreeAPS/Sources/Localizations/Main/zh-Hans.lproj/Localizable.strings
  35. 1 1
      FreeAPS/Sources/Models/AlertEntry.swift
  36. 1 1
      FreeAPS/Sources/Models/Announcement.swift
  37. 1 1
      FreeAPS/Sources/Models/CarbsEntry.swift
  38. 10 0
      FreeAPS/Sources/Models/FreeAPSSettings.swift
  39. 1 1
      FreeAPS/Sources/Models/NightscoutTreatment.swift
  40. 3 3
      FreeAPS/Sources/Models/Preferences.swift
  41. 6 1
      FreeAPS/Sources/Models/PumpHistoryEvent.swift
  42. 1 1
      FreeAPS/Sources/Models/TempTarget.swift
  43. 4 0
      FreeAPS/Sources/Modules/CGM/CGMStateModel.swift
  44. 3 1
      FreeAPS/Sources/Modules/CGM/View/CGMRootView.swift
  45. 1 1
      FreeAPS/Sources/Modules/CREditor/CREditorStateModel.swift
  46. 19 10
      FreeAPS/Sources/Modules/DataTable/DataTableDataFlow.swift
  47. 8 1
      FreeAPS/Sources/Modules/DataTable/DataTableStateModel.swift
  48. 2 1
      FreeAPS/Sources/Modules/DataTable/View/DataTableRootView.swift
  49. 1 2
      FreeAPS/Sources/Modules/OverrideProfilesConfig/View/OverrideProfilesRootView.swift
  50. 1 0
      FreeAPS/Sources/Modules/Snooze/View/SnoozeRootView.swift
  51. 2 2
      FreeAPS/Sources/Modules/Stat/View/ChartsView.swift
  52. 43 2
      FreeAPS/Sources/Services/Calendar/CalendarManager.swift
  53. 1 1
      FreeAPS/Sources/Services/Network/NightscoutAPI.swift
  54. 15 18
      FreeAPS/Sources/Services/UserNotifiactions/UserNotificationsManager.swift
  55. 2 1
      FreeAPS/Sources/Views/TagCloudView.swift
  56. 2 2
      FreeAPSWatch WatchKit Extension/Views/BolusConfirmationView.swift
  57. 1 1
      README.md
  58. 5 5
      fastlane/testflight.md

+ 1 - 1
.github/FUNDING.yml

@@ -1,3 +1,3 @@
 # These are supported funding model platforms
 # These are supported funding model platforms
 
 
-custom: ["https://paypal.me/jonbm78?country.x=SE&locale.x=sv_SE"]
+custom: ["https://paypal.me/jonbm78", "https://www.paypal.com/paypalme/jonbm78"]

+ 2 - 1
Config.xcconfig

@@ -1,11 +1,12 @@
 APP_DISPLAY_NAME = iAPS
 APP_DISPLAY_NAME = iAPS
-APP_VERSION = 2.2.2
+APP_VERSION = 2.2.5
 APP_BUILD_NUMBER = 1
 APP_BUILD_NUMBER = 1
 COPYRIGHT_NOTICE =
 COPYRIGHT_NOTICE =
 DEVELOPER_TEAM = ##TEAM_ID##
 DEVELOPER_TEAM = ##TEAM_ID##
 BUNDLE_IDENTIFIER = ru.artpancreas.$(DEVELOPMENT_TEAM).FreeAPS
 BUNDLE_IDENTIFIER = ru.artpancreas.$(DEVELOPMENT_TEAM).FreeAPS
 APP_GROUP_ID = group.com.$(DEVELOPMENT_TEAM).loopkit.LoopGroup
 APP_GROUP_ID = group.com.$(DEVELOPMENT_TEAM).loopkit.LoopGroup
 APP_ICON = pod_colorful
 APP_ICON = pod_colorful
+APP_URL_SCHEME = freeaps-x
 
 
 #include? "ConfigOverride.xcconfig"
 #include? "ConfigOverride.xcconfig"
 //#include? "../../ConfigOverride.xcconfig"
 //#include? "../../ConfigOverride.xcconfig"

+ 2 - 2
FreeAPS.xcodeproj/project.pbxproj

@@ -2254,11 +2254,11 @@
 			buildPhases = (
 			buildPhases = (
 				3811DEF525CA169200A708ED /* Swiftformat */,
 				3811DEF525CA169200A708ED /* Swiftformat */,
 				388E595425AD948C0019842D /* Sources */,
 				388E595425AD948C0019842D /* Sources */,
-				B99D8B8E295F34DB00420AB8 /* Run Script */,
 				388E595525AD948C0019842D /* Frameworks */,
 				388E595525AD948C0019842D /* Frameworks */,
 				388E595625AD948C0019842D /* Resources */,
 				388E595625AD948C0019842D /* Resources */,
 				3821ECD025DC703C00BC42AD /* Embed Frameworks */,
 				3821ECD025DC703C00BC42AD /* Embed Frameworks */,
 				38E8753D27554D5900975559 /* Embed Watch Content */,
 				38E8753D27554D5900975559 /* Embed Watch Content */,
+				B99D8B8E295F34DB00420AB8 /* Run Script */,
 			);
 			);
 			buildRules = (
 			buildRules = (
 			);
 			);
@@ -2484,7 +2484,7 @@
 			);
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 			runOnlyForDeploymentPostprocessing = 0;
 			shellPath = /bin/sh;
 			shellPath = /bin/sh;
-			shellScript = "git_version=$(git log -1 --format=\"%h\")\ngit_branch=$(git symbolic-ref --short -q HEAD)\ngit_tag=$(git describe --tags --exact-match 2>/dev/null)\n\ngit_branch_or_tag=\"${git_branch:-${git_tag}}\"\ngit_branch_or_tag_version=\"${git_branch:-${git_tag}} ${git_version}\"\n\ninfo_plist=\"${SRCROOT}/FreeAPS/Resources/Info.plist\"\n\n/usr/libexec/PlistBuddy -c \"Set :BuildBranch '${git_branch_or_tag_version}'\" \"${info_plist}\"\n";
+			shellScript = "#!/bin/sh\n\ngit_version=$(git log -1 --format=\"%h\")\ngit_branch=$(git symbolic-ref --short -q HEAD)\ngit_tag=$(git describe --tags --exact-match 2>/dev/null)\n\ngit_branch_or_tag=\"${git_branch:-${git_tag}}\"\ngit_branch_or_tag_version=\"${git_branch:-${git_tag}} ${git_version}\"\n\ninfo_plist=\"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\n\n/usr/libexec/PlistBuddy -c \"Set :BuildBranch '${git_branch_or_tag_version}'\" \"${info_plist}\"\n";
 		};
 		};
 /* End PBXShellScriptBuildPhase section */
 /* End PBXShellScriptBuildPhase section */
 
 

+ 1 - 0
FreeAPS/Resources/Info.plist

@@ -37,6 +37,7 @@
 			<string>com.artificial-pancreas-iaps</string>
 			<string>com.artificial-pancreas-iaps</string>
 			<key>CFBundleURLSchemes</key>
 			<key>CFBundleURLSchemes</key>
 			<array>
 			<array>
+				<string>$(APP_URL_SCHEME)</string>
 				<string>freeaps-x</string>
 				<string>freeaps-x</string>
 			</array>
 			</array>
 		</dict>
 		</dict>

Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
FreeAPS/Resources/javascript/bundle/determine-basal.js


Datei-Diff unterdrückt, da er zu groß ist
+ 1 - 1
FreeAPS/Resources/javascript/bundle/profile.js


+ 2 - 2
FreeAPS/Resources/javascript/prepare/autotune-prep.js

@@ -1,6 +1,6 @@
 function generate(pumphistory_data, profile_data, glucose_data, pumpprofile_data, carb_data = {} , categorize_uam_as_basal = false, tune_insulin_curve = false) {
 function generate(pumphistory_data, profile_data, glucose_data, pumpprofile_data, carb_data = {} , categorize_uam_as_basal = false, tune_insulin_curve = false) {
-    if (typeof(profile_data.carb_ratio) === 'undefined' || profile_data.carb_ratio < 1) {
-        if (typeof(pumpprofile_data.carb_ratio) === 'undefined' || pumpprofile_data.carb_ratio < 1) {
+    if (typeof(profile_data.carb_ratio) === 'undefined' || profile_data.carb_ratio < 0.1) {
+        if (typeof(pumpprofile_data.carb_ratio) === 'undefined' || pumpprofile_data.carb_ratio < 0.1) {
             console.log('{ "carbs": 0, "mealCOB": 0, "reason": "carb_ratios ' + profile_data.carb_ratio + ' and ' + pumpprofile_data.carb_ratio + ' out of bounds" }');
             console.log('{ "carbs": 0, "mealCOB": 0, "reason": "carb_ratios ' + profile_data.carb_ratio + ' and ' + pumpprofile_data.carb_ratio + ' out of bounds" }');
             return console.error("Error: carb_ratios " + profile_data.carb_ratio + ' and ' + pumpprofile_data.carb_ratio + " out of bounds");
             return console.error("Error: carb_ratios " + profile_data.carb_ratio + ' and ' + pumpprofile_data.carb_ratio + " out of bounds");
         } else {
         } else {

+ 1 - 1
FreeAPS/Resources/javascript/prepare/meal.js

@@ -1,7 +1,7 @@
 //для monitor/meal.json параметры: monitor/pumphistory-24h-zoned.json settings/profile.json monitor/clock-zoned.json monitor/glucose.json settings/basal_profile.json monitor/carbhistory.json
 //для monitor/meal.json параметры: monitor/pumphistory-24h-zoned.json settings/profile.json monitor/clock-zoned.json monitor/glucose.json settings/basal_profile.json monitor/carbhistory.json
 
 
 function generate(pumphistory_data, profile_data, clock_data, glucose_data, basalprofile_data, carbhistory = false) {
 function generate(pumphistory_data, profile_data, clock_data, glucose_data, basalprofile_data, carbhistory = false) {
-    if (typeof(profile_data.carb_ratio) === 'undefined' || profile_data.carb_ratio < 1) {
+    if (typeof(profile_data.carb_ratio) === 'undefined' || profile_data.carb_ratio < 0.1) {
         return {"error":"Error: carb_ratio " + profile_data.carb_ratio + " out of bounds"};
         return {"error":"Error: carb_ratio " + profile_data.carb_ratio + " out of bounds"};
     }
     }
 
 

+ 44 - 40
FreeAPS/Resources/json/defaults/freeaps/freeaps_settings.json

@@ -1,42 +1,46 @@
 {
 {
-    "useAlarmSound" : false,
-      "uploadStats" : false,
-      "useCalendar" : false,
-      "rulerMarks" : false,
-      "individualAdjustmentFactor" : 0.5,
-      "low" : 70,
-      "displayHR" : true,
-      "localGlucosePort" : 8080,
-      "uploadGlucose" : true,
-      "allowAnnouncements" : false,
-      "debugOptions" : false,
-      "useAppleHealth" : false,
-      "high" : 170,
-      "yGridLines" : true,
-      "useLocalGlucoseSource" : false,
-      "closedLoop" : false,
-      "units" : "mmol/L",
-      "xGridLines" : true,
-      "lowGlucose" : 70,
-      "oneDimensionalGraph" : false,
-      "glucoseNotificationsAlways" : false,
-      "addSourceInfoToGlucoseNotifications" : false,
-      "cgm" : "nightscout",
-      "glucoseBadge" : true,
-      "overrideHbA1cUnit" : false,
-      "delay" : 80,
-      "smoothGlucose" : false,
-      "skipBolusScreenAfterCarbs" : false,
-      "highGlucose" : 220,
-      "timeCap" : 8,
-      "minuteInterval" : 20,
-      "isUploadEnabled" : true,
-      "useAutotune" : false,
-      "hours" : 6,
-      "carbsRequiredThreshold" : 50,
-      "insulinReqPercentage" : 80,
-      "useFPUconversion" : false,
-      "displayOnWatch" : "HR",
-      "animatedBackground" : false
-      "maxCarbs": 1000
+  "units" : "mmol/L",
+  "closedLoop" : false,
+  "allowAnnouncements" : false,
+  "useAutotune" : false,
+  "onlyAutotuneBasals" : false,
+  "isUploadEnabled" : false,
+  "useLocalGlucoseSource" : false,
+  "localGlucosePort" : 8080,
+  "debugOptions" : false,
+  "insulinReqPercentage" : 70,
+  "skipBolusScreenAfterCarbs" : false,
+  "displayHR" : false,
+  "cgm" : "nightscout",
+  "uploadGlucose" : true,
+  "useCalendar" : false,
+  "displayCalendarEmojis" : false,
+  "displayCalendarIOBandCOB" : false,
+  "glucoseBadge" : false,
+  "glucoseNotificationsAlways" : false,
+  "useAlarmSound" : false,
+  "addSourceInfoToGlucoseNotifications" : false,
+  "lowGlucose" : 72,
+  "highGlucose" : 270,
+  "carbsRequiredThreshold" : 10,
+  "animatedBackground" : false,
+  "useFPUconversion" : true,
+  "individualAdjustmentFactor" : 0.5,
+  "timeCap" : 8,
+  "minuteInterval" : 30,
+  "delay" : 60,
+  "useAppleHealth" : false,
+  "smoothGlucose" : false,
+  "displayOnWatch" : "BGTarget",
+  "overrideHbA1cUnit" : false,
+  "high" : 145,
+  "low" : 70,
+  "uploadStats" : true,
+  "hours" : 6,
+  "xGridLines" : true,
+  "yGridLines" : true,
+  "oneDimensionalGraph" : false,
+  "rulerMarks" : false,
+  "maxCarbs": 1000,
+  "displayFatAndProteinOnWatch": false
 }
 }

+ 53 - 0
FreeAPS/Resources/json/defaults/preferences.json

@@ -0,0 +1,53 @@
+{
+  "max_iob" : 0,
+  "max_daily_safety_multiplier" : 3,
+  "current_basal_safety_multiplier" : 4,
+  "autosens_max" : 1.2,
+  "autosens_min" : 0.7,
+  "smb_delivery_ratio" : 0.5,
+  "rewind_resets_autosens" : true,
+  "high_temptarget_raises_sensitivity" : false,
+  "low_temptarget_lowers_sensitivity" : false,
+  "sensitivity_raises_target" : true,
+  "resistanceLowersTarget" : false,
+  "adv_target_adjustments" : false,
+  "exercise_mode" : false,
+  "half_basal_exercise_target" : 160,
+  "maxCOB" : 120,
+  "wide_bg_target_range" : false,
+  "skip_neutral_temps" : false,
+  "unsuspend_if_no_temp" : false,
+  "min_5m_carbimpact" : 8,
+  "autotune_isf_adjustmentFraction" : 1,
+  "remainingCarbsFraction" : 1,
+  "remainingCarbsCap" : 90,
+  "enableUAM" : false,
+  "A52_risk_enable" : false,
+  "enableSMB_with_COB" : false,
+  "enableSMB_with_temptarget" : false,
+  "enableSMB_always" : false,
+  "enableSMB_after_carbs" : false,
+  "allowSMB_with_high_temptarget" : false,
+  "maxSMBBasalMinutes" : 30,
+  "maxUAMSMBBasalMinutes" : 30,
+  "SMBInterval" : 3,
+  "bolus_increment" : 0.1,
+  "curve" : "rapid-acting",
+  "useCustomPeakTime" : false,
+  "insulinPeakTime" : 75,
+  "carbsReqThreshold" : 1,
+  "noisyCGMTargetMultiplier" : 1.3,
+  "suspend_zeros_iob" : false,
+  "maxDelta_bg_threshold" : 0.2,
+  "adjustmentFactor" : 0.5,
+  "sigmoid" : false,
+  "enableDynamicCR" : false,
+  "useNewFormula" : false,
+  "useWeightedAverage" : false,
+  "weightPercentage" : 0.65,
+  "tddAdjBasal" : false,
+  "enableSMB_high_bg" : false,
+  "enableSMB_high_bg_target" : 110,
+  "threshold_setting" : 65,
+  "updateInterval" : 20
+}

+ 1 - 1
FreeAPS/Resources/json/defaults/settings/bg_targets.json

@@ -4,7 +4,7 @@
     "targets": [
     "targets": [
         {
         {
             "low": 5.5,
             "low": 5.5,
-            "high": 6.0,
+            "high": 5.5,
             "start": "00:00:00",
             "start": "00:00:00",
             "offset": 0
             "offset": 0
         }
         }

+ 28 - 18
FreeAPS/Sources/APS/CGM/DexcomSourceG6.swift

@@ -145,25 +145,35 @@ extension DexcomSourceG6: CGMManagerDelegate {
         debug(.deviceManager, "DEXCOM - Process CGM Reading Result launched with \(readingResult)")
         debug(.deviceManager, "DEXCOM - Process CGM Reading Result launched with \(readingResult)")
         switch readingResult {
         switch readingResult {
         case let .newData(values):
         case let .newData(values):
-            let bloodGlucose = values.compactMap { newGlucoseSample -> BloodGlucose? in
-                let quantity = newGlucoseSample.quantity
-                let value = Int(quantity.doubleValue(for: .milligramsPerDeciliter))
-                return BloodGlucose(
-                    _id: newGlucoseSample.syncIdentifier,
-                    sgv: value,
-                    direction: .init(trendType: newGlucoseSample.trend),
-                    date: Decimal(Int(newGlucoseSample.date.timeIntervalSince1970 * 1000)),
-                    dateString: newGlucoseSample.date,
-                    unfiltered: Decimal(value),
-                    filtered: nil,
-                    noise: nil,
-                    glucose: value,
-                    type: "sgv",
-                    transmitterID: self.transmitterID
-                )
+            if let cgmG6Manager = cgmManager as? G6CGMManager,
+               let activationDate = cgmG6Manager.latestReading?.activationDate,
+               let sessionStartDate = cgmG6Manager.latestReading?.sessionStartDate
+            {
+                let bloodGlucose = values.compactMap { newGlucoseSample -> BloodGlucose? in
+                    let quantity = newGlucoseSample.quantity
+                    let value = Int(quantity.doubleValue(for: .milligramsPerDeciliter))
+                    return BloodGlucose(
+                        _id: newGlucoseSample.syncIdentifier,
+                        sgv: value,
+                        direction: .init(trendType: newGlucoseSample.trend),
+                        date: Decimal(Int(newGlucoseSample.date.timeIntervalSince1970 * 1000)),
+                        dateString: newGlucoseSample.date,
+                        unfiltered: Decimal(value),
+                        filtered: nil,
+                        noise: nil,
+                        glucose: value,
+                        type: "sgv",
+                        activationDate: activationDate,
+                        sessionStartDate: sessionStartDate,
+                        transmitterID: self.transmitterID
+                    )
+                }
+                promise?(.success(bloodGlucose))
+                completion()
+            } else {
+                // Handle the case where activationDate or sessionStartDate is nil
+                completion()
             }
             }
-            promise?(.success(bloodGlucose))
-            completion()
         case .unreliableData:
         case .unreliableData:
             // loopManager.receivedUnreliableCGMReading()
             // loopManager.receivedUnreliableCGMReading()
             promise?(.failure(GlucoseDataError.unreliableData))
             promise?(.failure(GlucoseDataError.unreliableData))

+ 3 - 2
FreeAPS/Sources/APS/Storage/PumpHistoryStorage.swift

@@ -44,7 +44,8 @@ final class BasePumpHistoryStorage: PumpHistoryStorage, Injectable {
                         durationMin: nil,
                         durationMin: nil,
                         rate: nil,
                         rate: nil,
                         temp: nil,
                         temp: nil,
-                        carbInput: nil
+                        carbInput: nil,
+                        isSMB: dose.automatic
                     )]
                     )]
                 case .tempBasal:
                 case .tempBasal:
                     guard let dose = event.dose else { return [] }
                     guard let dose = event.dose else { return [] }
@@ -255,7 +256,7 @@ final class BasePumpHistoryStorage: PumpHistoryStorage, Injectable {
                     rawRate: nil,
                     rawRate: nil,
                     absolute: nil,
                     absolute: nil,
                     rate: nil,
                     rate: nil,
-                    eventType: .bolus,
+                    eventType: (event.isSMB ?? false) ? .smb : .bolus,
                     createdAt: event.timestamp,
                     createdAt: event.timestamp,
                     enteredBy: NigtscoutTreatment.local,
                     enteredBy: NigtscoutTreatment.local,
                     bolus: event,
                     bolus: event,

+ 1 - 1
FreeAPS/Sources/Localizations/Main/ar.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Calibrations";
 "Calibrations" = "Calibrations";
 
 
 /* */
 /* */
-"Create events in calendar" = "Create events in calendar";
+"Create Events in Calendar" = "Create Events in Calendar";
 
 
 /* */
 /* */
 "Calendar" = "Calendar";
 "Calendar" = "Calendar";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/ca.lproj/Localizable.strings

@@ -514,7 +514,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Calibrations";
 "Calibrations" = "Calibrations";
 
 
 /* */
 /* */
-"Create events in calendar" = "Create events in calendar";
+"Create Events in Calendar" = "Create Events in Calendar";
 
 
 /* */
 /* */
 "Calendar" = "Calendar";
 "Calendar" = "Calendar";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/da.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Calibrations";
 "Calibrations" = "Calibrations";
 
 
 /* */
 /* */
-"Create events in calendar" = "Create events in calendar";
+"Create Events in Calendar" = "Create Events in Calendar";
 
 
 /* */
 /* */
 "Calendar" = "Calendar";
 "Calendar" = "Calendar";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/de.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Kalibrierungen";
 "Calibrations" = "Kalibrierungen";
 
 
 /* */
 /* */
-"Create events in calendar" = "Kalendereintrag erstellen";
+"Create Events in Calendar" = "Kalendereintrag erstellen";
 
 
 /* */
 /* */
 "Calendar" = "Kalender";
 "Calendar" = "Kalender";

+ 4 - 1
FreeAPS/Sources/Localizations/Main/en.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Calibrations";
 "Calibrations" = "Calibrations";
 
 
 /* */
 /* */
-"Create events in calendar" = "Create events in calendar";
+"Create Events in Calendar" = "Create Events in Calendar";
 
 
 /* */
 /* */
 "Calendar" = "Calendar";
 "Calendar" = "Calendar";
@@ -1115,6 +1115,9 @@ Enact a temp Basal or a temp target */
 /* Manual temp basal mode */
 /* Manual temp basal mode */
 "Manual" = "Manual";
 "Manual" = "Manual";
 
 
+/* An Automatic delivered bolus (SMB) */
+"SMB" = "SMB";
+
 /* Status highlight when manual temp basal is running. */
 /* Status highlight when manual temp basal is running. */
 "Manual Basal" = "Manual Basal";
 "Manual Basal" = "Manual Basal";
 
 

+ 1 - 1
FreeAPS/Sources/Localizations/Main/es.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Calibraciones";
 "Calibrations" = "Calibraciones";
 
 
 /* */
 /* */
-"Create events in calendar" = "Crear eventos en el calendario";
+"Create Events in Calendar" = "Crear eventos en el calendario";
 
 
 /* */
 /* */
 "Calendar" = "Calendario";
 "Calendar" = "Calendario";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/fi.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Calibrations";
 "Calibrations" = "Calibrations";
 
 
 /* */
 /* */
-"Create events in calendar" = "Create events in calendar";
+"Create Events in Calendar" = "Create Events in Calendar";
 
 
 /* */
 /* */
 "Calendar" = "Calendar";
 "Calendar" = "Calendar";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/fr.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Étalonnages";
 "Calibrations" = "Étalonnages";
 
 
 /* */
 /* */
-"Create events in calendar" = "Créer des événements dans le calendrier";
+"Create Events in Calendar" = "Créer des événements dans le calendrier";
 
 
 /* */
 /* */
 "Calendar" = "Calendrier";
 "Calendar" = "Calendrier";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/he.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Calibrations";
 "Calibrations" = "Calibrations";
 
 
 /* */
 /* */
-"Create events in calendar" = "Create events in calendar";
+"Create Events in Calendar" = "Create Events in Calendar";
 
 
 /* */
 /* */
 "Calendar" = "Calendar";
 "Calendar" = "Calendar";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/it.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Calibrazioni";
 "Calibrations" = "Calibrazioni";
 
 
 /* */
 /* */
-"Create events in calendar" = "Crea eventi nel calendario";
+"Create Events in Calendar" = "Crea eventi nel calendario";
 
 
 /* */
 /* */
 "Calendar" = "Calendario";
 "Calendar" = "Calendario";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/nb.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Kalibreringer";
 "Calibrations" = "Kalibreringer";
 
 
 /* */
 /* */
-"Create events in calendar" = "Opprett hendelser i kalenderen";
+"Create Events in Calendar" = "Opprett hendelser i kalenderen";
 
 
 /* */
 /* */
 "Calendar" = "Kalender";
 "Calendar" = "Kalender";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/nl.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Kalibraties";
 "Calibrations" = "Kalibraties";
 
 
 /* */
 /* */
-"Create events in calendar" = "Voeg gebeurtenissen toe aan de kalender";
+"Create Events in Calendar" = "Voeg gebeurtenissen toe aan de kalender";
 
 
 /* */
 /* */
 "Calendar" = "Agenda";
 "Calendar" = "Agenda";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/pl.lproj/Localizable.strings

@@ -521,7 +521,7 @@ Połączono z Nightscout!";
 "Calibrations" = "Calibrations";
 "Calibrations" = "Calibrations";
 
 
 /* */
 /* */
-"Create events in calendar" = "Create events in calendar";
+"Create Events in Calendar" = "Create Events in Calendar";
 
 
 /* */
 /* */
 "Calendar" = "Calendar";
 "Calendar" = "Calendar";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/pt-BR.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Calibragens";
 "Calibrations" = "Calibragens";
 
 
 /* */
 /* */
-"Create events in calendar" = "Criar eventos no calendário";
+"Create Events in Calendar" = "Criar eventos no calendário";
 
 
 /* */
 /* */
 "Calendar" = "Calendário";
 "Calendar" = "Calendário";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/pt-PT.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Calibrations";
 "Calibrations" = "Calibrations";
 
 
 /* */
 /* */
-"Create events in calendar" = "Create events in calendar";
+"Create Events in Calendar" = "Create Events in Calendar";
 
 
 /* */
 /* */
 "Calendar" = "Calendar";
 "Calendar" = "Calendar";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/ru.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Калибровки";
 "Calibrations" = "Калибровки";
 
 
 /* */
 /* */
-"Create events in calendar" = "Создавать событий в календаре";
+"Create Events in Calendar" = "Создавать событий в календаре";
 
 
 /* */
 /* */
 "Calendar" = "Календарь";
 "Calendar" = "Календарь";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/sk.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Calibrations";
 "Calibrations" = "Calibrations";
 
 
 /* */
 /* */
-"Create events in calendar" = "Create events in calendar";
+"Create Events in Calendar" = "Create Events in Calendar";
 
 
 /* */
 /* */
 "Calendar" = "Calendar";
 "Calendar" = "Calendar";

+ 2 - 2
FreeAPS/Sources/Localizations/Main/sv.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Kalibreringar";
 "Calibrations" = "Kalibreringar";
 
 
 /* */
 /* */
-"Create events in calendar" = "Skapa kalenderhändelser";
+"Create Events in Calendar" = "Skapa kalenderhändelser";
 
 
 /* */
 /* */
 "Calendar" = "Kalender";
 "Calendar" = "Kalender";
@@ -1112,7 +1112,7 @@ Enact a temp Basal or a temp target */
 "Error" = "Fel";
 "Error" = "Fel";
 
 
 /* Manual temp basal mode */
 /* Manual temp basal mode */
-"Manual" = "Manuellt";
+"Manual" = "Manuell";
 
 
 /* Status highlight when manual temp basal is running. */
 /* Status highlight when manual temp basal is running. */
 "Manual Basal" = "Manuell temporär basal";
 "Manual Basal" = "Manuell temporär basal";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/tr.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Kalibrasyonlar";
 "Calibrations" = "Kalibrasyonlar";
 
 
 /* */
 /* */
-"Create events in calendar" = "Takvimde etkinlikler oluşturun";
+"Create Events in Calendar" = "Takvimde etkinlikler oluşturun";
 
 
 /* */
 /* */
 "Calendar" = "Takvim";
 "Calendar" = "Takvim";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/uk.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "Калібрування";
 "Calibrations" = "Калібрування";
 
 
 /* */
 /* */
-"Create events in calendar" = "Створити подію в календарі";
+"Create Events in Calendar" = "Створити подію в календарі";
 
 
 /* */
 /* */
 "Calendar" = "Календар";
 "Calendar" = "Календар";

+ 1 - 1
FreeAPS/Sources/Localizations/Main/zh-Hans.lproj/Localizable.strings

@@ -519,7 +519,7 @@ Enact a temp Basal or a temp target */
 "Calibrations" = "校准";
 "Calibrations" = "校准";
 
 
 /* */
 /* */
-"Create events in calendar" = "在日历中创建事件";
+"Create Events in Calendar" = "在日历中创建事件";
 
 
 /* */
 /* */
 "Calendar" = "日历";
 "Calendar" = "日历";

+ 1 - 1
FreeAPS/Sources/Models/AlertEntry.swift

@@ -15,7 +15,7 @@ struct AlertEntry: JSON, Codable, Hashable {
     let contentBody: String?
     let contentBody: String?
     var errorMessage: String?
     var errorMessage: String?
 
 
-    static let manual = "freeaps-x"
+    static let manual = "iAPS"
 
 
     static func == (lhs: AlertEntry, rhs: AlertEntry) -> Bool {
     static func == (lhs: AlertEntry, rhs: AlertEntry) -> Bool {
         lhs.issuedDate == rhs.issuedDate
         lhs.issuedDate == rhs.issuedDate

+ 1 - 1
FreeAPS/Sources/Models/Announcement.swift

@@ -5,7 +5,7 @@ struct Announcement: JSON {
     let enteredBy: String
     let enteredBy: String
     let notes: String
     let notes: String
 
 
-    static let remote = "freeaps-x-remote"
+    static let remote = "remote"
 
 
     var action: AnnouncementAction? {
     var action: AnnouncementAction? {
         let components = notes.replacingOccurrences(of: " ", with: "").split(separator: ":")
         let components = notes.replacingOccurrences(of: " ", with: "").split(separator: ":")

+ 1 - 1
FreeAPS/Sources/Models/CarbsEntry.swift

@@ -11,7 +11,7 @@ struct CarbsEntry: JSON, Equatable, Hashable {
     let isFPU: Bool?
     let isFPU: Bool?
     let fpuID: String?
     let fpuID: String?
 
 
-    static let manual = "freeaps-x"
+    static let manual = "iAPS"
     static let appleHealth = "applehealth"
     static let appleHealth = "applehealth"
 
 
     static func == (lhs: CarbsEntry, rhs: CarbsEntry) -> Bool {
     static func == (lhs: CarbsEntry, rhs: CarbsEntry) -> Bool {

+ 10 - 0
FreeAPS/Sources/Models/FreeAPSSettings.swift

@@ -15,6 +15,8 @@ struct FreeAPSSettings: JSON, Equatable {
     var cgm: CGMType = .nightscout
     var cgm: CGMType = .nightscout
     var uploadGlucose: Bool = true
     var uploadGlucose: Bool = true
     var useCalendar: Bool = false
     var useCalendar: Bool = false
+    var displayCalendarIOBandCOB: Bool = false
+    var displayCalendarEmojis: Bool = false
     var glucoseBadge: Bool = false
     var glucoseBadge: Bool = false
     var glucoseNotificationsAlways: Bool = false
     var glucoseNotificationsAlways: Bool = false
     var useAlarmSound: Bool = false
     var useAlarmSound: Bool = false
@@ -113,6 +115,14 @@ extension FreeAPSSettings: Decodable {
             settings.useCalendar = useCalendar
             settings.useCalendar = useCalendar
         }
         }
 
 
+        if let displayCalendarIOBandCOB = try? container.decode(Bool.self, forKey: .displayCalendarIOBandCOB) {
+            settings.displayCalendarIOBandCOB = displayCalendarIOBandCOB
+        }
+
+        if let displayCalendarEmojis = try? container.decode(Bool.self, forKey: .displayCalendarEmojis) {
+            settings.displayCalendarEmojis = displayCalendarEmojis
+        }
+
         if let useAppleHealth = try? container.decode(Bool.self, forKey: .useAppleHealth) {
         if let useAppleHealth = try? container.decode(Bool.self, forKey: .useAppleHealth) {
             settings.useAppleHealth = useAppleHealth
             settings.useAppleHealth = useAppleHealth
         }
         }

+ 1 - 1
FreeAPS/Sources/Models/NightscoutTreatment.swift

@@ -19,7 +19,7 @@ struct NigtscoutTreatment: JSON, Hashable, Equatable {
     let targetTop: Decimal?
     let targetTop: Decimal?
     let targetBottom: Decimal?
     let targetBottom: Decimal?
 
 
-    static let local = "freeaps-x"
+    static let local = "iAPS"
 
 
     static let empty = NigtscoutTreatment(from: "{}")!
     static let empty = NigtscoutTreatment(from: "{}")!
 
 

+ 3 - 3
FreeAPS/Sources/Models/Preferences.swift

@@ -8,8 +8,8 @@ struct Preferences: JSON {
     var autosensMin: Decimal = 0.7
     var autosensMin: Decimal = 0.7
     var smbDeliveryRatio: Decimal = 0.5
     var smbDeliveryRatio: Decimal = 0.5
     var rewindResetsAutosens: Bool = true
     var rewindResetsAutosens: Bool = true
-    var highTemptargetRaisesSensitivity: Bool = true
-    var lowTemptargetLowersSensitivity: Bool = true
+    var highTemptargetRaisesSensitivity: Bool = false
+    var lowTemptargetLowersSensitivity: Bool = false
     var sensitivityRaisesTarget: Bool = true
     var sensitivityRaisesTarget: Bool = true
     var resistanceLowersTarget: Bool = false
     var resistanceLowersTarget: Bool = false
     var advTargetAdjustments: Bool = false
     var advTargetAdjustments: Bool = false
@@ -39,7 +39,7 @@ struct Preferences: JSON {
     var insulinPeakTime: Decimal = 75
     var insulinPeakTime: Decimal = 75
     var carbsReqThreshold: Decimal = 1.0
     var carbsReqThreshold: Decimal = 1.0
     var noisyCGMTargetMultiplier: Decimal = 1.3
     var noisyCGMTargetMultiplier: Decimal = 1.3
-    var suspendZerosIOB: Bool = true
+    var suspendZerosIOB: Bool = false
     var timestamp: Date?
     var timestamp: Date?
     var maxDeltaBGthreshold: Decimal = 0.2
     var maxDeltaBGthreshold: Decimal = 0.2
     var adjustmentFactor: Decimal = 0.5
     var adjustmentFactor: Decimal = 0.5

+ 6 - 1
FreeAPS/Sources/Models/PumpHistoryEvent.swift

@@ -11,6 +11,7 @@ struct PumpHistoryEvent: JSON, Equatable {
     let temp: TempType?
     let temp: TempType?
     let carbInput: Int?
     let carbInput: Int?
     let note: String?
     let note: String?
+    let isSMB: Bool?
 
 
     init(
     init(
         id: String,
         id: String,
@@ -22,7 +23,8 @@ struct PumpHistoryEvent: JSON, Equatable {
         rate: Decimal? = nil,
         rate: Decimal? = nil,
         temp: TempType? = nil,
         temp: TempType? = nil,
         carbInput: Int? = nil,
         carbInput: Int? = nil,
-        note: String? = nil
+        note: String? = nil,
+        isSMB: Bool? = nil
     ) {
     ) {
         self.id = id
         self.id = id
         self.type = type
         self.type = type
@@ -34,11 +36,13 @@ struct PumpHistoryEvent: JSON, Equatable {
         self.temp = temp
         self.temp = temp
         self.carbInput = carbInput
         self.carbInput = carbInput
         self.note = note
         self.note = note
+        self.isSMB = isSMB
     }
     }
 }
 }
 
 
 enum EventType: String, JSON {
 enum EventType: String, JSON {
     case bolus = "Bolus"
     case bolus = "Bolus"
+    case smb = "SMB"
     case mealBulus = "Meal Bolus"
     case mealBulus = "Meal Bolus"
     case correctionBolus = "Correction Bolus"
     case correctionBolus = "Correction Bolus"
     case snackBolus = "Snack Bolus"
     case snackBolus = "Snack Bolus"
@@ -80,5 +84,6 @@ extension PumpHistoryEvent {
         case temp
         case temp
         case carbInput = "carb_input"
         case carbInput = "carb_input"
         case note
         case note
+        case isSMB
     }
     }
 }
 }

+ 1 - 1
FreeAPS/Sources/Models/TempTarget.swift

@@ -10,7 +10,7 @@ struct TempTarget: JSON, Identifiable, Equatable, Hashable {
     let enteredBy: String?
     let enteredBy: String?
     let reason: String?
     let reason: String?
 
 
-    static let manual = "freeaps-x"
+    static let manual = "iAPS"
     static let custom = "Temp target"
     static let custom = "Temp target"
     static let cancel = "Cancel"
     static let cancel = "Cancel"
 
 

+ 4 - 0
FreeAPS/Sources/Modules/CGM/CGMStateModel.swift

@@ -16,6 +16,8 @@ extension CGM {
         @Published var uploadGlucose = true
         @Published var uploadGlucose = true
         @Published var smoothGlucose = false
         @Published var smoothGlucose = false
         @Published var createCalendarEvents = false
         @Published var createCalendarEvents = false
+        @Published var displayCalendarIOBandCOB = false
+        @Published var displayCalendarEmojis = false
         @Published var calendarIDs: [String] = []
         @Published var calendarIDs: [String] = []
         @Published var currentCalendarID: String = ""
         @Published var currentCalendarID: String = ""
         @Persisted(key: "CalendarManager.currentCalendarID") var storedCalendarID: String? = nil
         @Persisted(key: "CalendarManager.currentCalendarID") var storedCalendarID: String? = nil
@@ -28,6 +30,8 @@ extension CGM {
             cgmTransmitterDeviceAddress = UserDefaults.standard.cgmTransmitterDeviceAddress
             cgmTransmitterDeviceAddress = UserDefaults.standard.cgmTransmitterDeviceAddress
 
 
             subscribeSetting(\.useCalendar, on: $createCalendarEvents) { createCalendarEvents = $0 }
             subscribeSetting(\.useCalendar, on: $createCalendarEvents) { createCalendarEvents = $0 }
+            subscribeSetting(\.displayCalendarIOBandCOB, on: $displayCalendarIOBandCOB) { displayCalendarIOBandCOB = $0 }
+            subscribeSetting(\.displayCalendarEmojis, on: $displayCalendarEmojis) { displayCalendarEmojis = $0 }
             subscribeSetting(\.smoothGlucose, on: $smoothGlucose, initial: { smoothGlucose = $0 })
             subscribeSetting(\.smoothGlucose, on: $smoothGlucose, initial: { smoothGlucose = $0 })
 
 
             $cgm
             $cgm

+ 3 - 1
FreeAPS/Sources/Modules/CGM/View/CGMRootView.swift

@@ -54,13 +54,15 @@ extension CGM {
                         Text("Calibrations").navigationLink(to: .calibrations, from: self)
                         Text("Calibrations").navigationLink(to: .calibrations, from: self)
                     }
                     }
                     Section(header: Text("Calendar")) {
                     Section(header: Text("Calendar")) {
-                        Toggle("Create events in calendar", isOn: $state.createCalendarEvents)
+                        Toggle("Create Events in Calendar", isOn: $state.createCalendarEvents)
                         if state.calendarIDs.isNotEmpty {
                         if state.calendarIDs.isNotEmpty {
                             Picker("Calendar", selection: $state.currentCalendarID) {
                             Picker("Calendar", selection: $state.currentCalendarID) {
                                 ForEach(state.calendarIDs, id: \.self) {
                                 ForEach(state.calendarIDs, id: \.self) {
                                     Text($0).tag($0)
                                     Text($0).tag($0)
                                 }
                                 }
                             }
                             }
+                            Toggle("Display Emojis as Labels", isOn: $state.displayCalendarEmojis)
+                            Toggle("Display IOB and COB", isOn: $state.displayCalendarIOBandCOB)
                         }
                         }
                     }
                     }
 
 

+ 1 - 1
FreeAPS/Sources/Modules/CREditor/CREditorStateModel.swift

@@ -7,7 +7,7 @@ extension CREditor {
 
 
         let timeValues = stride(from: 0.0, to: 1.days.timeInterval, by: 30.minutes.timeInterval).map { $0 }
         let timeValues = stride(from: 0.0, to: 1.days.timeInterval, by: 30.minutes.timeInterval).map { $0 }
 
 
-        let rateValues = stride(from: 15.0, to: 501.0, by: 1.0).map { ($0.decimal ?? .zero) / 10 }
+        let rateValues = stride(from: 1.0, to: 501.0, by: 1.0).map { ($0.decimal ?? .zero) / 10 }
 
 
         var canAdd: Bool {
         var canAdd: Bool {
             guard let lastItem = items.last else { return true }
             guard let lastItem = items.last else { return true }

+ 19 - 10
FreeAPS/Sources/Modules/DataTable/DataTableDataFlow.swift

@@ -66,8 +66,9 @@ enum DataTable {
         let isFPU: Bool?
         let isFPU: Bool?
         let fpuID: String?
         let fpuID: String?
         let note: String?
         let note: String?
+        let isSMB: Bool?
 
 
-        private var numberFormater: NumberFormatter {
+        private var numberFormatter: NumberFormatter {
             let formatter = NumberFormatter()
             let formatter = NumberFormatter()
             formatter.numberStyle = .decimal
             formatter.numberStyle = .decimal
             formatter.maximumFractionDigits = 2
             formatter.maximumFractionDigits = 2
@@ -90,9 +91,10 @@ enum DataTable {
             duration: Decimal? = nil,
             duration: Decimal? = nil,
             id: String? = nil,
             id: String? = nil,
             idPumpEvent: String? = nil,
             idPumpEvent: String? = nil,
-            isFPU: Bool? = false,
+            isFPU: Bool? = nil,
             fpuID: String? = nil,
             fpuID: String? = nil,
-            note: String? = nil
+            note: String? = nil,
+            isSMB: Bool? = nil
         ) {
         ) {
             self.units = units
             self.units = units
             self.type = type
             self.type = type
@@ -105,6 +107,7 @@ enum DataTable {
             self.isFPU = isFPU
             self.isFPU = isFPU
             self.fpuID = fpuID
             self.fpuID = fpuID
             self.note = note
             self.note = note
+            self.isSMB = isSMB
         }
         }
 
 
         static func == (lhs: Treatment, rhs: Treatment) -> Bool {
         static func == (lhs: Treatment, rhs: Treatment) -> Bool {
@@ -126,14 +129,20 @@ enum DataTable {
 
 
             switch type {
             switch type {
             case .carbs:
             case .carbs:
-                return numberFormater.string(from: amount as NSNumber)! + NSLocalizedString(" g", comment: "gram of carbs")
+                return numberFormatter
+                    .string(from: amount as NSNumber)! + NSLocalizedString(" g", comment: "gram of carbs")
             case .fpus:
             case .fpus:
-                return numberFormater
+                return numberFormatter
                     .string(from: amount as NSNumber)! + NSLocalizedString(" g", comment: "gram of carb equilvalents")
                     .string(from: amount as NSNumber)! + NSLocalizedString(" g", comment: "gram of carb equilvalents")
             case .bolus:
             case .bolus:
-                return numberFormater.string(from: amount as NSNumber)! + NSLocalizedString(" U", comment: "Insulin unit")
+                return numberFormatter
+                    .string(from: amount as NSNumber)! + NSLocalizedString(" U", comment: "Insulin unit") +
+                    (
+                        (isSMB ?? false) ? " " + NSLocalizedString("Auto", comment: "Automatic delivered bolus (SMB)") : " " +
+                            NSLocalizedString("Manual", comment: "Manual Bolus")
+                    )
             case .tempBasal:
             case .tempBasal:
-                return numberFormater
+                return numberFormatter
                     .string(from: amount as NSNumber)! + NSLocalizedString(" U/hr", comment: "Unit insulin per hour")
                     .string(from: amount as NSNumber)! + NSLocalizedString(" U/hr", comment: "Unit insulin per hour")
             case .tempTarget:
             case .tempTarget:
                 var converted = amount
                 var converted = amount
@@ -142,7 +151,7 @@ enum DataTable {
                 }
                 }
 
 
                 guard var secondAmount = secondAmount else {
                 guard var secondAmount = secondAmount else {
-                    return numberFormater.string(from: converted as NSNumber)! + " \(units.rawValue)"
+                    return numberFormatter.string(from: converted as NSNumber)! + " \(units.rawValue)"
                 }
                 }
                 if units == .mmolL {
                 if units == .mmolL {
                     secondAmount = secondAmount.asMmolL
                     secondAmount = secondAmount.asMmolL
@@ -161,7 +170,7 @@ enum DataTable {
             case .carbs:
             case .carbs:
                 return .loopYellow
                 return .loopYellow
             case .fpus:
             case .fpus:
-                return .red
+                return .loopRed
             case .bolus:
             case .bolus:
                 return .insulin
                 return .insulin
             case .tempBasal:
             case .tempBasal:
@@ -177,7 +186,7 @@ enum DataTable {
             guard let duration = duration, duration > 0 else {
             guard let duration = duration, duration > 0 else {
                 return nil
                 return nil
             }
             }
-            return numberFormater.string(from: duration as NSNumber)! + " min"
+            return numberFormatter.string(from: duration as NSNumber)! + " min"
         }
         }
     }
     }
 
 

+ 8 - 1
FreeAPS/Sources/Modules/DataTable/DataTableStateModel.swift

@@ -66,7 +66,14 @@ extension DataTable {
                 let boluses = self.provider.pumpHistory()
                 let boluses = self.provider.pumpHistory()
                     .filter { $0.type == .bolus }
                     .filter { $0.type == .bolus }
                     .map {
                     .map {
-                        Treatment(units: units, type: .bolus, date: $0.timestamp, amount: $0.amount, idPumpEvent: $0.id)
+                        Treatment(
+                            units: units,
+                            type: .bolus,
+                            date: $0.timestamp,
+                            amount: $0.amount,
+                            idPumpEvent: $0.id,
+                            isSMB: $0.isSMB
+                        )
                     }
                     }
 
 
                 let tempBasals = self.provider.pumpHistory()
                 let tempBasals = self.provider.pumpHistory()

+ 2 - 1
FreeAPS/Sources/Modules/DataTable/View/DataTableRootView.swift

@@ -113,8 +113,9 @@ extension DataTable {
                 Image(systemName: "circle.fill").foregroundColor(item.color)
                 Image(systemName: "circle.fill").foregroundColor(item.color)
                 Text(dateFormatter.string(from: item.date))
                 Text(dateFormatter.string(from: item.date))
                     .moveDisabled(true)
                     .moveDisabled(true)
-                Text(item.type.name)
+                Text((item.isSMB ?? false) ? "SMB" : item.type.name)
                 Text(item.amountText).foregroundColor(.secondary)
                 Text(item.amountText).foregroundColor(.secondary)
+
                 if let duration = item.durationText {
                 if let duration = item.durationText {
                     Text(duration).foregroundColor(.secondary)
                     Text(duration).foregroundColor(.secondary)
                 }
                 }

+ 1 - 2
FreeAPS/Sources/Modules/OverrideProfilesConfig/View/OverrideProfilesRootView.swift

@@ -292,10 +292,9 @@ extension OverrideProfilesConfig {
             let durationString = perpetual ? "" : "\(formatter.string(from: duration as NSNumber)!)"
             let durationString = perpetual ? "" : "\(formatter.string(from: duration as NSNumber)!)"
             let scheduledSMBstring = (preset.smbIsOff && preset.smbIsAlwaysOff) ? "Scheduled SMBs" : ""
             let scheduledSMBstring = (preset.smbIsOff && preset.smbIsAlwaysOff) ? "Scheduled SMBs" : ""
             let smbString = (preset.smbIsOff && scheduledSMBstring == "") ? "SMBs are off" : ""
             let smbString = (preset.smbIsOff && scheduledSMBstring == "") ? "SMBs are off" : ""
-            let targetString = target != 0 ? "\(formatter.string(from: target as NSNumber)!)" : ""
+            let targetString = target != 0 ? "\(glucoseFormatter.string(from: target as NSNumber)!)" : ""
             let maxMinutesSMB = (preset.smbMinutes as Decimal?) != nil ? (preset.smbMinutes ?? 0) as Decimal : 0
             let maxMinutesSMB = (preset.smbMinutes as Decimal?) != nil ? (preset.smbMinutes ?? 0) as Decimal : 0
             let maxMinutesUAM = (preset.uamMinutes as Decimal?) != nil ? (preset.uamMinutes ?? 0) as Decimal : 0
             let maxMinutesUAM = (preset.uamMinutes as Decimal?) != nil ? (preset.uamMinutes ?? 0) as Decimal : 0
-
             let isfString = preset.isf ? "ISF" : ""
             let isfString = preset.isf ? "ISF" : ""
             let crString = preset.cr ? "CR" : ""
             let crString = preset.cr ? "CR" : ""
             let dash = crString != "" ? "/" : ""
             let dash = crString != "" ? "/" : ""

+ 1 - 0
FreeAPS/Sources/Modules/Snooze/View/SnoozeRootView.swift

@@ -88,6 +88,7 @@ extension Snooze {
                     debug(.default, "will snooze for \(snoozeFor) until \(dateFormatter.string(from: untilDate))")
                     debug(.default, "will snooze for \(snoozeFor) until \(dateFormatter.string(from: untilDate))")
                     snoozeDescription = getSnoozeDescription()
                     snoozeDescription = getSnoozeDescription()
                     BaseUserNotificationsManager.stopSound()
                     BaseUserNotificationsManager.stopSound()
+                    state.hideModal()
                 } label: {
                 } label: {
                     Text("Click to Snooze Alerts")
                     Text("Click to Snooze Alerts")
                         .padding()
                         .padding()

+ 2 - 2
FreeAPS/Sources/Modules/Stat/View/ChartsView.swift

@@ -215,7 +215,7 @@ struct ChartsView: View {
                 let mapGlucoseNormal = mapGlucose.filter({ $0 > Int16(3.8 / 0.0555) && $0 < Int16(7.9 / 0.0555) })
                 let mapGlucoseNormal = mapGlucose.filter({ $0 > Int16(3.8 / 0.0555) && $0 < Int16(7.9 / 0.0555) })
                 HStack {
                 HStack {
                     let value = Double(mapGlucoseHigh.count * 100 / mapGlucose.count)
                     let value = Double(mapGlucoseHigh.count * 100 / mapGlucose.count)
-                    Text(units == .mmolL ? ">  11  " : ">  200 ").foregroundColor(.secondary)
+                    Text(units == .mmolL ? ">  11  " : ">  198 ").foregroundColor(.secondary)
                     Text(value.formatted()).foregroundColor(.orange)
                     Text(value.formatted()).foregroundColor(.orange)
                     Text("%").foregroundColor(.secondary)
                     Text("%").foregroundColor(.secondary)
                 }.font(.caption)
                 }.font(.caption)
@@ -259,7 +259,7 @@ struct ChartsView: View {
                 Spacer()
                 Spacer()
                 HStack {
                 HStack {
                     let value = Double(mapGlucoseAcuteHigh.count * 100 / mapGlucose.count)
                     let value = Double(mapGlucoseAcuteHigh.count * 100 / mapGlucose.count)
-                    Text(units == .mmolL ? "> 11.0" : "> 216").font(.caption).foregroundColor(.secondary)
+                    Text(units == .mmolL ? "> 11.0" : "> 198").font(.caption).foregroundColor(.secondary)
                     Text(value.formatted()).font(.caption).foregroundColor(value == 0 ? .green : .orange)
                     Text(value.formatted()).font(.caption).foregroundColor(value == 0 ? .green : .orange)
                     Text("%").font(.caption)
                     Text("%").font(.caption)
                 }
                 }

+ 43 - 2
FreeAPS/Sources/Services/Calendar/CalendarManager.swift

@@ -16,6 +16,7 @@ final class BaseCalendarManager: CalendarManager, Injectable {
     @Injected() private var settingsManager: SettingsManager!
     @Injected() private var settingsManager: SettingsManager!
     @Injected() private var broadcaster: Broadcaster!
     @Injected() private var broadcaster: Broadcaster!
     @Injected() private var glucoseStorage: GlucoseStorage!
     @Injected() private var glucoseStorage: GlucoseStorage!
+    @Injected() private var storage: FileStorage!
 
 
     init(resolver: Resolver) {
     init(resolver: Resolver) {
         injectServices(resolver)
         injectServices(resolver)
@@ -62,6 +63,10 @@ final class BaseCalendarManager: CalendarManager, Injectable {
         // create an event now
         // create an event now
         let event = EKEvent(eventStore: eventStore)
         let event = EKEvent(eventStore: eventStore)
 
 
+        var glucoseIcon = "🟢"
+        glucoseIcon = Double(glucoseValue) <= Double(settingsManager.settings.low) ? "🔴" : glucoseIcon
+        glucoseIcon = Double(glucoseValue) >= Double(settingsManager.settings.high) ? "🟠" : glucoseIcon
+
         let glucoseText = glucoseFormatter
         let glucoseText = glucoseFormatter
             .string(from: Double(
             .string(from: Double(
                 settingsManager.settings.units == .mmolL ?glucoseValue
                 settingsManager.settings.units == .mmolL ?glucoseValue
@@ -74,9 +79,31 @@ final class BaseCalendarManager: CalendarManager, Injectable {
                     .string(from: Double(settingsManager.settings.units == .mmolL ? $0.asMmolL : Decimal($0)) as NSNumber)!
                     .string(from: Double(settingsManager.settings.units == .mmolL ? $0.asMmolL : Decimal($0)) as NSNumber)!
             } ?? "--"
             } ?? "--"
 
 
-        let title = glucoseText + " " + directionText + " " + deltaText
+        let fetchedSuggestion = storage.retrieve(OpenAPS.Enact.enacted, as: Suggestion.self)
+        let iobText = iobFormatter.string(from: (fetchedSuggestion?.iob ?? 0) as NSNumber) ?? ""
+        let cobText = cobFormatter.string(from: (fetchedSuggestion?.cob ?? 0) as NSNumber) ?? ""
+
+        var glucoseDisplayText = settingsManager.settings.displayCalendarEmojis ? glucoseIcon + " " : ""
+        glucoseDisplayText += glucoseText + " " + directionText + " " + deltaText
+
+        var iobDisplayText = ""
+        var cobDisplayText = ""
+
+        if settingsManager.settings.displayCalendarIOBandCOB {
+            if settingsManager.settings.displayCalendarEmojis {
+                iobDisplayText += "💉"
+                cobDisplayText += "🥨"
+            } else {
+                iobDisplayText += "IOB:"
+                cobDisplayText += "COB:"
+            }
+            iobDisplayText += " " + iobText
+            cobDisplayText += " " + cobText
+
+            event.location = iobDisplayText + " " + cobDisplayText
+        }
 
 
-        event.title = title
+        event.title = glucoseDisplayText
         event.notes = "iAPS"
         event.notes = "iAPS"
         event.startDate = Date()
         event.startDate = Date()
         event.endDate = Date(timeIntervalSinceNow: 60 * 10)
         event.endDate = Date(timeIntervalSinceNow: 60 * 10)
@@ -133,6 +160,20 @@ final class BaseCalendarManager: CalendarManager, Injectable {
         return formatter
         return formatter
     }
     }
 
 
+    private var iobFormatter: NumberFormatter {
+        let formatter = NumberFormatter()
+        formatter.numberStyle = .decimal
+        formatter.maximumFractionDigits = 1
+        return formatter
+    }
+
+    private var cobFormatter: NumberFormatter {
+        let formatter = NumberFormatter()
+        formatter.numberStyle = .decimal
+        formatter.maximumFractionDigits = 0
+        return formatter
+    }
+
     func setupGlucose() {
     func setupGlucose() {
         let glucose = glucoseStorage.recent()
         let glucose = glucoseStorage.recent()
         let recentGlucose = glucose.last
         let recentGlucose = glucose.last

+ 1 - 1
FreeAPS/Sources/Services/Network/NightscoutAPI.swift

@@ -33,7 +33,7 @@ extension NightscoutAPI {
     func checkConnection() -> AnyPublisher<Void, Swift.Error> {
     func checkConnection() -> AnyPublisher<Void, Swift.Error> {
         struct Check: Codable, Equatable {
         struct Check: Codable, Equatable {
             var eventType = "Note"
             var eventType = "Note"
-            var enteredBy = "freeaps-x"
+            var enteredBy = "iAPS"
             var notes = "iAPS connected"
             var notes = "iAPS connected"
         }
         }
         let check = Check()
         let check = Check()

+ 15 - 18
FreeAPS/Sources/Services/UserNotifiactions/UserNotificationsManager.swift

@@ -196,7 +196,6 @@ final class BaseUserNotificationsManager: NSObject, UserNotificationsManager, In
 
 
         ensureCanSendNotification {
         ensureCanSendNotification {
             var titles: [String] = []
             var titles: [String] = []
-
             var notificationAlarm = false
             var notificationAlarm = false
 
 
             switch self.glucoseStorage.alarm {
             switch self.glucoseStorage.alarm {
@@ -210,29 +209,27 @@ final class BaseUserNotificationsManager: NSObject, UserNotificationsManager, In
                 notificationAlarm = true
                 notificationAlarm = true
             }
             }
 
 
-            if self.snoozeUntilDate > Date() {
-                titles.append(NSLocalizedString("(Snoozed)", comment: "(Snoozed)"))
-                notificationAlarm = false
-            }
-
             let delta = glucose.count >= 2 ? glucoseValue - (glucose[glucose.count - 2].glucose ?? 0) : nil
             let delta = glucose.count >= 2 ? glucoseValue - (glucose[glucose.count - 2].glucose ?? 0) : nil
-
             let body = self.glucoseText(glucoseValue: glucoseValue, delta: delta, direction: lastGlucose.direction) + self
             let body = self.glucoseText(glucoseValue: glucoseValue, delta: delta, direction: lastGlucose.direction) + self
                 .infoBody()
                 .infoBody()
 
 
-            titles.append(body)
-
-            let content = UNMutableNotificationContent()
-            content.title = titles.joined(separator: " ")
-            content.body = body
+            if self.snoozeUntilDate > Date() {
+                titles.append(NSLocalizedString("(Snoozed)", comment: "(Snoozed)"))
+                notificationAlarm = false
+            } else {
+                titles.append(body)
+                let content = UNMutableNotificationContent()
+                content.title = titles.joined(separator: " ")
+                content.body = body
+
+                if notificationAlarm {
+                    self.playSoundIfNeeded()
+                    content.sound = .default
+                    content.userInfo[NotificationAction.key] = NotificationAction.snooze.rawValue
+                }
 
 
-            if notificationAlarm {
-                self.playSoundIfNeeded()
-                content.sound = .default
-                content.userInfo[NotificationAction.key] = NotificationAction.snooze.rawValue
+                self.addRequest(identifier: .glucocoseNotification, content: content, deleteOld: true)
             }
             }
-
-            self.addRequest(identifier: .glucocoseNotification, content: content, deleteOld: true)
         }
         }
     }
     }
 
 

+ 2 - 1
FreeAPS/Sources/Views/TagCloudView.swift

@@ -66,7 +66,8 @@ struct TagCloudView: View {
                  textTag where textTag.contains("AF:"),
                  textTag where textTag.contains("AF:"),
                  textTag where textTag.contains("Autosens/Dynamic Limit:"),
                  textTag where textTag.contains("Autosens/Dynamic Limit:"),
                  textTag where textTag.contains("Dynamic ISF/CR"),
                  textTag where textTag.contains("Dynamic ISF/CR"),
-                 textTag where textTag.contains("Basal ratio"):
+                 textTag where textTag.contains("Basal ratio"),
+                 textTag where textTag.contains("SMB Ratio:"):
                 return .zt
                 return .zt
             default:
             default:
                 return .insulin
                 return .insulin

+ 2 - 2
FreeAPSWatch WatchKit Extension/Views/BolusConfirmationView.swift

@@ -40,7 +40,7 @@ struct BolusConfirmationView: View {
                     if isCrownLeftOriented {
                     if isCrownLeftOriented {
                         Spacer().frame(width: elementSize / 2)
                         Spacer().frame(width: elementSize / 2)
                     } else {
                     } else {
-                        Image(systemName: "arrow.down")
+                        Image(systemName: "digitalcrown.arrow.counterclockwise.fill")
                             .resizable()
                             .resizable()
                             .frame(width: elementSize / 2, height: elementSize / 2)
                             .frame(width: elementSize / 2, height: elementSize / 2)
                             .foregroundColor(.primary)
                             .foregroundColor(.primary)
@@ -51,7 +51,7 @@ struct BolusConfirmationView: View {
             .padding()
             .padding()
             HStack(spacing: 16) {
             HStack(spacing: 16) {
                 if isCrownLeftOriented {
                 if isCrownLeftOriented {
-                    Image(systemName: "arrow.down")
+                    Image(systemName: "digitalcrown.arrow.counterclockwise.fill")
                         .resizable()
                         .resizable()
                         .frame(width: elementSize / 2, height: elementSize / 2)
                         .frame(width: elementSize / 2, height: elementSize / 2)
                         .foregroundColor(.primary)
                         .foregroundColor(.primary)

+ 1 - 1
README.md

@@ -56,7 +56,7 @@ iAPS app runs on iPhone or iPod. An iPhone 8 or newer is required.
 
 
 # Documentation
 # Documentation
 
 
-[Discord iAPS - Server ](https://discord.gg/3eGsdykA6)
+[Discord iAPS - Server ](https://discord.gg/2gBpxRT2g)
 
 
 [iAPS documentation (under development)](https://iaps.readthedocs.io/en/latest/)
 [iAPS documentation (under development)](https://iaps.readthedocs.io/en/latest/)
 
 

+ 5 - 5
fastlane/testflight.md

@@ -20,7 +20,7 @@ There are more detailed instructions in LoopDocs for doing Browser Builds of Loo
 
 
 ## Generate App Store Connect API Key
 ## Generate App Store Connect API Key
 
 
-This step is common for all "Browser Builds", and should be done ony once. Please save the API key somewhere safe, so it can be re-used for other builds, or if needing to start from scratch.
+This step is common for all "Browser Builds", and should be done only once. Please save the API key somewhere safe, so it can be re-used for other builds, or if needing to start from scratch.
 
 
 1. Sign in to the [Apple developer portal page](https://developer.apple.com/account/resources/certificates/list).
 1. Sign in to the [Apple developer portal page](https://developer.apple.com/account/resources/certificates/list).
 1. Copy the team id from the upper right of the screen. Record this as your `TEAMID`.
 1. Copy the team id from the upper right of the screen. Record this as your `TEAMID`.
@@ -71,18 +71,18 @@ If you have previously built Loop or another app using the "browser build" metho
 ## Create App Group
 ## Create App Group
 
 
 If you have already built iAPS via Xcode using this Apple ID, you can skip on to [Create iAPS App in App Store Connect](#create-FreeAPS-X-app-in-app-store-connect).
 If you have already built iAPS via Xcode using this Apple ID, you can skip on to [Create iAPS App in App Store Connect](#create-FreeAPS-X-app-in-app-store-connect).
-_Please note that in default builds of iAPS, the app group is actually identical to the one used with Loop, so please enter these details exactly as described below. This is to ease the setup of apps such as Xdrip4iOS. It may require some caution if transfering between FreAPS X and Loop._
+_Please note that in default builds of iAPS, the app group is actually identical to the one used with Loop, so please enter these details exactly as described below. This is to ease the setup of apps such as Xdrip4iOS. It may require some caution if transfering between iAPS and Loop._
 
 
 1. Go to [Register an App Group](https://developer.apple.com/account/resources/identifiers/applicationGroup/add/) on the apple developer site.
 1. Go to [Register an App Group](https://developer.apple.com/account/resources/identifiers/applicationGroup/add/) on the apple developer site.
 1. For Description, use "Loop App Group".
 1. For Description, use "Loop App Group".
-1. For Identifier, enter "group.com.TEAMID.loopkit.LoopGroup", subsituting your team id for `TEAMID`.
+1. For Identifier, enter "group.com.TEAMID.loopkit.LoopGroup", substituting your team id for `TEAMID`.
 1. Click "Continue" and then "Register".
 1. Click "Continue" and then "Register".
 
 
 ## Add App Group to Bundle Identifiers
 ## Add App Group to Bundle Identifiers
 
 
-1. Go to [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources/identifiers/list) on the apple developer site.
+1. Go to [Certificates, Identifiers & Profiles](https://developer.apple.com/account/resources/identifiers/list) on the Apple developer site.
 1. For each of the following identifier names:
 1. For each of the following identifier names:
-    * FreeeAPS
+    * FreeAPS
     * FreeAPS watchkitapp
     * FreeAPS watchkitapp
     * FreeAPS watchkitapp watchkitextension
     * FreeAPS watchkitapp watchkitextension
 1. Click on the identifier's name.
 1. Click on the identifier's name.