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

Version 1.1.4 (#12)

* Profile Override 
I created profiles for iAPS, that is profile overrides. Using this is similar to using an override in Loop, but better. You can set a duration or enable the Profile Override indefinitely (from now on until you disable it). 
All Profile Basal rates, scheduled ISF:s and CR:s will be adjusted. Your total insulin delivered will be adjusted with this override. Basal adjusted and ISF+CR inversely adjusted with set percentage. 
Current Overide % and time remaining of override will be displayed in info panel in main view.

New Icons!
Icons created by our designer Tom Barrows. 

* Simplify TT Slider and auto-set Half Basal Target settings. 

* New Default icon (less blurry).

*Bump version

* Fix for default app name

* UI Team feedback (Tom Barrows). Simplify text for TT slider

* Avoid truncating in info panel for overrides.
Jon B Mårtensson 3 лет назад
Родитель
Сommit
1ed821864a
99 измененных файлов с 815 добавлено и 324 удалено
  1. 2 2
      Config.xcconfig
  2. 8 1
      Core_Data.xcdatamodeld/Core_Data.xcdatamodel/contents
  3. 42 3
      Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Contents.json
  4. 50 14
      FreeAPS.xcodeproj/project.pbxproj
  5. 7 7
      FreeAPS.xcworkspace/xcshareddata/swiftpm/Package.resolved
  6. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/1024 1.png
  7. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/1024 2.png
  8. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/1024.png
  9. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/128.png
  10. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/16.png
  11. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/256.png
  12. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/32.png
  13. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/512.png
  14. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/64.png
  15. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon117x117@2x.png
  16. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon129x129@2x.png
  17. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon33x33@2x.png
  18. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon46x46@2x.png
  19. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon51x51@2x.png
  20. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon54x54@2x.png
  21. 0 80
      FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json
  22. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-1024 1.png
  23. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-1024.png
  24. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-1025.png
  25. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-128.png
  26. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-16.png
  27. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-256.png
  28. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-257.png
  29. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-32.png
  30. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-33.png
  31. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-512.png
  32. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-513.png
  33. BIN
      FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-64.png
  34. 0 80
      FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/Contents.json
  35. 20 0
      FreeAPS/Resources/Assets.xcassets/iAPS.appiconset/Contents.json
  36. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS.appiconset/iAPS Text 1.png
  37. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS.appiconset/iAPS Text.png
  38. 20 0
      FreeAPS/Resources/Assets.xcassets/iAPS_Black.appiconset/Contents.json
  39. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Black.appiconset/iAPS Icon2 1.png
  40. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Black.appiconset/iAPS Icon2.png
  41. 20 0
      FreeAPS/Resources/Assets.xcassets/iAPS_Black_Black.appiconset/Contents.json
  42. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Black_Black.appiconset/iAPS Icon4 1.png
  43. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Black_Black.appiconset/iAPS Icon4.png
  44. 20 0
      FreeAPS/Resources/Assets.xcassets/iAPS_Clean.appiconset/Contents.json
  45. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Clean.appiconset/Logo_Pink 1.png
  46. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Clean.appiconset/Logo_Pink.png
  47. 20 0
      FreeAPS/Resources/Assets.xcassets/iAPS_Glow_BG.appiconset/Contents.json
  48. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Glow_BG.appiconset/iAPS Icon1 1.png
  49. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Glow_BG.appiconset/iAPS Icon1.png
  50. 20 0
      FreeAPS/Resources/Assets.xcassets/iAPS_Gray.appiconset/Contents.json
  51. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Gray.appiconset/iAPS Pump_Bevel 1.png
  52. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Gray.appiconset/iAPS Pump_Bevel.png
  53. 20 0
      FreeAPS/Resources/Assets.xcassets/iAPS_Gray_Flat.appiconset/Contents.json
  54. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Gray_Flat.appiconset/iAPS Pump_Black 1.png
  55. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Gray_Flat.appiconset/iAPS Pump_Black.png
  56. 20 0
      FreeAPS/Resources/Assets.xcassets/iAPS_Gray_No_Buttons_BBG.appiconset/Contents.json
  57. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Gray_No_Buttons_BBG.appiconset/iAPS Pump_Bevel2_Black 1.png
  58. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Gray_No_Buttons_BBG.appiconset/iAPS Pump_Bevel2_Black.png
  59. 20 0
      FreeAPS/Resources/Assets.xcassets/iAPS_Loop.appiconset/Contents.json
  60. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Loop.appiconset/imageLoop 1.png
  61. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Loop.appiconset/imageLoop.png
  62. 20 0
      FreeAPS/Resources/Assets.xcassets/iAPS_Loop_Text.appiconset/Contents.json
  63. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Loop_Text.appiconset/image 1.png
  64. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Loop_Text.appiconset/image.png
  65. 20 0
      FreeAPS/Resources/Assets.xcassets/iAPS_NoButtons_Gray_White_BG.appiconset/Contents.json
  66. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_NoButtons_Gray_White_BG.appiconset/iAPS Pump_Bevel2_Transparent.png
  67. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_NoButtons_Gray_White_BG.appiconset/iAPS_NoButtons_Gray1024x1024.png
  68. 20 0
      FreeAPS/Resources/Assets.xcassets/iAPS_Purple.appiconset/Contents.json
  69. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Purple.appiconset/iAPS Pump_FlatGradient 1.png
  70. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Purple.appiconset/iAPS Pump_FlatGradient.png
  71. 20 0
      FreeAPS/Resources/Assets.xcassets/iAPS_Purple_BG.appiconset/Contents.json
  72. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Purple_BG.appiconset/iAPS Icon3 1.png
  73. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_Purple_BG.appiconset/iAPS Icon3.png
  74. 20 0
      FreeAPS/Resources/Assets.xcassets/iAPS_WhiteAndGray.appiconset/Contents.json
  75. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_WhiteAndGray.appiconset/iAPS Pump_White 1.png
  76. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_WhiteAndGray.appiconset/iAPS Pump_White.png
  77. 20 0
      FreeAPS/Resources/Assets.xcassets/iAPS_White_BG.appiconset/Contents.json
  78. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_White_BG.appiconset/iAPS Icon5 1.png
  79. BIN
      FreeAPS/Resources/Assets.xcassets/iAPS_White_BG.appiconset/iAPS Icon5.png
  80. 2 0
      FreeAPS/Resources/Info.plist
  81. 1 1
      FreeAPS/Resources/javascript/bundle/determine-basal.js
  82. 6 6
      FreeAPS/Resources/javascript/prepare/determine-basal.js
  83. 115 10
      FreeAPS/Sources/APS/APSManager.swift
  84. 1 1
      FreeAPS/Sources/APS/OpenAPS/Constants.swift
  85. 4 4
      FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift
  86. 0 1
      FreeAPS/Sources/Application/FreeAPSApp.swift
  87. 23 3
      FreeAPS/Sources/Models/TDD_averages.swift
  88. 8 4
      FreeAPS/Sources/Modules/AddTempTarget/AddTempTargetStateModel.swift
  89. 31 18
      FreeAPS/Sources/Modules/AddTempTarget/View/AddTempTargetRootView.swift
  90. 26 0
      FreeAPS/Sources/Modules/Home/View/HomeRootView.swift
  91. 5 0
      FreeAPS/Sources/Modules/OverrideProfilesConfig/OverrideProfilesDataFlow.swift
  92. 3 0
      FreeAPS/Sources/Modules/OverrideProfilesConfig/OverrideProfilesProvider.swift
  93. 59 0
      FreeAPS/Sources/Modules/OverrideProfilesConfig/OverrideProfilesStateModel.swift
  94. 107 0
      FreeAPS/Sources/Modules/OverrideProfilesConfig/View/OverrideProfilesRootView.swift
  95. 1 0
      FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift
  96. 3 0
      FreeAPS/Sources/Router/Screen.swift
  97. 10 0
      FreeAPSWatch/Info.plist
  98. 1 1
      README.md
  99. 0 88
      README_RU.md

+ 2 - 2
Config.xcconfig

@@ -1,11 +1,11 @@
 APP_DISPLAY_NAME = iAPS
-APP_VERSION = 1.1.2
+APP_VERSION = 1.1.4
 APP_BUILD_NUMBER = 1
 COPYRIGHT_NOTICE =
 DEVELOPER_TEAM = ##TEAM_ID##
 BUNDLE_IDENTIFIER = ru.artpancreas.$(DEVELOPMENT_TEAM).FreeAPS
 APP_GROUP_ID = group.com.$(DEVELOPMENT_TEAM).loopkit.LoopGroup
-APP_ICON = AppIcon
+APP_ICON = iAPS_Loop_Text
 
 #include? "ConfigOverride.xcconfig"
 #include? "../../ConfigOverride.xcconfig"

+ 8 - 1
Core_Data.xcdatamodeld/Core_Data.xcdatamodel/contents

@@ -21,7 +21,6 @@
         <attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
         <attribute name="enteredBy" optional="YES" attributeType="String"/>
     </entity>
-    <entity name="Entity" representedClassName="Entity" syncable="YES" codeGenerationType="class"/>
     <entity name="HbA1c" representedClassName="HbA1c" syncable="YES" codeGenerationType="class">
         <attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
         <attribute name="hba1c" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
@@ -47,6 +46,13 @@
         <relationship name="computedInsulinDistribution" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="InsulinDistribution" inverseName="insulin" inverseEntity="InsulinDistribution"/>
         <relationship name="computedTDD" optional="YES" toMany="YES" deletionRule="Nullify" destinationEntity="TDD" inverseName="computed" inverseEntity="TDD"/>
     </entity>
+    <entity name="Override" representedClassName="Override" syncable="YES" codeGenerationType="class">
+        <attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
+        <attribute name="duration" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
+        <attribute name="enabled" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
+        <attribute name="indefinite" optional="YES" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES"/>
+        <attribute name="percentage" optional="YES" attributeType="Double" defaultValueString="100" usesScalarValueType="YES"/>
+    </entity>
     <entity name="Presets" representedClassName="Presets" syncable="YES" codeGenerationType="class">
         <attribute name="carbs" optional="YES" attributeType="Decimal" defaultValueString="0.0"/>
         <attribute name="dish" optional="YES" attributeType="String"/>
@@ -68,5 +74,6 @@
     <entity name="ViewPercentage" representedClassName="ViewPercentage" syncable="YES" codeGenerationType="class">
         <attribute name="date" optional="YES" attributeType="Date" usesScalarValueType="NO"/>
         <attribute name="enabled" optional="YES" attributeType="Boolean" defaultValueString="100" usesScalarValueType="YES"/>
+        <attribute name="hbt" optional="YES" attributeType="Double" defaultValueString="160" usesScalarValueType="YES"/>
     </entity>
 </model>

+ 42 - 3
Dependencies/CGMBLEKit/ResetTransmitter/Assets.xcassets/AppIcon.appiconset/Contents.json

@@ -139,6 +139,13 @@
       "size" : "29x29"
     },
     {
+      "idiom" : "watch",
+      "role" : "notificationCenter",
+      "scale" : "2x",
+      "size" : "33x33",
+      "subtype" : "45mm"
+    },
+    {
       "filename" : "Icon-40@2x.png",
       "idiom" : "watch",
       "role" : "appLauncher",
@@ -158,10 +165,31 @@
       "idiom" : "watch",
       "role" : "appLauncher",
       "scale" : "2x",
+      "size" : "46x46",
+      "subtype" : "41mm"
+    },
+    {
+      "idiom" : "watch",
+      "role" : "appLauncher",
+      "scale" : "2x",
       "size" : "50x50",
       "subtype" : "44mm"
     },
     {
+      "idiom" : "watch",
+      "role" : "appLauncher",
+      "scale" : "2x",
+      "size" : "51x51",
+      "subtype" : "45mm"
+    },
+    {
+      "idiom" : "watch",
+      "role" : "appLauncher",
+      "scale" : "2x",
+      "size" : "54x54",
+      "subtype" : "49mm"
+    },
+    {
       "filename" : "Icon-86@2x.png",
       "idiom" : "watch",
       "role" : "quickLook",
@@ -185,6 +213,20 @@
       "subtype" : "44mm"
     },
     {
+      "idiom" : "watch",
+      "role" : "quickLook",
+      "scale" : "2x",
+      "size" : "117x117",
+      "subtype" : "45mm"
+    },
+    {
+      "idiom" : "watch",
+      "role" : "quickLook",
+      "scale" : "2x",
+      "size" : "129x129",
+      "subtype" : "49mm"
+    },
+    {
       "idiom" : "watch-marketing",
       "scale" : "1x",
       "size" : "1024x1024"
@@ -193,8 +235,5 @@
   "info" : {
     "author" : "xcode",
     "version" : 1
-  },
-  "properties" : {
-    "pre-rendered" : true
   }
 }

+ 50 - 14
FreeAPS.xcodeproj/project.pbxproj

@@ -15,7 +15,7 @@
 		17A9D0899046B45E87834820 /* CREditorProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9C8D5F457B5AFF763F8CF3DF /* CREditorProvider.swift */; };
 		19012CDC291D2CB900FB8210 /* LoopStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19012CDB291D2CB900FB8210 /* LoopStats.swift */; };
 		1927C8E62744606D00347C69 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 1927C8E82744606D00347C69 /* InfoPlist.strings */; };
-		1935364028496F7D001E0B16 /* TDD_averages.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1935363F28496F7D001E0B16 /* TDD_averages.swift */; };
+		1935364028496F7D001E0B16 /* Oref2_variables.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1935363F28496F7D001E0B16 /* Oref2_variables.swift */; };
 		19795118275953E50044850D /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 198377D4266BFFF6004DE65E /* Localizable.strings */; };
 		198377D2266BFFF6004DE65E /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = 198377D4266BFFF6004DE65E /* Localizable.strings */; };
 		19854F492961C3E500941627 /* DurationButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19854F482961C3E500941627 /* DurationButton.swift */; };
@@ -25,6 +25,13 @@
 		19D466A529AA2BD4004D5F33 /* FPUConfigProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19D466A429AA2BD4004D5F33 /* FPUConfigProvider.swift */; };
 		19D466A729AA2C22004D5F33 /* FPUConfigStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19D466A629AA2C22004D5F33 /* FPUConfigStateModel.swift */; };
 		19D466AA29AA3099004D5F33 /* FPUConfigRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19D466A929AA3099004D5F33 /* FPUConfigRootView.swift */; };
+		19DA48E829CD339B00EEA1E7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 19DA487F29CD2B8400EEA1E7 /* Assets.xcassets */; };
+		19DA48E929CD339C00EEA1E7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 19DA487F29CD2B8400EEA1E7 /* Assets.xcassets */; };
+		19DA48EA29CD339C00EEA1E7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 19DA487F29CD2B8400EEA1E7 /* Assets.xcassets */; };
+		19DC677F29CA675700FD9EC4 /* OverrideProfilesDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19DC677E29CA675700FD9EC4 /* OverrideProfilesDataFlow.swift */; };
+		19DC678129CA676A00FD9EC4 /* OverrideProfilesProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19DC678029CA676A00FD9EC4 /* OverrideProfilesProvider.swift */; };
+		19DC678329CA677D00FD9EC4 /* OverrideProfilesStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19DC678229CA677D00FD9EC4 /* OverrideProfilesStateModel.swift */; };
+		19DC678529CA67A400FD9EC4 /* OverrideProfilesRootView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 19DC678429CA67A400FD9EC4 /* OverrideProfilesRootView.swift */; };
 		1BBB001DAD60F3B8CEA4B1C7 /* ISFEditorStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 505E09DC17A0C3D0AF4B66FE /* ISFEditorStateModel.swift */; };
 		1D845DF2E3324130E1D95E67 /* DataTableProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 60744C3E9BB3652895C908CC /* DataTableProvider.swift */; };
 		23888883D4EA091C88480FF2 /* BolusProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = C19984D62EFC0035A9E9644D /* BolusProvider.swift */; };
@@ -130,7 +137,6 @@
 		388358C825EEF6D200E024B2 /* BasalProfileEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388358C725EEF6D200E024B2 /* BasalProfileEntry.swift */; };
 		38887CCE25F5725200944304 /* IOBEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38887CCD25F5725200944304 /* IOBEntry.swift */; };
 		388E595C25AD948C0019842D /* FreeAPSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388E595B25AD948C0019842D /* FreeAPSApp.swift */; };
-		388E596025AD948E0019842D /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 388E595F25AD948E0019842D /* Assets.xcassets */; };
 		388E596C25AD95110019842D /* OpenAPS.swift in Sources */ = {isa = PBXBuildFile; fileRef = 388E596B25AD95110019842D /* OpenAPS.swift */; };
 		388E596F25AD96040019842D /* javascript in Resources */ = {isa = PBXBuildFile; fileRef = 388E596E25AD96040019842D /* javascript */; };
 		388E597225AD9CF10019842D /* json in Resources */ = {isa = PBXBuildFile; fileRef = 388E597125AD9CF10019842D /* json */; };
@@ -203,8 +209,6 @@
 		38E8753427554D5800975559 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 38E8753327554D5800975559 /* Assets.xcassets */; };
 		38E8753727554D5900975559 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 38E8753627554D5800975559 /* Preview Assets.xcassets */; };
 		38E8753C27554D5900975559 /* FreeAPSWatch.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = 38E8751C27554D5500975559 /* FreeAPSWatch.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
-		38E8754527554D8800975559 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 388E595F25AD948E0019842D /* Assets.xcassets */; };
-		38E8754627554D8A00975559 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 388E595F25AD948E0019842D /* Assets.xcassets */; };
 		38E8754727554DF100975559 /* Color+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38F37827261260DC009DB701 /* Color+Extensions.swift */; };
 		38E8754A275550BB00975559 /* CarbsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E87549275550BB00975559 /* CarbsView.swift */; };
 		38E8754C2755548F00975559 /* WatchStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E8754B2755548F00975559 /* WatchStateModel.swift */; };
@@ -467,7 +471,8 @@
 		1927C8FA2744612500347C69 /* tr */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = tr; path = tr.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		1927C8FB2744612600347C69 /* uk */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = uk; path = uk.lproj/InfoPlist.strings; sourceTree = "<group>"; };
 		1927C8FE274489BA00347C69 /* Base */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = Base; path = Base.lproj/InfoPlist.strings; sourceTree = "<group>"; };
-		1935363F28496F7D001E0B16 /* TDD_averages.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TDD_averages.swift; sourceTree = "<group>"; };
+		1935363F28496F7D001E0B16 /* Oref2_variables.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Oref2_variables.swift; sourceTree = "<group>"; };
+		1980131D29CC9839002FF024 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
 		198377D3266BFFF6004DE65E /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/Localizable.strings; sourceTree = "<group>"; };
 		198377D5266C0A05004DE65E /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Localizable.strings; sourceTree = "<group>"; };
 		198377D6266C0A0A004DE65E /* ca */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ca; path = ca.lproj/Localizable.strings; sourceTree = "<group>"; };
@@ -496,6 +501,11 @@
 		19D466A429AA2BD4004D5F33 /* FPUConfigProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FPUConfigProvider.swift; sourceTree = "<group>"; };
 		19D466A629AA2C22004D5F33 /* FPUConfigStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FPUConfigStateModel.swift; sourceTree = "<group>"; };
 		19D466A929AA3099004D5F33 /* FPUConfigRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FPUConfigRootView.swift; sourceTree = "<group>"; };
+		19DA487F29CD2B8400EEA1E7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		19DC677E29CA675700FD9EC4 /* OverrideProfilesDataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideProfilesDataFlow.swift; sourceTree = "<group>"; };
+		19DC678029CA676A00FD9EC4 /* OverrideProfilesProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideProfilesProvider.swift; sourceTree = "<group>"; };
+		19DC678229CA677D00FD9EC4 /* OverrideProfilesStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideProfilesStateModel.swift; sourceTree = "<group>"; };
+		19DC678429CA67A400FD9EC4 /* OverrideProfilesRootView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OverrideProfilesRootView.swift; sourceTree = "<group>"; };
 		1CAE81192B118804DCD23034 /* SnoozeProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SnoozeProvider.swift; sourceTree = "<group>"; };
 		212E8BFE6D66EE65AA26A114 /* CalibrationsProvider.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CalibrationsProvider.swift; sourceTree = "<group>"; };
 		223EC0494F55A91E3EA69EF4 /* BolusStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BolusStateModel.swift; sourceTree = "<group>"; };
@@ -589,7 +599,6 @@
 		38887CCD25F5725200944304 /* IOBEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IOBEntry.swift; sourceTree = "<group>"; };
 		388E595825AD948C0019842D /* FreeAPS.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FreeAPS.app; sourceTree = BUILT_PRODUCTS_DIR; };
 		388E595B25AD948C0019842D /* FreeAPSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FreeAPSApp.swift; sourceTree = "<group>"; };
-		388E595F25AD948E0019842D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
 		388E596425AD948E0019842D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
 		388E596B25AD95110019842D /* OpenAPS.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenAPS.swift; sourceTree = "<group>"; };
 		388E596E25AD96040019842D /* javascript */ = {isa = PBXFileReference; lastKnownFileType = folder; path = javascript; sourceTree = "<group>"; };
@@ -956,6 +965,25 @@
 			path = View;
 			sourceTree = "<group>";
 		};
+		19DC677C29CA66F200FD9EC4 /* OverrideProfilesConfig */ = {
+			isa = PBXGroup;
+			children = (
+				19DC677E29CA675700FD9EC4 /* OverrideProfilesDataFlow.swift */,
+				19DC678029CA676A00FD9EC4 /* OverrideProfilesProvider.swift */,
+				19DC678229CA677D00FD9EC4 /* OverrideProfilesStateModel.swift */,
+				19DC677D29CA672500FD9EC4 /* View */,
+			);
+			path = OverrideProfilesConfig;
+			sourceTree = "<group>";
+		};
+		19DC677D29CA672500FD9EC4 /* View */ = {
+			isa = PBXGroup;
+			children = (
+				19DC678429CA67A400FD9EC4 /* OverrideProfilesRootView.swift */,
+			);
+			path = View;
+			sourceTree = "<group>";
+		};
 		29B478DF61BF8D270F7D8954 /* Snooze */ = {
 			isa = PBXGroup;
 			children = (
@@ -998,6 +1026,7 @@
 				5031FE61F63C2A8A8B7674DD /* ManualTempBasal */,
 				D533BF261CDC1C3F871E7BFD /* NightscoutConfig */,
 				F66B236E00924A05D6A9F9DF /* NotificationsConfig */,
+				19DC677C29CA66F200FD9EC4 /* OverrideProfilesConfig */,
 				3E1C41D9301B7058AA7BF5EA /* PreferencesEditor */,
 				99C01B871ACAB3F32CE755C7 /* PumpConfig */,
 				E493126EA71765130F64CCE5 /* PumpSettingsEditor */,
@@ -1193,7 +1222,7 @@
 				3811DEC725C9DA7300A708ED /* FreeAPS.entitlements */,
 				388E596425AD948E0019842D /* Info.plist */,
 				1927C8E82744606D00347C69 /* InfoPlist.strings */,
-				388E595F25AD948E0019842D /* Assets.xcassets */,
+				19DA487F29CD2B8400EEA1E7 /* Assets.xcassets */,
 			);
 			path = Resources;
 			sourceTree = "<group>";
@@ -1416,7 +1445,7 @@
 				3871F39B25ED892B0013ECB5 /* TempTarget.swift */,
 				3811DE8E25C9D80400A708ED /* User.swift */,
 				E0D4F80427513ECF00BDF1FE /* HealthKitSample.swift */,
-				1935363F28496F7D001E0B16 /* TDD_averages.swift */,
+				1935363F28496F7D001E0B16 /* Oref2_variables.swift */,
 				CE82E02628E869DF00473A9C /* AlertEntry.swift */,
 				19B0EF2028F6D66200069496 /* Statistics.swift */,
 				19012CDB291D2CB900FB8210 /* LoopStats.swift */,
@@ -1549,6 +1578,7 @@
 		38E8751D27554D5500975559 /* FreeAPSWatch */ = {
 			isa = PBXGroup;
 			children = (
+				1980131D29CC9839002FF024 /* Info.plist */,
 				38E8755627564B6100975559 /* FreeAPSWatch.entitlements */,
 				38E8751E27554D5700975559 /* Assets.xcassets */,
 			);
@@ -2175,11 +2205,11 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				388E596025AD948E0019842D /* Assets.xcassets in Resources */,
 				198377D2266BFFF6004DE65E /* Localizable.strings in Resources */,
 				38DF178D27733E6800B3528F /* snow.sks in Resources */,
 				388E597225AD9CF10019842D /* json in Resources */,
 				38DF178E27733E6800B3528F /* Assets.xcassets in Resources */,
+				19DA48E829CD339B00EEA1E7 /* Assets.xcassets in Resources */,
 				388E596F25AD96040019842D /* javascript in Resources */,
 				1927C8E62744606D00347C69 /* InfoPlist.strings in Resources */,
 			);
@@ -2189,7 +2219,7 @@
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
-				38E8754527554D8800975559 /* Assets.xcassets in Resources */,
+				19DA48E929CD339C00EEA1E7 /* Assets.xcassets in Resources */,
 				38E8751F27554D5700975559 /* Assets.xcassets in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -2200,7 +2230,7 @@
 			files = (
 				38E8753727554D5900975559 /* Preview Assets.xcassets in Resources */,
 				19795118275953E50044850D /* Localizable.strings in Resources */,
-				38E8754627554D8A00975559 /* Assets.xcassets in Resources */,
+				19DA48EA29CD339C00EEA1E7 /* Assets.xcassets in Resources */,
 				38E8753427554D5800975559 /* Assets.xcassets in Resources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
@@ -2321,6 +2351,7 @@
 				E013D872273AC6FE0014109C /* GlucoseSimulatorSource.swift in Sources */,
 				388E5A5C25B6F0770019842D /* JSON.swift in Sources */,
 				3811DF0225CA9FEA00A708ED /* Credentials.swift in Sources */,
+				19DC678529CA67A400FD9EC4 /* OverrideProfilesRootView.swift in Sources */,
 				389A572026079BAA00BC102F /* Interpolation.swift in Sources */,
 				38B4F3C625E5017E00E76A18 /* NotificationCenter.swift in Sources */,
 				19D466A729AA2C22004D5F33 /* FPUConfigStateModel.swift in Sources */,
@@ -2395,7 +2426,8 @@
 				38C4D33A25E9A1ED00D30B77 /* NSObject+AssociatedValues.swift in Sources */,
 				38DF179027733EAD00B3528F /* SnowScene.swift in Sources */,
 				38AAF8712600C1B0004AF583 /* MainChartView.swift in Sources */,
-				1935364028496F7D001E0B16 /* TDD_averages.swift in Sources */,
+				19DC677F29CA675700FD9EC4 /* OverrideProfilesDataFlow.swift in Sources */,
+				1935364028496F7D001E0B16 /* Oref2_variables.swift in Sources */,
 				CE2FAD3A297D93F0001A872C /* BloodGlucoseExtensions.swift in Sources */,
 				38E4453A274E411700EC9A94 /* Disk+[UIImage].swift in Sources */,
 				72F1BD388F42FCA6C52E4500 /* ConfigEditorProvider.swift in Sources */,
@@ -2419,6 +2451,7 @@
 				A0B8EC8CC5CD1DD237D1BCD2 /* PumpSettingsEditorRootView.swift in Sources */,
 				E06B911A275B5EEA003C04B6 /* Array+Extension.swift in Sources */,
 				38EA0600262091870064E39B /* BolusProgressViewStyle.swift in Sources */,
+				19DC678329CA677D00FD9EC4 /* OverrideProfilesStateModel.swift in Sources */,
 				389ECDFE2601061500D86C4F /* View+Snapshot.swift in Sources */,
 				38FEF3FE2738083E00574A46 /* CGMProvider.swift in Sources */,
 				38E98A3725F5509500C0CED0 /* String+Extensions.swift in Sources */,
@@ -2457,6 +2490,7 @@
 				F5F7E6C1B7F098F59EB67EC5 /* TargetsEditorDataFlow.swift in Sources */,
 				5075C1608E6249A51495C422 /* TargetsEditorProvider.swift in Sources */,
 				E13B7DAB2A435F57066AF02E /* TargetsEditorStateModel.swift in Sources */,
+				19DC678129CA676A00FD9EC4 /* OverrideProfilesProvider.swift in Sources */,
 				9702FF92A09C53942F20D7EA /* TargetsEditorRootView.swift in Sources */,
 				38E8754F275556FA00975559 /* WatchManager.swift in Sources */,
 				A228DF96647338139F152B15 /* PreferencesEditorDataFlow.swift in Sources */,
@@ -2804,7 +2838,7 @@
 			buildSettings = {
 				APP_DISPLAY_NAME = "$(APP_DISPLAY_NAME)";
 				APP_GROUP_ID = "$(APP_GROUP_ID)";
-				ASSETCATALOG_COMPILER_APPICON_NAME = "$(APP_ICON)";
+				ASSETCATALOG_COMPILER_APPICON_NAME = iAPS_Loop_Text;
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				BUNDLE_IDENTIFIER = "$(BUNDLE_IDENTIFIER)";
 				CODE_SIGN_ENTITLEMENTS = FreeAPS/Resources/FreeAPS.entitlements;
@@ -2850,6 +2884,7 @@
 				DEVELOPMENT_TEAM = "$(DEVELOPER_TEAM)";
 				GENERATE_INFOPLIST_FILE = YES;
 				IBSC_MODULE = FreeAPSWatch_WatchKit_Extension;
+				INFOPLIST_FILE = FreeAPSWatch/Info.plist;
 				INFOPLIST_KEY_CFBundleDisplayName = iAPS;
 				INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
 				INFOPLIST_KEY_WKCompanionAppBundleIdentifier = "$(BUNDLE_IDENTIFIER)";
@@ -2870,7 +2905,7 @@
 			buildSettings = {
 				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				APP_DISPLAY_NAME = "$(APP_DISPLAY_NAME)";
-				ASSETCATALOG_COMPILER_APPICON_NAME = "$(APP_ICON)";
+				ASSETCATALOG_COMPILER_APPICON_NAME = iAPS_Loop_Text;
 				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
 				BUNDLE_IDENTIFIER = "$(BUNDLE_IDENTIFIER)";
 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
@@ -2880,6 +2915,7 @@
 				DEVELOPMENT_TEAM = "$(DEVELOPER_TEAM)";
 				GENERATE_INFOPLIST_FILE = YES;
 				IBSC_MODULE = FreeAPSWatch_WatchKit_Extension;
+				INFOPLIST_FILE = FreeAPSWatch/Info.plist;
 				INFOPLIST_KEY_CFBundleDisplayName = iAPS;
 				INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
 				INFOPLIST_KEY_WKCompanionAppBundleIdentifier = "$(BUNDLE_IDENTIFIER)";

+ 7 - 7
FreeAPS.xcworkspace/xcshareddata/swiftpm/Package.resolved

@@ -6,8 +6,8 @@
         "repositoryURL": "https://github.com/krzyzanowskim/CryptoSwift",
         "state": {
           "branch": null,
-          "revision": "039f56c5d7960f277087a0be51f5eb04ed0ec073",
-          "version": "1.5.1"
+          "revision": "19b3c3ceed117c5cc883517c4e658548315ba70b",
+          "version": "1.6.0"
         }
       },
       {
@@ -30,7 +30,7 @@
       },
       {
         "package": "SwiftCharts",
-        "repositoryURL": "https://github.com/ivanschuetz/SwiftCharts",
+        "repositoryURL": "https://github.com/ivanschuetz/SwiftCharts.git",
         "state": {
           "branch": "master",
           "revision": "c354c1945bb35a1f01b665b22474f6db28cba4a2",
@@ -51,8 +51,8 @@
         "repositoryURL": "https://github.com/SwiftKickMobile/SwiftMessages",
         "state": {
           "branch": null,
-          "revision": "1e49de7b3780b69927bc3e61903d8ec0693a3dc5",
-          "version": "9.0.5"
+          "revision": "b29dd21090b708aa0ae9ecbaf6e2d0487028dc3f",
+          "version": "9.0.6"
         }
       },
       {
@@ -60,8 +60,8 @@
         "repositoryURL": "https://github.com/Swinject/Swinject",
         "state": {
           "branch": null,
-          "revision": "f10b6e9ebff440f985c43008f7c2d097639fcb81",
-          "version": "2.8.1"
+          "revision": "8bc503e60965298984fb58cf47b71c541449fe2a",
+          "version": "2.8.3"
         }
       }
     ]

BIN
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/1024 1.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/1024 2.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/1024.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/128.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/16.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/256.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/32.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/512.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/64.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon117x117@2x.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon129x129@2x.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon33x33@2x.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon46x46@2x.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon51x51@2x.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/AppIcon54x54@2x.png


+ 0 - 80
FreeAPS/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json

@@ -1,80 +0,0 @@
-{
-  "images" : [
-    {
-      "filename" : "1024 1.png",
-      "idiom" : "universal",
-      "platform" : "ios",
-      "size" : "1024x1024"
-    },
-    {
-      "filename" : "16.png",
-      "idiom" : "mac",
-      "scale" : "1x",
-      "size" : "16x16"
-    },
-    {
-      "filename" : "32.png",
-      "idiom" : "mac",
-      "scale" : "2x",
-      "size" : "16x16"
-    },
-    {
-      "filename" : "32.png",
-      "idiom" : "mac",
-      "scale" : "1x",
-      "size" : "32x32"
-    },
-    {
-      "filename" : "64.png",
-      "idiom" : "mac",
-      "scale" : "2x",
-      "size" : "32x32"
-    },
-    {
-      "filename" : "128.png",
-      "idiom" : "mac",
-      "scale" : "1x",
-      "size" : "128x128"
-    },
-    {
-      "filename" : "256.png",
-      "idiom" : "mac",
-      "scale" : "2x",
-      "size" : "128x128"
-    },
-    {
-      "filename" : "256.png",
-      "idiom" : "mac",
-      "scale" : "1x",
-      "size" : "256x256"
-    },
-    {
-      "filename" : "512.png",
-      "idiom" : "mac",
-      "scale" : "2x",
-      "size" : "256x256"
-    },
-    {
-      "filename" : "512.png",
-      "idiom" : "mac",
-      "scale" : "1x",
-      "size" : "512x512"
-    },
-    {
-      "filename" : "1024.png",
-      "idiom" : "mac",
-      "scale" : "2x",
-      "size" : "512x512"
-    },
-    {
-      "filename" : "1024 2.png",
-      "idiom" : "universal",
-      "platform" : "watchos",
-      "size" : "1024x1024"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  }
-}

BIN
FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-1024 1.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-1024.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-1025.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-128.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-16.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-256.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-257.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-32.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-33.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-512.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-513.png


BIN
FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/1024_-64.png


+ 0 - 80
FreeAPS/Resources/Assets.xcassets/AppIcon_BW.appiconset/Contents.json

@@ -1,80 +0,0 @@
-{
-  "images" : [
-    {
-      "filename" : "1024_-1024.png",
-      "idiom" : "universal",
-      "platform" : "ios",
-      "size" : "1024x1024"
-    },
-    {
-      "filename" : "1024_-16.png",
-      "idiom" : "mac",
-      "scale" : "1x",
-      "size" : "16x16"
-    },
-    {
-      "filename" : "1024_-32.png",
-      "idiom" : "mac",
-      "scale" : "2x",
-      "size" : "16x16"
-    },
-    {
-      "filename" : "1024_-33.png",
-      "idiom" : "mac",
-      "scale" : "1x",
-      "size" : "32x32"
-    },
-    {
-      "filename" : "1024_-64.png",
-      "idiom" : "mac",
-      "scale" : "2x",
-      "size" : "32x32"
-    },
-    {
-      "filename" : "1024_-128.png",
-      "idiom" : "mac",
-      "scale" : "1x",
-      "size" : "128x128"
-    },
-    {
-      "filename" : "1024_-256.png",
-      "idiom" : "mac",
-      "scale" : "2x",
-      "size" : "128x128"
-    },
-    {
-      "filename" : "1024_-257.png",
-      "idiom" : "mac",
-      "scale" : "1x",
-      "size" : "256x256"
-    },
-    {
-      "filename" : "1024_-512.png",
-      "idiom" : "mac",
-      "scale" : "2x",
-      "size" : "256x256"
-    },
-    {
-      "filename" : "1024_-513.png",
-      "idiom" : "mac",
-      "scale" : "1x",
-      "size" : "512x512"
-    },
-    {
-      "filename" : "1024_-1025.png",
-      "idiom" : "mac",
-      "scale" : "2x",
-      "size" : "512x512"
-    },
-    {
-      "filename" : "1024_-1024 1.png",
-      "idiom" : "universal",
-      "platform" : "watchos",
-      "size" : "1024x1024"
-    }
-  ],
-  "info" : {
-    "author" : "xcode",
-    "version" : 1
-  }
-}

+ 20 - 0
FreeAPS/Resources/Assets.xcassets/iAPS.appiconset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "filename" : "iAPS Text.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "filename" : "iAPS Text 1.png",
+      "idiom" : "universal",
+      "platform" : "watchos",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
FreeAPS/Resources/Assets.xcassets/iAPS.appiconset/iAPS Text 1.png


BIN
FreeAPS/Resources/Assets.xcassets/iAPS.appiconset/iAPS Text.png


+ 20 - 0
FreeAPS/Resources/Assets.xcassets/iAPS_Black.appiconset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "filename" : "iAPS Icon2.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "filename" : "iAPS Icon2 1.png",
+      "idiom" : "universal",
+      "platform" : "watchos",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Black.appiconset/iAPS Icon2 1.png


BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Black.appiconset/iAPS Icon2.png


+ 20 - 0
FreeAPS/Resources/Assets.xcassets/iAPS_Black_Black.appiconset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "filename" : "iAPS Icon4.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "filename" : "iAPS Icon4 1.png",
+      "idiom" : "universal",
+      "platform" : "watchos",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Black_Black.appiconset/iAPS Icon4 1.png


BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Black_Black.appiconset/iAPS Icon4.png


+ 20 - 0
FreeAPS/Resources/Assets.xcassets/iAPS_Clean.appiconset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "filename" : "Logo_Pink.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "filename" : "Logo_Pink 1.png",
+      "idiom" : "universal",
+      "platform" : "watchos",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Clean.appiconset/Logo_Pink 1.png


BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Clean.appiconset/Logo_Pink.png


+ 20 - 0
FreeAPS/Resources/Assets.xcassets/iAPS_Glow_BG.appiconset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "filename" : "iAPS Icon1.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "filename" : "iAPS Icon1 1.png",
+      "idiom" : "universal",
+      "platform" : "watchos",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Glow_BG.appiconset/iAPS Icon1 1.png


BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Glow_BG.appiconset/iAPS Icon1.png


+ 20 - 0
FreeAPS/Resources/Assets.xcassets/iAPS_Gray.appiconset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "filename" : "iAPS Pump_Bevel.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "filename" : "iAPS Pump_Bevel 1.png",
+      "idiom" : "universal",
+      "platform" : "watchos",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Gray.appiconset/iAPS Pump_Bevel 1.png


BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Gray.appiconset/iAPS Pump_Bevel.png


+ 20 - 0
FreeAPS/Resources/Assets.xcassets/iAPS_Gray_Flat.appiconset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "filename" : "iAPS Pump_Black.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "filename" : "iAPS Pump_Black 1.png",
+      "idiom" : "universal",
+      "platform" : "watchos",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Gray_Flat.appiconset/iAPS Pump_Black 1.png


BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Gray_Flat.appiconset/iAPS Pump_Black.png


+ 20 - 0
FreeAPS/Resources/Assets.xcassets/iAPS_Gray_No_Buttons_BBG.appiconset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "filename" : "iAPS Pump_Bevel2_Black.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "filename" : "iAPS Pump_Bevel2_Black 1.png",
+      "idiom" : "universal",
+      "platform" : "watchos",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Gray_No_Buttons_BBG.appiconset/iAPS Pump_Bevel2_Black 1.png


BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Gray_No_Buttons_BBG.appiconset/iAPS Pump_Bevel2_Black.png


+ 20 - 0
FreeAPS/Resources/Assets.xcassets/iAPS_Loop.appiconset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "filename" : "imageLoop.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "filename" : "imageLoop 1.png",
+      "idiom" : "universal",
+      "platform" : "watchos",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Loop.appiconset/imageLoop 1.png


BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Loop.appiconset/imageLoop.png


+ 20 - 0
FreeAPS/Resources/Assets.xcassets/iAPS_Loop_Text.appiconset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "filename" : "image.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "filename" : "image 1.png",
+      "idiom" : "universal",
+      "platform" : "watchos",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Loop_Text.appiconset/image 1.png


BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Loop_Text.appiconset/image.png


+ 20 - 0
FreeAPS/Resources/Assets.xcassets/iAPS_NoButtons_Gray_White_BG.appiconset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "filename" : "iAPS_NoButtons_Gray1024x1024.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "filename" : "iAPS Pump_Bevel2_Transparent.png",
+      "idiom" : "universal",
+      "platform" : "watchos",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
FreeAPS/Resources/Assets.xcassets/iAPS_NoButtons_Gray_White_BG.appiconset/iAPS Pump_Bevel2_Transparent.png


BIN
FreeAPS/Resources/Assets.xcassets/iAPS_NoButtons_Gray_White_BG.appiconset/iAPS_NoButtons_Gray1024x1024.png


+ 20 - 0
FreeAPS/Resources/Assets.xcassets/iAPS_Purple.appiconset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "filename" : "iAPS Pump_FlatGradient.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "filename" : "iAPS Pump_FlatGradient 1.png",
+      "idiom" : "universal",
+      "platform" : "watchos",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Purple.appiconset/iAPS Pump_FlatGradient 1.png


BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Purple.appiconset/iAPS Pump_FlatGradient.png


+ 20 - 0
FreeAPS/Resources/Assets.xcassets/iAPS_Purple_BG.appiconset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "filename" : "iAPS Icon3.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "filename" : "iAPS Icon3 1.png",
+      "idiom" : "universal",
+      "platform" : "watchos",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Purple_BG.appiconset/iAPS Icon3 1.png


BIN
FreeAPS/Resources/Assets.xcassets/iAPS_Purple_BG.appiconset/iAPS Icon3.png


+ 20 - 0
FreeAPS/Resources/Assets.xcassets/iAPS_WhiteAndGray.appiconset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "filename" : "iAPS Pump_White.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "filename" : "iAPS Pump_White 1.png",
+      "idiom" : "universal",
+      "platform" : "watchos",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
FreeAPS/Resources/Assets.xcassets/iAPS_WhiteAndGray.appiconset/iAPS Pump_White 1.png


BIN
FreeAPS/Resources/Assets.xcassets/iAPS_WhiteAndGray.appiconset/iAPS Pump_White.png


+ 20 - 0
FreeAPS/Resources/Assets.xcassets/iAPS_White_BG.appiconset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "filename" : "iAPS Icon5.png",
+      "idiom" : "universal",
+      "platform" : "ios",
+      "size" : "1024x1024"
+    },
+    {
+      "filename" : "iAPS Icon5 1.png",
+      "idiom" : "universal",
+      "platform" : "watchos",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
FreeAPS/Resources/Assets.xcassets/iAPS_White_BG.appiconset/iAPS Icon5 1.png


BIN
FreeAPS/Resources/Assets.xcassets/iAPS_White_BG.appiconset/iAPS Icon5.png


+ 2 - 0
FreeAPS/Resources/Info.plist

@@ -104,6 +104,8 @@
 		<string>UIInterfaceOrientationPortrait</string>
 		<string>UIInterfaceOrientationPortraitUpsideDown</string>
 	</array>
+	<key>CBBundleDisplayName</key>
+	<string>$(APP_DISPLAY_NAME)</string>
 	<key>UISupportedInterfaceOrientations~ipad</key>
 	<array>
 		<string>UIInterfaceOrientationPortrait</string>

Разница между файлами не показана из-за своего большого размера
+ 1 - 1
FreeAPS/Resources/javascript/bundle/determine-basal.js


+ 6 - 6
FreeAPS/Resources/javascript/prepare/determine-basal.js

@@ -1,11 +1,11 @@
 //для enact/smb-suggested.json параметры: monitor/iob.json monitor/temp_basal.json monitor/glucose.json settings/profile.json settings/autosens.json --meal monitor/meal.json --microbolus --reservoir monitor/reservoir.json
 
-function generate(iob, currenttemp, glucose, profile, autosens = null, meal = null, microbolusAllowed = false, reservoir = null, clock = new Date(), pump_history, preferences, basalProfile, tdd_averages) {
+function generate(iob, currenttemp, glucose, profile, autosens = null, meal = null, microbolusAllowed = false, reservoir = null, clock = new Date(), pump_history, preferences, basalProfile, oref2_variables) {
 
     var clock = new Date();
     
     try {
-        var middlewareReason = middleware(iob, currenttemp, glucose, profile, autosens, meal, reservoir, clock, pump_history, preferences, basalProfile, tdd_averages);
+        var middlewareReason = middleware(iob, currenttemp, glucose, profile, autosens, meal, reservoir, clock, pump_history, preferences, basalProfile, oref2_variables);
         console.log("Middleware reason: " + (middlewareReason || "Nothing changed"));
     } catch (error) {
         console.log("Invalid middleware: " + error);
@@ -44,10 +44,10 @@ function generate(iob, currenttemp, glucose, profile, autosens = null, meal = nu
     }
      */
     
-    var tdd_averages_ = {};
-    if (tdd_averages) {
-        tdd_averages_ = tdd_averages;
+    var oref2_variables_ = {};
+    if (oref2_variables) {
+        oref2_variables_ = oref2_variables;
     }
     
-    return freeaps_determineBasal(glucose_status, currenttemp, iob, profile, autosens_data, meal_data, freeaps_basalSetTemp, microbolusAllowed, reservoir_data, clock, pumphistory, preferences, basalprofile, tdd_averages_);
+    return freeaps_determineBasal(glucose_status, currenttemp, iob, profile, autosens_data, meal_data, freeaps_basalSetTemp, microbolusAllowed, reservoir_data, clock, pumphistory, preferences, basalprofile, oref2_variables_);
 }

+ 115 - 10
FreeAPS/Sources/APS/APSManager.swift

@@ -81,7 +81,8 @@ final class BaseAPSManager: APSManager, Injectable {
         }
     }
 
-    let coredataContext = CoreDataStack.shared.persistentContainer.newBackgroundContext()
+    // let coredataContext = CoreDataStack.shared.persistentContainer.newBackgroundContext()
+    let coredataContext = CoreDataStack.shared.persistentContainer.viewContext
 
     private var openAPS: OpenAPS!
 
@@ -713,7 +714,15 @@ final class BaseAPSManager: APSManager, Injectable {
         let preferences = settingsManager.preferences
         let currentTDD = enacted_.tdd ?? 0
 
-        // MARK: Fetch data from Core Data: TDD Entity. TEST:
+        var booleanArray = [ViewPercentage]()
+        var overrideArray = [Override]()
+        var isPercentageEnabled = false
+        var useOverride = false
+        var overridePercentage: Decimal = 100
+        var duration: Decimal = 0
+        var unlimited: Bool = false
+        var newDuration: Decimal = 0
+        var hbtSetting: Decimal = 160
 
         if currentTDD > 0 {
             let tenDaysAgo = Date().addingTimeInterval(-10.days.timeInterval)
@@ -725,9 +734,6 @@ final class BaseAPSManager: APSManager, Injectable {
             var indeces: Int = 0
             var nrOfIndeces: Int = 0
 
-            var booleanArray = [ViewPercentage]()
-            var isPercentageEnabled = false
-
             coredataContext.performAndWait {
                 let requestTDD = TDD.fetchRequest() as NSFetchRequest<TDD>
                 requestTDD.predicate = NSPredicate(format: "timestamp > %@ AND tdd > 0", tenDaysAgo as NSDate)
@@ -741,6 +747,12 @@ final class BaseAPSManager: APSManager, Injectable {
                 requestIsEnbled.fetchLimit = 1
                 try? booleanArray = coredataContext.fetch(requestIsEnbled)
 
+                let requestOverrides = Override.fetchRequest() as NSFetchRequest<Override>
+                let sortOverride = NSSortDescriptor(key: "date", ascending: false)
+                requestOverrides.sortDescriptors = [sortOverride]
+                requestOverrides.fetchLimit = 1
+                try? overrideArray = coredataContext.fetch(requestOverrides)
+
                 total = uniqEvents.compactMap({ each in each.tdd as? Decimal ?? 0 }).reduce(0, +)
                 indeces = uniqEvents.count
                 // Only fetch once. Use same (previous) fetch
@@ -761,20 +773,113 @@ final class BaseAPSManager: APSManager, Injectable {
             let weight = preferences.weightPercentage
             let weighted_average = weight * average2hours + (1 - weight) * average14
 
-            if !booleanArray.isEmpty {
-                isPercentageEnabled = booleanArray[0].enabled
+            isPercentageEnabled = booleanArray.first?.enabled ?? false
+            useOverride = overrideArray.first?.enabled ?? false
+            overridePercentage = Decimal(overrideArray.first?.percentage ?? 100)
+            unlimited = overrideArray.first?.indefinite ?? true
+            hbtSetting = Decimal(booleanArray.first?.hbt ?? 160)
+
+            if useOverride {
+                duration = (overrideArray.first?.duration ?? 0) as Decimal
+                let addedMinutes = Int(duration)
+                let date = overrideArray.first?.date ?? Date()
+                if date.addingTimeInterval(addedMinutes.minutes.timeInterval) < Date(),
+                   !unlimited
+                { useOverride = false }
+
+                newDuration = Decimal(Date().distance(to: date.addingTimeInterval(addedMinutes.minutes.timeInterval)).minutes)
             }
 
-            let averages = TDD_averages(
+            if newDuration < 0 {
+                newDuration = 0
+            } else { duration = newDuration }
+
+            if !useOverride {
+                unlimited = true
+                overridePercentage = 100
+                duration = 0
+            }
+
+            let averages = Oref2_variables(
                 average_total_data: roundDecimal(average14, 1),
                 weightedAverage: roundDecimal(weighted_average, 1),
                 past2hoursAverage: roundDecimal(average2hours, 1),
                 date: Date(),
-                isEnabled: isPercentageEnabled
+                isEnabled: isPercentageEnabled,
+                overridePercentage: overridePercentage,
+                useOverride: useOverride,
+                duration: duration,
+                unlimited: unlimited,
+                hbt: hbtSetting
             )
-            storage.save(averages, as: OpenAPS.Monitor.tdd_averages)
+            storage.save(averages, as: OpenAPS.Monitor.oref2_variables)
 
             print("Test time of TDD: \(-1 * tddStartedAt.timeIntervalSinceNow) s")
+        } else {
+            coredataContext.performAndWait {
+                let requestIsEnbled = ViewPercentage.fetchRequest() as NSFetchRequest<ViewPercentage>
+                let sortIsEnabled = NSSortDescriptor(key: "date", ascending: false)
+                requestIsEnbled.sortDescriptors = [sortIsEnabled]
+                requestIsEnbled.fetchLimit = 1
+                try? booleanArray = coredataContext.fetch(requestIsEnbled)
+
+                let requestOverrides = Override.fetchRequest() as NSFetchRequest<Override>
+                let sortOverride = NSSortDescriptor(key: "date", ascending: false)
+                requestOverrides.sortDescriptors = [sortOverride]
+                requestOverrides.fetchLimit = 1
+                try? overrideArray = coredataContext.fetch(requestOverrides)
+            }
+
+            isPercentageEnabled = booleanArray.first?.enabled ?? false
+            useOverride = overrideArray.first?.enabled ?? false
+            overridePercentage = Decimal(overrideArray.first?.percentage ?? 100)
+            unlimited = overrideArray.first?.indefinite ?? true
+            hbtSetting = Decimal(booleanArray.first?.hbt ?? 160)
+
+            if useOverride {
+                duration = (overrideArray.first?.duration ?? 0) as Decimal
+                let addedMinutes = Int(duration)
+                let date = overrideArray.first?.date ?? Date()
+                if date.addingTimeInterval(addedMinutes.minutes.timeInterval) < Date(),
+                   !unlimited
+                { useOverride = false }
+
+                newDuration = Decimal(Date().distance(to: date.addingTimeInterval(addedMinutes.minutes.timeInterval)).minutes)
+            }
+
+            if newDuration < 0 {
+                newDuration = 0
+            } else { duration = newDuration }
+
+            if !useOverride {
+                unlimited = true
+                overridePercentage = 100
+                duration = 0
+            }
+
+            let averages = Oref2_variables(
+                average_total_data: 0,
+                weightedAverage: 1,
+                past2hoursAverage: 0,
+                date: Date(),
+                isEnabled: isPercentageEnabled,
+                overridePercentage: overridePercentage,
+                useOverride: useOverride,
+                duration: duration,
+                unlimited: unlimited,
+                hbt: hbtSetting
+            )
+            storage.save(averages, as: OpenAPS.Monitor.oref2_variables)
+        }
+
+        coredataContext.performAndWait {
+            let saveNewUseOverride = Override(context: self.coredataContext)
+            saveNewUseOverride.date = Date()
+            saveNewUseOverride.enabled = useOverride
+            saveNewUseOverride.percentage = Double(overridePercentage)
+            saveNewUseOverride.duration = newDuration as NSDecimalNumber
+            saveNewUseOverride.indefinite = unlimited
+            try? self.coredataContext.save()
         }
     }
 

+ 1 - 1
FreeAPS/Sources/APS/OpenAPS/Constants.swift

@@ -55,7 +55,7 @@ extension OpenAPS {
         static let cgmState = "monitor/cgm-state.json"
         static let podAge = "monitor/pod-age.json"
         // static let tdd = "monitor/tdd.json"
-        static let tdd_averages = "monitor/tdd_averages.json"
+        static let oref2_variables = "monitor/oref2_variables.json"
         static let alertHistory = "monitor/alerthistory.json"
         static let statistics = "monitor/statistics.json"
     }

+ 4 - 4
FreeAPS/Sources/APS/OpenAPS/OpenAPS.swift

@@ -44,7 +44,7 @@ final class OpenAPS {
 
                 self.storage.save(meal, as: Monitor.meal)
 
-                let tdd_averages = self.loadFileFromStorage(name: OpenAPS.Monitor.tdd_averages)
+                let oref2_variables = self.loadFileFromStorage(name: OpenAPS.Monitor.oref2_variables)
 
                 // iob
                 let autosens = self.loadFileFromStorage(name: Settings.autosense)
@@ -74,7 +74,7 @@ final class OpenAPS {
                     pumpHistory: pumpHistory,
                     preferences: preferences,
                     basalProfile: basalProfile,
-                    tdd_averages: tdd_averages
+                    oref2_variables: oref2_variables
                 )
                 debug(.openAPS, "SUGGESTED: \(suggested)")
 
@@ -333,7 +333,7 @@ final class OpenAPS {
         pumpHistory: JSON,
         preferences: JSON,
         basalProfile: JSON,
-        tdd_averages: JSON
+        oref2_variables: JSON
     ) -> RawJSON {
         dispatchPrecondition(condition: .onQueue(processQueue))
         return jsWorker.inCommonContext { worker in
@@ -362,7 +362,7 @@ final class OpenAPS {
                     pumpHistory,
                     preferences,
                     basalProfile,
-                    tdd_averages
+                    oref2_variables
                 ]
             )
         }

+ 0 - 1
FreeAPS/Sources/Application/FreeAPSApp.swift

@@ -57,7 +57,6 @@ import Swinject
     var body: some Scene {
         WindowGroup {
             Main.RootView(resolver: resolver)
-
                 .environment(\.managedObjectContext, dataController.persistentContainer.viewContext)
         }
         .onChange(of: scenePhase) { newScenePhase in

+ 23 - 3
FreeAPS/Sources/Models/TDD_averages.swift

@@ -1,33 +1,53 @@
 import Foundation
 
-struct TDD_averages: JSON, Equatable {
+struct Oref2_variables: JSON, Equatable {
     var average_total_data: Decimal
     var weightedAverage: Decimal
     var past2hoursAverage: Decimal
     var date: Date
     var isEnabled: Bool
+    var overridePercentage: Decimal
+    var useOverride: Bool
+    var duration: Decimal
+    var unlimited: Bool
+    var hbt: Decimal
 
     init(
         average_total_data: Decimal,
         weightedAverage: Decimal,
         past2hoursAverage: Decimal,
         date: Date,
-        isEnabled: Bool
+        isEnabled: Bool,
+        overridePercentage: Decimal,
+        useOverride: Bool,
+        duration: Decimal,
+        unlimited: Bool,
+        hbt: Decimal
     ) {
         self.average_total_data = average_total_data
         self.weightedAverage = weightedAverage
         self.past2hoursAverage = past2hoursAverage
         self.date = date
         self.isEnabled = isEnabled
+        self.overridePercentage = overridePercentage
+        self.useOverride = useOverride
+        self.duration = duration
+        self.unlimited = unlimited
+        self.hbt = hbt
     }
 }
 
-extension TDD_averages {
+extension Oref2_variables {
     private enum CodingKeys: String, CodingKey {
         case average_total_data
         case weightedAverage
         case past2hoursAverage
         case date
         case isEnabled
+        case overridePercentage
+        case useOverride
+        case duration
+        case unlimited
+        case hbt
     }
 }

+ 8 - 4
FreeAPS/Sources/Modules/AddTempTarget/AddTempTargetStateModel.swift

@@ -14,8 +14,9 @@ extension AddTempTarget {
         @Published var presets: [TempTarget] = []
         @Published var percentage = 100.0
         @Published var maxValue: Decimal = 1.2
-        @Published var halfBasal: Decimal = 160
         @Published var viewPercantage = false
+        @Published var hbt: Double = 160
+        @Published var saveSettings: Bool = false
 
         private(set) var units: GlucoseUnits = .mmolL
 
@@ -23,7 +24,6 @@ extension AddTempTarget {
             units = settingsManager.settings.units
             presets = storage.presets()
             maxValue = settingsManager.preferences.autosensMax
-            halfBasal = settingsManager.preferences.halfBasalExerciseTarget
         }
 
         func enact() {
@@ -31,7 +31,7 @@ extension AddTempTarget {
 
             if viewPercantage {
                 var ratio = Decimal(percentage / 100)
-                let hB = halfBasal
+                let hB = Decimal(hbt)
                 let c = hB - 100
                 var target = (c / ratio) - c + 100
 
@@ -41,6 +41,7 @@ extension AddTempTarget {
                 }
                 lowTarget = target
                 lowTarget = Decimal(round(Double(target)))
+                saveSettings = true
             }
             var highTarget = lowTarget
 
@@ -72,7 +73,7 @@ extension AddTempTarget {
 
             if viewPercantage {
                 var ratio = Decimal(percentage / 100)
-                let hB = halfBasal
+                let hB = Decimal(hbt)
                 let c = hB - 100
                 var target = (c / ratio) - c + 100
 
@@ -82,6 +83,7 @@ extension AddTempTarget {
                 }
                 lowTarget = target
                 lowTarget = Decimal(round(Double(target)))
+                saveSettings = true
             }
             var highTarget = lowTarget
 
@@ -111,6 +113,8 @@ extension AddTempTarget {
             }
         }
 
+        func savedHBT() {}
+
         func removePreset(id: String) {
             presets = presets.filter { $0.id != id }
             storage.storePresets(presets)

+ 31 - 18
FreeAPS/Sources/Modules/AddTempTarget/View/AddTempTargetRootView.swift

@@ -13,7 +13,7 @@ extension AddTempTarget {
 
         @FetchRequest(
             entity: ViewPercentage.entity(),
-            sortDescriptors: [NSSortDescriptor(key: "enabled", ascending: false)]
+            sortDescriptors: [NSSortDescriptor(key: "date", ascending: false)]
         ) var isEnabledArray: FetchedResults<ViewPercentage>
 
         @Environment(\.managedObjectContext) var moc
@@ -36,21 +36,17 @@ extension AddTempTarget {
                 }
 
                 Toggle(isOn: $state.viewPercantage) {
-                    Text("Exercise / Pre Meal Slider")
+                    HStack {
+                        Text("Use Slider for")
+                        Image(systemName: "figure.highintensity.intervaltraining")
+                        Text("or")
+                        Image(systemName: "fork.knife")
+                    }
                 }
 
                 if state.viewPercantage {
                     Section(
-                        header: Text("Effect of TT on Basal and Sensitivity"),
-                        footer: Text(
-                            NSLocalizedString(
-                                "'Half Basal Target' (HBT) setting adjusts how a temp target affects basal and ISF.\n     A lower HBT will allow Basal to be reduced earlier (at a less high TT).\n",
-                                comment: ""
-                            ) +
-                                NSLocalizedString("     HBT setting: ", comment: "") + "\(state.halfBasal) " +
-                                NSLocalizedString("mg/dl. Autosens.max setting determines the max endpoint", comment: "") +
-                                " (\(state.maxValue): \(state.maxValue * 100) %)"
-                        )
+                        header: Text("Percent Insulin")
                     ) {
                         VStack {
                             Slider(
@@ -67,14 +63,27 @@ extension AddTempTarget {
                                 .font(.largeTitle)
                             Divider()
                             Text(
-                                NSLocalizedString("Temp Target to Save", comment: "") +
+                                NSLocalizedString("Target glucose", comment: "") +
                                     (
                                         state
                                             .units == .mmolL ?
                                             ": \(computeTarget().asMmolL.formatted(.number.grouping(.never).rounded().precision(.fractionLength(1)))) mmol/L" :
                                             ": \(computeTarget().formatted(.number.grouping(.never).rounded().precision(.fractionLength(0)))) mg/dl"
                                     )
-                            ).foregroundColor(.primary).italic()
+                            ) // .foregroundColor(.primary).italic()
+
+                            Slider(
+                                value: $state.hbt,
+                                in: 120 ... 180,
+                                step: 1
+                            )
+                            Text(
+                                state
+                                    .units == .mgdL ? "Half normal Basal at: \(state.hbt.formatted(.number)) mg/dl" :
+                                    "Half normal Basal at: \(state.hbt.asMmolL.formatted(.number.grouping(.never).rounded().precision(.fractionLength(1)))) mmol/L"
+                            )
+                            .foregroundColor(.green)
+                            .font(.caption).italic()
                         }
                     }
                 } else {
@@ -131,20 +140,25 @@ extension AddTempTarget {
                     }
                 }
             }
-            .onAppear(perform: configureView)
+            .onAppear {
+                configureView()
+                state.hbt = isEnabledArray.first?.hbt ?? 160
+            }
             .navigationTitle("Enact Temp Target")
             .navigationBarTitleDisplayMode(.automatic)
             .navigationBarItems(leading: Button("Close", action: state.hideModal))
             .onDisappear {
-                if state.viewPercantage {
+                if state.viewPercantage, state.saveSettings {
                     let isEnabledMoc = ViewPercentage(context: moc)
                     isEnabledMoc.enabled = true
                     isEnabledMoc.date = Date()
+                    isEnabledMoc.hbt = state.hbt
                     try? moc.save()
                 } else {
                     let isEnabledMoc = ViewPercentage(context: moc)
                     isEnabledMoc.enabled = false
                     isEnabledMoc.date = Date()
+                    isEnabledMoc.hbt = isEnabledArray.first?.hbt ?? 160
                     try? moc.save()
                 }
             }
@@ -152,8 +166,7 @@ extension AddTempTarget {
 
         func computeTarget() -> Decimal {
             var ratio = Decimal(state.percentage / 100)
-            let hB = state.halfBasal
-            let c = hB - 100
+            let c = Decimal(state.hbt - 100)
             var target = (c / ratio) - c + 100
 
             if c * (c + target - 100) <= 0 {

+ 26 - 0
FreeAPS/Sources/Modules/Home/View/HomeRootView.swift

@@ -1,3 +1,4 @@
+import CoreData
 import SpriteKit
 import SwiftDate
 import SwiftUI
@@ -25,6 +26,11 @@ extension Home {
         // Switch between Loops and Errors when tapping in statPanel
         @State var loopStatTitle = NSLocalizedString("Loops", comment: "Nr of Loops in statPanel")
 
+        @FetchRequest(
+            entity: Override.entity(),
+            sortDescriptors: [NSSortDescriptor(key: "date", ascending: false)]
+        ) var fetchedPercent: FetchedResults<Override>
+
         private var numberFormatter: NumberFormatter {
             let formatter = NumberFormatter()
             formatter.numberStyle = .decimal
@@ -224,7 +230,27 @@ extension Home {
                         }
                     }
                 }
+
                 Spacer()
+
+                Text(
+                    (fetchedPercent.first?.enabled ?? false) ?
+                        "\((fetchedPercent.first?.percentage ?? 100).formatted(.number)) % " : ""
+                )
+                .font(.system(size: 12, weight: .bold))
+                .foregroundColor(.orange)
+                .padding(.trailing, 2)
+                if fetchedPercent.first?.enabled ?? false {
+                    Text(
+                        (tirFormatter.string(from: (fetchedPercent.first?.duration ?? 0) as NSNumber) ?? "") == "0" ?
+                            "Perpetual" :
+                            (tirFormatter.string(from: (fetchedPercent.first?.duration ?? 0) as NSNumber) ?? "") + " min"
+                    )
+                    .font(.system(size: 12))
+                    .foregroundColor(.orange)
+                    .padding(.trailing, 8)
+                }
+
                 if let progress = state.bolusProgress {
                     Text("Bolusing")
                         .font(.system(size: 12, weight: .bold)).foregroundColor(.insulin)

+ 5 - 0
FreeAPS/Sources/Modules/OverrideProfilesConfig/OverrideProfilesDataFlow.swift

@@ -0,0 +1,5 @@
+enum OverrideProfilesConfig {
+    enum Config {}
+}
+
+protocol OverrideProfilesProvider: Provider {}

+ 3 - 0
FreeAPS/Sources/Modules/OverrideProfilesConfig/OverrideProfilesProvider.swift

@@ -0,0 +1,3 @@
+extension OverrideProfilesConfig {
+    final class Provider: BaseProvider, OverrideProfilesProvider {}
+}

+ 59 - 0
FreeAPS/Sources/Modules/OverrideProfilesConfig/OverrideProfilesStateModel.swift

@@ -0,0 +1,59 @@
+import CoreData
+import SwiftUI
+
+extension OverrideProfilesConfig {
+    final class StateModel: BaseStateModel<Provider> {
+        @Published var percentage: Double = 100
+        @Published var isEnabled = false
+        @Published var _indefinite = true
+        @Published var duration: Decimal = 0
+
+        let coredataContext = CoreDataStack.shared.persistentContainer.viewContext
+
+        func saveSettings() {
+            coredataContext.perform {
+                let saveOverride = Override(context: self.coredataContext)
+                saveOverride.duration = self.duration as NSDecimalNumber
+                saveOverride.indefinite = self._indefinite
+                saveOverride.percentage = self.percentage
+                saveOverride.enabled = self.isEnabled
+                saveOverride.date = Date()
+                try? self.coredataContext.save()
+            }
+        }
+
+        func savedSettings() {
+            coredataContext.performAndWait {
+                var overrideArray = [Override]()
+                let requestEnabled = Override.fetchRequest() as NSFetchRequest<Override>
+                let sortIsEnabled = NSSortDescriptor(key: "date", ascending: false)
+                requestEnabled.sortDescriptors = [sortIsEnabled]
+                requestEnabled.fetchLimit = 1
+                try? overrideArray = coredataContext.fetch(requestEnabled)
+                isEnabled = overrideArray.first?.enabled ?? false
+                percentage = overrideArray.first?.percentage ?? 100
+                _indefinite = overrideArray.first?.indefinite ?? true
+                duration = (overrideArray.first?.duration ?? 0) as Decimal
+
+                var newDuration = Double(duration)
+                if isEnabled {
+                    let duration = overrideArray.first?.duration ?? 0
+                    let addedMinutes = Int(duration as Decimal)
+                    let date = overrideArray.first?.date ?? Date()
+                    if date.addingTimeInterval(addedMinutes.minutes.timeInterval) < Date(), !_indefinite {
+                        isEnabled = false
+                    }
+                    newDuration = Date().distance(to: date.addingTimeInterval(addedMinutes.minutes.timeInterval)).minutes
+                }
+
+                if newDuration < 0 { newDuration = 0 } else { duration = Decimal(newDuration) }
+
+                if !isEnabled {
+                    _indefinite = true
+                    percentage = 100
+                    duration = 0
+                }
+            }
+        }
+    }
+}

+ 107 - 0
FreeAPS/Sources/Modules/OverrideProfilesConfig/View/OverrideProfilesRootView.swift

@@ -0,0 +1,107 @@
+import CoreData
+import SwiftUI
+import Swinject
+
+extension OverrideProfilesConfig {
+    struct RootView: BaseView {
+        let resolver: Resolver
+
+        @StateObject var state = StateModel()
+        @State private var isEditing = false
+        @State private var showAlert = false
+        @State private var showingDetail = false
+        @State private var isPresented = true
+        @Environment(\.dismiss) var dismiss
+
+        private var formatter: NumberFormatter {
+            let formatter = NumberFormatter()
+            formatter.numberStyle = .decimal
+            formatter.maximumFractionDigits = 0
+            return formatter
+        }
+
+        var body: some View {
+            Form {
+                Section(
+                    header: Text("Override your Basal, ISF and CR profiles"),
+                    footer: Text("" + (!state.isEnabled ? "Currently no Override active" : ""))
+                ) {
+                    Toggle(isOn: $state.isEnabled) {
+                        Text("Override Profiles")
+                    }._onBindingChange($state.isEnabled, perform: { _ in
+                        if !state.isEnabled {
+                            state.duration = 0
+                            state.percentage = 100
+                            state._indefinite = false
+                            state.saveSettings()
+                        }
+                    })
+                }
+                if state.isEnabled {
+                    Section(
+                        header: Text("Total Insulin Adjustment"),
+                        footer: Text(
+                            "Your profile basal insulin will be adjusted with the override percentage and your profile ISF and CR will be inversly adjusted with the percentage.\n\nIf you toggle off the override every profile setting will return to normal."
+                        )
+                    ) {
+                        VStack {
+                            Slider(
+                                value: $state.percentage,
+                                in: 10 ... 200,
+                                step: 1,
+                                onEditingChanged: { editing in
+                                    isEditing = editing
+                                }
+                            )
+                            Text("\(state.percentage.formatted(.number)) %")
+                                .foregroundColor(isEditing ? .orange : .blue)
+                                .font(.largeTitle)
+                            Spacer()
+                            Toggle(isOn: $state._indefinite) {
+                                Text("Enable indefinitely")
+                            }
+                        }
+                        if !state._indefinite {
+                            HStack {
+                                Text("Duration")
+                                DecimalTextField("0", value: $state.duration, formatter: formatter, cleanInput: false)
+                                Text("minutes").foregroundColor(.secondary)
+                            }
+                        }
+                        Button("Save") {
+                            showAlert.toggle()
+                        }
+                        .disabled(
+                            state.isEnabled == false || state
+                                .percentage == 100 || (!state._indefinite && state.duration == 0)
+                        )
+                        .accentColor(.orange)
+                        .buttonStyle(BorderlessButtonStyle())
+                        .font(.callout)
+                        .frame(maxWidth: .infinity, alignment: .center)
+                        .controlSize(.mini)
+                        .alert(
+                            "Saving this override will change your basal insulin, ISF and CR during the entire selected duration. Tapping save will start your new overide or edit your current active override.",
+                            isPresented: $showAlert,
+                            actions: {
+                                Button("Cancel", role: .cancel) {}
+                                Button("Start Override", role: .destructive) {
+                                    if state.percentage == 100 {
+                                        state.isEnabled = false
+                                    } else { state.isEnabled = true }
+                                    if state._indefinite {
+                                        state.duration = 0
+                                    } else if state.duration == 0 {
+                                        state.isEnabled = false
+                                    }
+                                    state.saveSettings()
+                                    dismiss()
+                                }
+                            }
+                        )
+                    }
+                }
+            }.onAppear { state.savedSettings() }
+        }
+    }
+}

+ 1 - 0
FreeAPS/Sources/Modules/Settings/View/SettingsRootView.swift

@@ -30,6 +30,7 @@ extension Settings {
                     }
                     Text("Notifications").navigationLink(to: .notificationsConfig, from: self)
                     Text("Fat And Protein Conversion").navigationLink(to: .fpuConfig, from: self)
+                    Text("Profile Override").navigationLink(to: .overrideProfilesConfig, from: self)
                 }
 
                 Section(header: Text("Configuration")) {

+ 3 - 0
FreeAPS/Sources/Router/Screen.swift

@@ -26,6 +26,7 @@ enum Screen: Identifiable, Hashable {
     case calibrations
     case notificationsConfig
     case fpuConfig
+    case overrideProfilesConfig
     case snooze
 
     var id: Int { String(reflecting: self).hashValue }
@@ -85,6 +86,8 @@ extension Screen {
             NotificationsConfig.RootView(resolver: resolver)
         case .fpuConfig:
             FPUConfig.RootView(resolver: resolver)
+        case .overrideProfilesConfig:
+            OverrideProfilesConfig.RootView(resolver: resolver)
         case .snooze:
             Snooze.RootView(resolver: resolver)
         }

+ 10 - 0
FreeAPSWatch/Info.plist

@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>CFBundleIcons</key>
+	<dict/>
+	<key>CFBundleIcons~ipad</key>
+	<dict/>
+</dict>
+</plist>

+ 1 - 1
README.md

@@ -69,4 +69,4 @@ Code contributions as PRs are welcome!
 
 Translators can click the Crowdin link above  
 
-For questions or contributions: jon.m@live.se
+For questions or other contributions: jon.m@live.se

+ 0 - 88
README_RU.md

@@ -1,88 +0,0 @@
-# FreeAPS X
-
-FreeAPS X - система искуственной поджелудочной железы для iOS на основе алгоритмов [OpenAPS Reference](https://github.com/openaps/oref0)
-
-FreeAPS X использует оригинальные JavaScript файлы oref0 и предоставляет пользовательский интерфейс (UI) для управления и настроек системы.
-
-## Документация
-
-[Обзор и советы на Loop&Learn](https://www.loopandlearn.org/freeaps-x/)
-
-[Полная документация OpenAPS](https://openaps.readthedocs.io/en/latest/)
-
-## Требования к смартфону
-
-- Все iPhone с поддержкой iOS 15 и выше.
-
-## Поддерживаемые помпы
-
-Для управления инсулиновой помпой используется модифицированная версия библиотеки [rileylink_ios](https://github.com/ps2/rileylink_ios), поддерживает тот же список помп:
-
-- Medtronic 515 or 715 (any firmware)
-- Medtronic 522 or 722 (any firmware)
-- Medtronic 523 or 723 (firmware 2.4 or lower)
-- Medtronic Worldwide Veo 554 or 754 (firmware 2.6A or lower)
-- Medtronic Canadian/Australian Veo 554 or 754 (firmware 2.7A or lower)
-- Omnipod "Eros" pods
-
-Для управления помпой необходимо устройство [RileyLink](https://getrileylink.org), OrangeLink, Pickle, GNARL, Emalink, DiaLink или аналоги.
-
-## Текущее состояние FreeAPS X
-
-FreeAPS X находится в состоянии активной разработки и часто меняется.
-
-Описание версий вы можете найти на [странице релизов](https://github.com/ivalkou/freeaps/releases).
-
-### Стабильные версии
-
-Стабильная версия означет, что она была протестирована долгое время и не содерждит критических багов. Мы считаем её готовой для повседневного использования.
-
-Номера стабильных версий заканчиваются на **.0**.
-
-### Бета-версии
-
-В бета-версиях впервые появляется новая функциональность. Они предназначены для тестирования и выявления проблем и багов.
-
-**Бета-версии довольно стабильны, но могут содержать случайные ошибки.**
-
-Номера бета-версий заканчиваются на число больше **0**.
-
-## Помощь в разработке
-
-Пулл-реквесты принимаются в [dev ветку](https://github.com/ivalkou/freeaps/tree/dev).
-
-Отчеты об ошибка их запросы на новую функциональность принимаются на странице [Issues](https://github.com/ivalkou/freeaps/issues).
-
-## Реализовано
-
-- Все базовые функции oref0
-- Все базовые функции oref1 (SMB, UAM и другие)
-- Autotune
-- Autosens
-- Использование Nightscout в качестве CGM
-- Использование оффлайн локального сервера в качестве CGM (программы Spike, Diabox)
-- Использование [xDrip4iOS](https://github.com/JohanDegraeve/xdripswift) оффлан в качестве CGM через shared app gpoup
-- Использование [GlucoseDirectApp](https://github.com/creepymonster/GlucoseDirectApp) оффлан в качестве CGM через shared app gpoup
-- Использование передатчиков Libre 1 и Libre 2 напрямую в качаесте CGM
-- Простой симулятор глюкозы
-- Загрузка состояния системы в Nightscout
-- Удаленный ввод углеводов и временных целей через Nightscout
-- Удаленный ввод болюса и управление помпой
-- Поддержка Dexcom (beta)
-- Поробное описание настроек oref внутри приложения (beta)
-- Уведомления на смартфоне о состоянии системы и подключенных к ней устройств (beta)
-- Приложение для часов (beta)
-- Поддержка Enlite (beta)
-- Поддержка программы Здоровье, глюкоза (beta)
-
-## Не реализовано (планируется в будущих версиях)
-
-- Режим открытой петли
-- Загрузка профиля в Nightscout
-- Виджет на рабочий стол
-- Поддержка программы Здоровье, углеводы и инсулин
-
-## Сообщество
-
-- [Английская Telegram группа](https://t.me/freeapsx_eng)
-- [Русская Telegram группа](https://t.me/freeapsx)