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

Merge branch 'dev' into feat/dev-eversense

Deniz Cengiz 11 часов назад
Родитель
Сommit
24e2d01a70

+ 4 - 1
.gitmodules

@@ -34,6 +34,9 @@
 [submodule "MedtrumKit"]
 [submodule "MedtrumKit"]
 	path = MedtrumKit
 	path = MedtrumKit
 	url = https://github.com/loopandlearn/MedtrumKit
 	url = https://github.com/loopandlearn/MedtrumKit
+[submodule "OmnipodKit"]
+	path = OmnipodKit
+	url = https://github.com/loopandlearn/OmnipodKit
 [submodule "EversenseKit"]
 [submodule "EversenseKit"]
 	path = EversenseKit
 	path = EversenseKit
-	url = https://github.com/loopandlearn/EversenseKit
+	url = https://github.com/loopandlearn/EversenseKit

+ 2 - 2
Config.xcconfig

@@ -18,8 +18,8 @@ BUNDLE_IDENTIFIER = org.nightscout.$(DEVELOPMENT_TEAM).trio
 TRIO_APP_GROUP_ID = group.org.nightscout.$(DEVELOPMENT_TEAM).trio.trio-app-group
 TRIO_APP_GROUP_ID = group.org.nightscout.$(DEVELOPMENT_TEAM).trio.trio-app-group
 
 
 // The developers set the version numbers, please leave them alone
 // The developers set the version numbers, please leave them alone
-APP_VERSION = 0.8.0
-APP_DEV_VERSION = 0.8.0
+APP_VERSION = 0.8.1
+APP_DEV_VERSION = 0.8.1.1
 APP_BUILD_NUMBER = 1
 APP_BUILD_NUMBER = 1
 COPYRIGHT_NOTICE =
 COPYRIGHT_NOTICE =
 
 

+ 1 - 1
Gemfile

@@ -1,5 +1,5 @@
 source "https://rubygems.org"
 source "https://rubygems.org"
 
 
-gem "fastlane", "2.233.1"
+gem "fastlane", "2.235.0"
 gem "json", ">=2.19.2"
 gem "json", ">=2.19.2"
 gem "addressable", ">=2.9.0"
 gem "addressable", ">=2.9.0"

+ 51 - 46
Gemfile.lock

@@ -8,8 +8,8 @@ GEM
     artifactory (3.0.17)
     artifactory (3.0.17)
     atomos (0.1.3)
     atomos (0.1.3)
     aws-eventstream (1.4.0)
     aws-eventstream (1.4.0)
-    aws-partitions (1.1206.0)
-    aws-sdk-core (3.241.4)
+    aws-partitions (1.1254.0)
+    aws-sdk-core (3.250.0)
       aws-eventstream (~> 1, >= 1.3.0)
       aws-eventstream (~> 1, >= 1.3.0)
       aws-partitions (~> 1, >= 1.992.0)
       aws-partitions (~> 1, >= 1.992.0)
       aws-sigv4 (~> 1.9)
       aws-sigv4 (~> 1.9)
@@ -17,19 +17,19 @@ GEM
       bigdecimal
       bigdecimal
       jmespath (~> 1, >= 1.6.1)
       jmespath (~> 1, >= 1.6.1)
       logger
       logger
-    aws-sdk-kms (1.121.0)
-      aws-sdk-core (~> 3, >= 3.241.4)
+    aws-sdk-kms (1.128.0)
+      aws-sdk-core (~> 3, >= 3.248.0)
       aws-sigv4 (~> 1.5)
       aws-sigv4 (~> 1.5)
-    aws-sdk-s3 (1.211.0)
-      aws-sdk-core (~> 3, >= 3.241.3)
+    aws-sdk-s3 (1.224.0)
+      aws-sdk-core (~> 3, >= 3.248.0)
       aws-sdk-kms (~> 1)
       aws-sdk-kms (~> 1)
       aws-sigv4 (~> 1.5)
       aws-sigv4 (~> 1.5)
     aws-sigv4 (1.12.1)
     aws-sigv4 (1.12.1)
       aws-eventstream (~> 1, >= 1.0.2)
       aws-eventstream (~> 1, >= 1.0.2)
     babosa (1.0.4)
     babosa (1.0.4)
-    base64 (0.2.0)
+    base64 (0.3.0)
     benchmark (0.5.0)
     benchmark (0.5.0)
-    bigdecimal (4.0.1)
+    bigdecimal (4.1.2)
     claide (1.1.0)
     claide (1.1.0)
     colored (1.2)
     colored (1.2)
     colored2 (3.1.2)
     colored2 (3.1.2)
@@ -71,17 +71,17 @@ GEM
     faraday-retry (1.0.4)
     faraday-retry (1.0.4)
     faraday_middleware (1.2.1)
     faraday_middleware (1.2.1)
       faraday (~> 1.0)
       faraday (~> 1.0)
-    fastimage (2.4.0)
-    fastlane (2.233.1)
-      CFPropertyList (>= 2.3, < 4.0.0)
-      abbrev (~> 0.1.2)
+    fastimage (2.4.1)
+    fastlane (2.235.0)
+      CFPropertyList (>= 2.3, < 5.0.0)
+      abbrev (~> 0.1)
       addressable (>= 2.8, < 3.0.0)
       addressable (>= 2.8, < 3.0.0)
       artifactory (~> 3.0)
       artifactory (~> 3.0)
       aws-sdk-s3 (~> 1.197)
       aws-sdk-s3 (~> 1.197)
       babosa (>= 1.0.3, < 2.0.0)
       babosa (>= 1.0.3, < 2.0.0)
-      base64 (~> 0.2.0)
+      base64 (~> 0.2)
       benchmark (>= 0.1.0)
       benchmark (>= 0.1.0)
-      bundler (>= 1.17.3, < 5.0.0)
+      bundler (>= 2.4.0, < 5.0.0)
       colored (~> 1.2)
       colored (~> 1.2)
       commander (~> 4.6)
       commander (~> 4.6)
       csv (~> 3.3)
       csv (~> 3.3)
@@ -96,18 +96,18 @@ GEM
       gh_inspector (>= 1.1.2, < 2.0.0)
       gh_inspector (>= 1.1.2, < 2.0.0)
       google-apis-androidpublisher_v3 (~> 0.3)
       google-apis-androidpublisher_v3 (~> 0.3)
       google-apis-playcustomapp_v1 (~> 0.1)
       google-apis-playcustomapp_v1 (~> 0.1)
-      google-cloud-env (>= 1.6.0, <= 2.1.1)
+      google-cloud-env (>= 1.6.0, < 2.3.0)
       google-cloud-storage (~> 1.31)
       google-cloud-storage (~> 1.31)
       highline (~> 2.0)
       highline (~> 2.0)
       http-cookie (~> 1.0.5)
       http-cookie (~> 1.0.5)
       json (< 3.0.0)
       json (< 3.0.0)
-      jwt (>= 2.1.0, < 3)
+      jwt (>= 2.1.0, < 4)
       logger (>= 1.6, < 2.0)
       logger (>= 1.6, < 2.0)
       mini_magick (>= 4.9.4, < 5.0.0)
       mini_magick (>= 4.9.4, < 5.0.0)
       multipart-post (>= 2.0.0, < 3.0.0)
       multipart-post (>= 2.0.0, < 3.0.0)
-      mutex_m (~> 0.3.0)
+      mutex_m (~> 0.3)
       naturally (~> 2.2)
       naturally (~> 2.2)
-      nkf (~> 0.2.0)
+      nkf (~> 0.2)
       optparse (>= 0.1.1, < 1.0.0)
       optparse (>= 0.1.1, < 1.0.0)
       ostruct (>= 0.1.0)
       ostruct (>= 0.1.0)
       plist (>= 3.1.0, < 4.0.0)
       plist (>= 3.1.0, < 4.0.0)
@@ -124,39 +124,44 @@ GEM
       xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
       xcpretty-travis-formatter (>= 0.0.3, < 2.0.0)
     fastlane-sirp (1.1.0)
     fastlane-sirp (1.1.0)
     gh_inspector (1.1.3)
     gh_inspector (1.1.3)
-    google-apis-androidpublisher_v3 (0.54.0)
-      google-apis-core (>= 0.11.0, < 2.a)
-    google-apis-core (0.11.3)
+    google-apis-androidpublisher_v3 (0.101.0)
+      google-apis-core (>= 0.15.0, < 2.a)
+    google-apis-core (0.18.0)
       addressable (~> 2.5, >= 2.5.1)
       addressable (~> 2.5, >= 2.5.1)
-      googleauth (>= 0.16.2, < 2.a)
-      httpclient (>= 2.8.1, < 3.a)
+      googleauth (~> 1.9)
+      httpclient (>= 2.8.3, < 3.a)
       mini_mime (~> 1.0)
       mini_mime (~> 1.0)
+      mutex_m
       representable (~> 3.0)
       representable (~> 3.0)
       retriable (>= 2.0, < 4.a)
       retriable (>= 2.0, < 4.a)
-      rexml
-    google-apis-iamcredentials_v1 (0.17.0)
-      google-apis-core (>= 0.11.0, < 2.a)
-    google-apis-playcustomapp_v1 (0.13.0)
-      google-apis-core (>= 0.11.0, < 2.a)
-    google-apis-storage_v1 (0.31.0)
-      google-apis-core (>= 0.11.0, < 2.a)
+    google-apis-iamcredentials_v1 (0.27.0)
+      google-apis-core (>= 0.15.0, < 2.a)
+    google-apis-playcustomapp_v1 (0.17.0)
+      google-apis-core (>= 0.15.0, < 2.a)
+    google-apis-storage_v1 (0.62.0)
+      google-apis-core (>= 0.15.0, < 2.a)
     google-cloud-core (1.8.0)
     google-cloud-core (1.8.0)
       google-cloud-env (>= 1.0, < 3.a)
       google-cloud-env (>= 1.0, < 3.a)
       google-cloud-errors (~> 1.0)
       google-cloud-errors (~> 1.0)
-    google-cloud-env (1.6.0)
-      faraday (>= 0.17.3, < 3.0)
-    google-cloud-errors (1.5.0)
-    google-cloud-storage (1.47.0)
+    google-cloud-env (2.2.2)
+      base64 (~> 0.2)
+      faraday (>= 1.0, < 3.a)
+    google-cloud-errors (1.6.0)
+    google-cloud-storage (1.60.0)
       addressable (~> 2.8)
       addressable (~> 2.8)
       digest-crc (~> 0.4)
       digest-crc (~> 0.4)
-      google-apis-iamcredentials_v1 (~> 0.1)
-      google-apis-storage_v1 (~> 0.31.0)
+      google-apis-core (>= 0.18, < 2)
+      google-apis-iamcredentials_v1 (~> 0.18)
+      google-apis-storage_v1 (>= 0.42)
       google-cloud-core (~> 1.6)
       google-cloud-core (~> 1.6)
-      googleauth (>= 0.16.2, < 2.a)
+      googleauth (~> 1.9)
       mini_mime (~> 1.0)
       mini_mime (~> 1.0)
-    googleauth (1.8.1)
-      faraday (>= 0.17.3, < 3.a)
-      jwt (>= 1.4, < 3.0)
+    google-logging-utils (0.2.0)
+    googleauth (1.16.2)
+      faraday (>= 1.0, < 3.a)
+      google-cloud-env (~> 2.2)
+      google-logging-utils (~> 0.1)
+      jwt (>= 1.4, < 4.0)
       multi_json (~> 1.11)
       multi_json (~> 1.11)
       os (>= 0.9, < 2.0)
       os (>= 0.9, < 2.0)
       signet (>= 0.16, < 2.a)
       signet (>= 0.16, < 2.a)
@@ -166,13 +171,13 @@ GEM
     httpclient (2.9.0)
     httpclient (2.9.0)
       mutex_m
       mutex_m
     jmespath (1.6.2)
     jmespath (1.6.2)
-    json (2.19.4)
-    jwt (2.10.3)
+    json (2.19.7)
+    jwt (3.2.0)
       base64
       base64
     logger (1.7.0)
     logger (1.7.0)
     mini_magick (4.13.2)
     mini_magick (4.13.2)
     mini_mime (1.1.5)
     mini_mime (1.1.5)
-    multi_json (1.19.1)
+    multi_json (1.21.1)
     multipart-post (2.4.1)
     multipart-post (2.4.1)
     mutex_m (0.3.0)
     mutex_m (0.3.0)
     nanaimo (0.4.0)
     nanaimo (0.4.0)
@@ -183,12 +188,12 @@ GEM
     ostruct (0.6.3)
     ostruct (0.6.3)
     plist (3.7.2)
     plist (3.7.2)
     public_suffix (7.0.5)
     public_suffix (7.0.5)
-    rake (13.3.1)
+    rake (13.4.2)
     representable (3.2.0)
     representable (3.2.0)
       declarative (< 0.1.0)
       declarative (< 0.1.0)
       trailblazer-option (>= 0.1.1, < 0.2.0)
       trailblazer-option (>= 0.1.1, < 0.2.0)
       uber (< 0.2.0)
       uber (< 0.2.0)
-    retriable (3.1.2)
+    retriable (3.8.0)
     rexml (3.4.4)
     rexml (3.4.4)
     rouge (3.28.0)
     rouge (3.28.0)
     ruby2_keywords (0.0.5)
     ruby2_keywords (0.0.5)
@@ -231,7 +236,7 @@ PLATFORMS
 
 
 DEPENDENCIES
 DEPENDENCIES
   addressable (>= 2.9.0)
   addressable (>= 2.9.0)
-  fastlane (= 2.233.1)
+  fastlane (= 2.235.0)
   json (>= 2.19.2)
   json (>= 2.19.2)
 
 
 BUNDLED WITH
 BUNDLED WITH

+ 1 - 0
OmnipodKit

@@ -0,0 +1 @@
+Subproject commit adf210d20bcfc05f8119e8665d8f5904db828e03

+ 7 - 2
PRIVACY_POLICY.md

@@ -73,6 +73,11 @@ The following information is included in the telemetry payload:
   on/off, Live Activity enabled, calendar integration enabled
   on/off, Live Activity enabled, calendar integration enabled
 - A rolling 7-day count of how often the app was cold-launched
 - A rolling 7-day count of how often the app was cold-launched
 - The commit SHAs of pinned submodules (e.g. LoopKit, OmniBLE)
 - The commit SHAs of pinned submodules (e.g. LoopKit, OmniBLE)
+- The device's system locale (e.g. "en_US") — used to help Trio
+  developers understand which languages to prioritize for translation
+- The device's time zone identifier (e.g. "America/New_York") — used
+  to help Trio developers understand which regions of the world Trio
+  is being used in
 
 
 The payload sends once every 24 hours while the app is running, plus
 The payload sends once every 24 hours while the app is running, plus
 once after a new build is installed. Sending failures simply retry on
 once after a new build is installed. Sending failures simply retry on
@@ -85,7 +90,7 @@ the next launch or scheduler tick — there is no continued retry.
 - Your Nightscout URL or API token
 - Your Nightscout URL or API token
 - Your Tidepool email, password, or session token
 - Your Tidepool email, password, or session token
 - Remote-command secrets or APNS keys
 - Remote-command secrets or APNS keys
-- Time zone or location
+- GPS coordinates or any precise location data
 - App logs — log sharing remains a separate, user-initiated flow under Settings
 - App logs — log sharing remains a separate, user-initiated flow under Settings
 
 
 ### Debug Symbols (dSYMs)
 ### Debug Symbols (dSYMs)
@@ -177,4 +182,4 @@ trio.diy.diabetes@gmail.com.
 
 
 ## Last Updated
 ## Last Updated
 
 
-May 14, 2025
+May 28, 2026

+ 6 - 0
Trio.xcodeproj/project.pbxproj

@@ -352,6 +352,8 @@
 		41740E936552456AAC0EDAC3 /* SettingsSearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3919BBB515547118D684CA2 /* SettingsSearchTests.swift */; };
 		41740E936552456AAC0EDAC3 /* SettingsSearchTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B3919BBB515547118D684CA2 /* SettingsSearchTests.swift */; };
 		A33352ED40476125EBAC6EE0 /* CarbRatioEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E22146D3DF4853786C78132 /* CarbRatioEditorDataFlow.swift */; };
 		A33352ED40476125EBAC6EE0 /* CarbRatioEditorDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7E22146D3DF4853786C78132 /* CarbRatioEditorDataFlow.swift */; };
 		AD3D2CD42CD01B9EB8F26522 /* PumpConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF65DA88F972B56090AD6AC3 /* PumpConfigDataFlow.swift */; };
 		AD3D2CD42CD01B9EB8F26522 /* PumpConfigDataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF65DA88F972B56090AD6AC3 /* PumpConfigDataFlow.swift */; };
+		B6E925132EB3932A0076D719 /* OmnipodKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B6E925122EB3932A0076D719 /* OmnipodKit.framework */; };
+		B6E925142EB3932A0076D719 /* OmnipodKit.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = B6E925122EB3932A0076D719 /* OmnipodKit.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
 		B7C465E9472624D8A2BE2A6A /* (null) in Sources */ = {isa = PBXBuildFile; };
 		B7C465E9472624D8A2BE2A6A /* (null) in Sources */ = {isa = PBXBuildFile; };
 		B958F1B72BA0711600484851 /* MKRingProgressView in Frameworks */ = {isa = PBXBuildFile; productRef = B958F1B62BA0711600484851 /* MKRingProgressView */; };
 		B958F1B72BA0711600484851 /* MKRingProgressView in Frameworks */ = {isa = PBXBuildFile; productRef = B958F1B62BA0711600484851 /* MKRingProgressView */; };
 		BA00D96F7B2FF169A06FB530 /* CGMSettingsStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C018D1680307A31C9ED7120 /* CGMSettingsStateModel.swift */; };
 		BA00D96F7B2FF169A06FB530 /* CGMSettingsStateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C018D1680307A31C9ED7120 /* CGMSettingsStateModel.swift */; };
@@ -845,6 +847,7 @@
 				3B4BA78B2D8DC0EC0069D5B8 /* ShareClient.framework in Embed Frameworks */,
 				3B4BA78B2D8DC0EC0069D5B8 /* ShareClient.framework in Embed Frameworks */,
 				3B4BA7912D8DC0EC0069D5B8 /* TidepoolServiceKitUI.framework in Embed Frameworks */,
 				3B4BA7912D8DC0EC0069D5B8 /* TidepoolServiceKitUI.framework in Embed Frameworks */,
 				CE95BF602BA7715800DC3DE3 /* MockKit.framework in Embed Frameworks */,
 				CE95BF602BA7715800DC3DE3 /* MockKit.framework in Embed Frameworks */,
+				B6E925142EB3932A0076D719 /* OmnipodKit.framework in Embed Frameworks */,
 				CE95BF5E2BA770C300DC3DE3 /* LoopKitUI.framework in Embed Frameworks */,
 				CE95BF5E2BA770C300DC3DE3 /* LoopKitUI.framework in Embed Frameworks */,
 			);
 			);
 			name = "Embed Frameworks";
 			name = "Embed Frameworks";
@@ -1222,6 +1225,7 @@
 		AAFF91130F2FCCC7EBBA11AD /* BasalProfileEditorStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorStateModel.swift; sourceTree = "<group>"; };
 		AAFF91130F2FCCC7EBBA11AD /* BasalProfileEditorStateModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = BasalProfileEditorStateModel.swift; sourceTree = "<group>"; };
 		AF65DA88F972B56090AD6AC3 /* PumpConfigDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PumpConfigDataFlow.swift; sourceTree = "<group>"; };
 		AF65DA88F972B56090AD6AC3 /* PumpConfigDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PumpConfigDataFlow.swift; sourceTree = "<group>"; };
 		B5822B15939E719628E9FF7C /* SnoozeRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SnoozeRootView.swift; sourceTree = "<group>"; };
 		B5822B15939E719628E9FF7C /* SnoozeRootView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = SnoozeRootView.swift; sourceTree = "<group>"; };
+		B6E925122EB3932A0076D719 /* OmnipodKit.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = OmnipodKit.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		B9B5C0607505A38F256BF99A /* CGMSettingsDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CGMSettingsDataFlow.swift; sourceTree = "<group>"; };
 		B9B5C0607505A38F256BF99A /* CGMSettingsDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = CGMSettingsDataFlow.swift; sourceTree = "<group>"; };
 		BA49538D56989D8DA6FCF538 /* TargetsEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetsEditorDataFlow.swift; sourceTree = "<group>"; };
 		BA49538D56989D8DA6FCF538 /* TargetsEditorDataFlow.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TargetsEditorDataFlow.swift; sourceTree = "<group>"; };
 		BD04ECCD2D299522008C5FEB /* BolusProgressOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusProgressOverlay.swift; sourceTree = "<group>"; };
 		BD04ECCD2D299522008C5FEB /* BolusProgressOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BolusProgressOverlay.swift; sourceTree = "<group>"; };
@@ -1670,6 +1674,7 @@
 				38E87401274F77E400975559 /* CoreNFC.framework in Frameworks */,
 				38E87401274F77E400975559 /* CoreNFC.framework in Frameworks */,
 				3B4BA78A2D8DC0EC0069D5B8 /* ShareClient.framework in Frameworks */,
 				3B4BA78A2D8DC0EC0069D5B8 /* ShareClient.framework in Frameworks */,
 				3B4BA77E2D8DBD690069D5B8 /* OmniKit.framework in Frameworks */,
 				3B4BA77E2D8DBD690069D5B8 /* OmniKit.framework in Frameworks */,
+				B6E925132EB3932A0076D719 /* OmnipodKit.framework in Frameworks */,
 				3811DE1025C9D37700A708ED /* Swinject in Frameworks */,
 				3811DE1025C9D37700A708ED /* Swinject in Frameworks */,
 				3B4BA78E2D8DC0EC0069D5B8 /* TidepoolServiceKit.framework in Frameworks */,
 				3B4BA78E2D8DC0EC0069D5B8 /* TidepoolServiceKit.framework in Frameworks */,
 				B958F1B72BA0711600484851 /* MKRingProgressView in Frameworks */,
 				B958F1B72BA0711600484851 /* MKRingProgressView in Frameworks */,
@@ -2308,6 +2313,7 @@
 		3818AA48274C267000843DB3 /* Frameworks */ = {
 		3818AA48274C267000843DB3 /* Frameworks */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				B6E925122EB3932A0076D719 /* OmnipodKit.framework */,
 				3E54EF2B2E476DA40006F54D /* MedtrumKit.framework */,
 				3E54EF2B2E476DA40006F54D /* MedtrumKit.framework */,
 				3E84DA3F2F48D96000033608 /* EversenseKit.framework */,
 				3E84DA3F2F48D96000033608 /* EversenseKit.framework */,
 				3B4BA7882D8DC0EC0069D5B8 /* TidepoolServiceKit.framework */,
 				3B4BA7882D8DC0EC0069D5B8 /* TidepoolServiceKit.framework */,

+ 3 - 0
Trio.xcworkspace/contents.xcworkspacedata

@@ -8,6 +8,9 @@
       location = "group:MinimedKit/MinimedKit.xcodeproj">
       location = "group:MinimedKit/MinimedKit.xcodeproj">
    </FileRef>
    </FileRef>
    <FileRef
    <FileRef
+      location = "group:OmnipodKit/OmnipodKit.xcodeproj">
+   </FileRef>
+   <FileRef
       location = "group:LibreTransmitter/LibreTransmitter.xcodeproj">
       location = "group:LibreTransmitter/LibreTransmitter.xcodeproj">
    </FileRef>
    </FileRef>
    <FileRef
    <FileRef

+ 10 - 3
Trio/Sources/APS/APSManager.swift

@@ -583,11 +583,18 @@ final class BaseAPSManager: APSManager, Injectable {
         do {
         do {
             try await pump.enactBolus(units: roundedAmount, automatic: isSMB)
             try await pump.enactBolus(units: roundedAmount, automatic: isSMB)
             debug(.apsManager, "Bolus succeeded")
             debug(.apsManager, "Bolus succeeded")
-            if !isSMB {
-                try await determineBasalSync()
-            }
             bolusProgress.send(0)
             bolusProgress.send(0)
             callback?(true, String(localized: "Bolus enacted successfully.", comment: "Success message for enacting a bolus"))
             callback?(true, String(localized: "Bolus enacted successfully.", comment: "Success message for enacting a bolus"))
+            if !isSMB {
+                do {
+                    try await determineBasalSync()
+                } catch {
+                    warning(
+                        .apsManager,
+                        "determineBasalSync after manual bolus failed: \(error.localizedDescription)"
+                    )
+                }
+            }
         } catch {
         } catch {
             warning(.apsManager, "Bolus failed with error: \(error)")
             warning(.apsManager, "Bolus failed with error: \(error)")
             processError(APSError.pumpError(error))
             processError(APSError.pumpError(error))

+ 59 - 1
Trio/Sources/APS/DeviceDataManager.swift

@@ -10,6 +10,7 @@ import MinimedKit
 import MockKit
 import MockKit
 import OmniBLE
 import OmniBLE
 import OmniKit
 import OmniKit
+import OmnipodKit
 import ShareClient
 import ShareClient
 import SwiftDate
 import SwiftDate
 import Swinject
 import Swinject
@@ -39,6 +40,7 @@ private let staticPumpManagers: [PumpManagerUI.Type] = [
     MinimedPumpManager.self,
     MinimedPumpManager.self,
     OmnipodPumpManager.self,
     OmnipodPumpManager.self,
     OmniBLEPumpManager.self,
     OmniBLEPumpManager.self,
+    OmniPumpManager.self,
     DanaKitPumpManager.self,
     DanaKitPumpManager.self,
     MedtrumPumpManager.self,
     MedtrumPumpManager.self,
     MockPumpManager.self
     MockPumpManager.self
@@ -48,6 +50,7 @@ private let staticPumpManagersByIdentifier: [String: PumpManagerUI.Type] = [
     MinimedPumpManager.pluginIdentifier: MinimedPumpManager.self,
     MinimedPumpManager.pluginIdentifier: MinimedPumpManager.self,
     OmnipodPumpManager.pluginIdentifier: OmnipodPumpManager.self,
     OmnipodPumpManager.pluginIdentifier: OmnipodPumpManager.self,
     OmniBLEPumpManager.pluginIdentifier: OmniBLEPumpManager.self,
     OmniBLEPumpManager.pluginIdentifier: OmniBLEPumpManager.self,
+    OmniPumpManager.pluginIdentifier: OmniPumpManager.self,
     DanaKitPumpManager.pluginIdentifier: DanaKitPumpManager.self,
     DanaKitPumpManager.pluginIdentifier: DanaKitPumpManager.self,
     MedtrumPumpManager.pluginIdentifier: MedtrumPumpManager.self,
     MedtrumPumpManager.pluginIdentifier: MedtrumPumpManager.self,
     MockPumpManager.pluginIdentifier: MockPumpManager.self
     MockPumpManager.pluginIdentifier: MockPumpManager.self
@@ -142,6 +145,13 @@ final class BaseDeviceDataManager: DeviceDataManager, Injectable {
                         pumpActivatedAtDate.send(medtrumPump.state.patchActivatedAt)
                         pumpActivatedAtDate.send(medtrumPump.state.patchActivatedAt)
                     }
                     }
                 }
                 }
+                if let omni = pumpManager as? OmniPumpManager {
+                    guard let endTime = omni.state.podState?.expiresAt else {
+                        pumpExpiresAtDate.send(nil)
+                        return
+                    }
+                    pumpExpiresAtDate.send(endTime)
+                }
                 if let simulatorPump = pumpManager as? MockPumpManager {
                 if let simulatorPump = pumpManager as? MockPumpManager {
                     pumpDisplayState.value = PumpDisplayState(name: simulatorPump.localizedTitle, image: simulatorPump.smallImage)
                     pumpDisplayState.value = PumpDisplayState(name: simulatorPump.localizedTitle, image: simulatorPump.smallImage)
                     pumpName.send(simulatorPump.localizedTitle)
                     pumpName.send(simulatorPump.localizedTitle)
@@ -292,6 +302,10 @@ final class BaseDeviceDataManager: DeviceDataManager, Injectable {
         self.recommendsLoop.send()
         self.recommendsLoop.send()
     }
     }
 
 
+    public func pumpManagerTypeByIdentifier(_ identifier: String) -> PumpManagerUI.Type? {
+        staticPumpManagersByIdentifier[identifier]
+    }
+
     private func pumpManagerFromRawValue(_ rawValue: [String: Any]) -> PumpManagerUI? {
     private func pumpManagerFromRawValue(_ rawValue: [String: Any]) -> PumpManagerUI? {
         guard let rawState = rawValue["state"] as? PumpManager.RawStateValue,
         guard let rawState = rawValue["state"] as? PumpManager.RawStateValue,
               let Manager = pumpManagerTypeFromRawValue(rawValue)
               let Manager = pumpManagerTypeFromRawValue(rawValue)
@@ -307,7 +321,18 @@ final class BaseDeviceDataManager: DeviceDataManager, Injectable {
             return nil
             return nil
         }
         }
 
 
-        return staticPumpManagersByIdentifier[managerIdentifier]
+        if let pumpManager = pumpManagerTypeByIdentifier(managerIdentifier) {
+            return pumpManager
+        }
+
+        /// The pumpManager was not found for managerIdentifier. If this was for an "Omnipod" (OmniKit) or
+        /// "Omnipod-DASH" (OmniBLE), have the universal "Omni" pumpManager (OmnipodKit) handle instead.
+        let OmniStr = "Omni"
+        if managerIdentifier.hasPrefix(OmniStr) {
+            return pumpManagerTypeByIdentifier(OmniStr)
+        }
+
+        return nil
     }
     }
 
 
     // MARK: - GlucoseSource
     // MARK: - GlucoseSource
@@ -554,6 +579,39 @@ extension BaseDeviceDataManager: PumpManagerDelegate {
             }
             }
         }
         }
 
 
+        if let omni = pumpManager as? OmniPumpManager {
+            let reservoirVal = omni.state.podState?.lastInsulinMeasurements?.reservoirLevel ?? 0xDEAD_BEEF
+            // TODO: find the value Pod.maximumReservoirReading
+            let reservoir = Decimal(reservoirVal) > 50.0 ? 0xDEAD_BEEF : reservoirVal
+
+            storage.save(Decimal(reservoir), as: OpenAPS.Monitor.reservoir)
+            broadcaster.notify(PumpReservoirObserver.self, on: processQueue) {
+                $0.pumpReservoirDidChange(Decimal(reservoir))
+            }
+
+            // manual temp basal on
+            if let tempBasal = omni.state.podState?.unfinalizedTempBasal, !tempBasal.isFinished(),
+               !tempBasal.automatic
+            {
+                // the manual basal temp is launch - block every thing
+                debug(.deviceManager, "manual temp basal")
+                manualTempBasal.send(true)
+            } else {
+                // no more manual Temp Basal !
+                manualTempBasal.send(false)
+            }
+
+            guard let endTime = omni.state.podState?.expiresAt else {
+                pumpExpiresAtDate.send(nil)
+                return
+            }
+            pumpExpiresAtDate.send(endTime)
+
+            if let startTime = omni.state.podState?.activatedAt {
+                storage.save(startTime, as: OpenAPS.Monitor.podAge)
+            }
+        }
+
         if let simulatorPump = pumpManager as? MockPumpManager {
         if let simulatorPump = pumpManager as? MockPumpManager {
             broadcaster.notify(PumpReservoirObserver.self, on: processQueue) {
             broadcaster.notify(PumpReservoirObserver.self, on: processQueue) {
                 $0.pumpReservoirDidChange(Decimal(simulatorPump.state.reservoirUnitsRemaining))
                 $0.pumpReservoirDidChange(Decimal(simulatorPump.state.reservoirUnitsRemaining))

+ 22 - 4
Trio/Sources/Application/AppDelegate.swift

@@ -20,21 +20,39 @@ class AppDelegate: NSObject, UIApplicationDelegate, ObservableObject, UNUserNoti
         Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(crashReportingEnabled)
         Crashlytics.crashlytics().setCrashlyticsCollectionEnabled(crashReportingEnabled)
         Crashlytics.crashlytics().setCustomValue(Bundle.main.appDevVersion ?? "unknown", forKey: "app_dev_version")
         Crashlytics.crashlytics().setCustomValue(Bundle.main.appDevVersion ?? "unknown", forKey: "app_dev_version")
 
 
-        // Telemetry: record this cold launch into the sliding 7-day window. If
-        // consent is set and the build SHA changed since the last successful
-        // send, fire an immediate ping — the 24h scheduler can't notice a
-        // build update on its own. Then arm the recurring 24h timer.
+        // Telemetry: record this cold launch into the sliding 7-day window,
+        // then drive cadence via three layered triggers — listed below in
+        // priority of reliability:
+        //
+        //   1. SHA-change ping: build updated since last send. Awaited so
+        //      the lastSentAt stamp is fresh before the overdue check.
+        //   2. checkAndSendIfOverdue: covers the regular cold launch on the
+        //      same build when >24h has passed since the last successful
+        //      send. Together with the foreground-transition hook below
+        //      (`applicationWillEnterForeground`), this keeps daily pings
+        //      flowing on iOS.
+        //   3. scheduleRecurring: best-effort fallback for the rare case
+        //      where the app stays foregrounded for a full 24h.
         TelemetryClient.shared.recordColdLaunch()
         TelemetryClient.shared.recordColdLaunch()
         Task.detached {
         Task.detached {
             if TelemetryClient.shared.buildShaChangedSinceLastSend() {
             if TelemetryClient.shared.buildShaChangedSinceLastSend() {
                 await TelemetryClient.shared.maybeSend()
                 await TelemetryClient.shared.maybeSend()
             }
             }
             TelemetryClient.shared.scheduleRecurring()
             TelemetryClient.shared.scheduleRecurring()
+            TelemetryClient.shared.checkAndSendIfOverdue()
         }
         }
 
 
         return true
         return true
     }
     }
 
 
+    /// Foreground-transition entry point for telemetry cadence. Re-evaluates
+    /// the overdue window every time the user brings Trio to the foreground,
+    /// since `scheduleRecurring`'s GCD timer doesn't fire while suspended.
+    /// No-op if a send already landed within the last 24h.
+    func applicationWillEnterForeground(_: UIApplication) {
+        TelemetryClient.shared.checkAndSendIfOverdue()
+    }
+
     func application(
     func application(
         _: UIApplication,
         _: UIApplication,
         didReceiveRemoteNotification userInfo: [AnyHashable: Any],
         didReceiveRemoteNotification userInfo: [AnyHashable: Any],

Разница между файлами не показана из-за своего большого размера
+ 127 - 0
Trio/Sources/Localizations/Main/Localizable.xcstrings


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

@@ -994,6 +994,7 @@ extension Home {
             // PUMP RELATED
             // PUMP RELATED
             .confirmationDialog("Pump Model", isPresented: $showPumpSelection) {
             .confirmationDialog("Pump Model", isPresented: $showPumpSelection) {
                 Button("Medtronic") { state.addPump(.minimed) }
                 Button("Medtronic") { state.addPump(.minimed) }
+                Button("All Omnipod Types") { state.addPump(.omni) }
                 Button("Omnipod Eros") { state.addPump(.omnipod) }
                 Button("Omnipod Eros") { state.addPump(.omnipod) }
                 Button("Omnipod DASH") { state.addPump(.omnipodBLE) }
                 Button("Omnipod DASH") { state.addPump(.omnipodBLE) }
                 Button("Dana(RS/-i)") { state.addPump(.dana) }
                 Button("Dana(RS/-i)") { state.addPump(.dana) }

+ 1 - 0
Trio/Sources/Modules/PumpConfig/PumpConfigDataFlow.swift

@@ -9,6 +9,7 @@ enum PumpConfig {
         case minimed
         case minimed
         case omnipod
         case omnipod
         case omnipodBLE
         case omnipodBLE
+        case omni
         case dana
         case dana
         case medtrum
         case medtrum
         case simulator
         case simulator

+ 2 - 0
Trio/Sources/Modules/PumpConfig/View/PumpConfigRootView.swift

@@ -118,6 +118,7 @@ extension PumpConfig {
                                 )
                                 )
                                 VStack(alignment: .leading) {
                                 VStack(alignment: .leading) {
                                     Text("• Medtronic")
                                     Text("• Medtronic")
+                                    Text("• All Omnipod Types")
                                     Text("• Omnipod Eros")
                                     Text("• Omnipod Eros")
                                     Text("• Omnipod DASH")
                                     Text("• Omnipod DASH")
                                     Text("• Dana (RS/-i)")
                                     Text("• Dana (RS/-i)")
@@ -134,6 +135,7 @@ extension PumpConfig {
                 }
                 }
                 .confirmationDialog("Pump Model", isPresented: $showPumpSelection) {
                 .confirmationDialog("Pump Model", isPresented: $showPumpSelection) {
                     Button("Medtronic") { state.addPump(.minimed) }
                     Button("Medtronic") { state.addPump(.minimed) }
+                    Button("All Omnipod Types") { state.addPump(.omni) }
                     Button("Omnipod Eros") { state.addPump(.omnipod) }
                     Button("Omnipod Eros") { state.addPump(.omnipod) }
                     Button("Omnipod DASH") { state.addPump(.omnipodBLE) }
                     Button("Omnipod DASH") { state.addPump(.omnipodBLE) }
                     Button("Dana(RS/-i)") { state.addPump(.dana) }
                     Button("Dana(RS/-i)") { state.addPump(.dana) }

+ 10 - 0
Trio/Sources/Modules/PumpConfig/View/PumpSetupView.swift

@@ -9,6 +9,7 @@ import MockKitUI
 import OmniBLE
 import OmniBLE
 import OmniKit
 import OmniKit
 import OmniKitUI
 import OmniKitUI
+import OmnipodKit
 import SwiftUI
 import SwiftUI
 import UIKit
 import UIKit
 
 
@@ -60,6 +61,15 @@ extension PumpConfig {
                     allowDebugFeatures: true,
                     allowDebugFeatures: true,
                     allowedInsulinTypes: [.apidra, .humalog, .novolog, .fiasp, .lyumjev]
                     allowedInsulinTypes: [.apidra, .humalog, .novolog, .fiasp, .lyumjev]
                 )
                 )
+            case .omni:
+                setupViewController = OmniPumpManager.setupViewController(
+                    initialSettings: initialSettings,
+                    bluetoothProvider: bluetoothManager,
+                    colorPalette: .default,
+                    allowDebugFeatures: true,
+                    prefersToSkipUserInteraction: false,
+                    allowedInsulinTypes: [.apidra, .humalog, .novolog, .fiasp, .lyumjev]
+                )
             case .dana:
             case .dana:
                 setupViewController = DanaKitPumpManager.setupViewController(
                 setupViewController = DanaKitPumpManager.setupViewController(
                     initialSettings: initialSettings,
                     initialSettings: initialSettings,

+ 51 - 4
Trio/Sources/Services/Telemetry/TelemetryClient.swift

@@ -21,6 +21,11 @@ final class TelemetryClient: Injectable {
 
 
     private static let productionBaseURL: URL? = URL(string: "https://telemetry.triodocs.org")
     private static let productionBaseURL: URL? = URL(string: "https://telemetry.triodocs.org")
 
 
+    // MARK: if you fork Trio and keep telemetry enabled, please change the name here
+
+    // so that we can distinguish forks from mainline Trio builds in our telemetry.
+    private static let telemetryAppName: String = "Trio"
+
     /// Effective base URL: respects the debug override in
     /// Effective base URL: respects the debug override in
     /// `PropertyPersistentFlags.telemetryDebugServerURL`, then falls back to
     /// `PropertyPersistentFlags.telemetryDebugServerURL`, then falls back to
     /// `productionBaseURL`. Used by both the registration and `/checkin` paths.
     /// `productionBaseURL`. Used by both the registration and `/checkin` paths.
@@ -39,6 +44,14 @@ final class TelemetryClient: Injectable {
     private static let dailyInterval: TimeInterval = 24 * 60 * 60
     private static let dailyInterval: TimeInterval = 24 * 60 * 60
     private static let maxPayloadBytes = 4096
     private static let maxPayloadBytes = 4096
 
 
+    private static let buildDateFormatter: DateFormatter = {
+        let f = DateFormatter()
+        f.dateFormat = "yyyy-MM-dd"
+        f.locale = Locale(identifier: "en_US_POSIX")
+        f.timeZone = TimeZone(identifier: "UTC")
+        return f
+    }()
+
     // MARK: Injected services
     // MARK: Injected services
 
 
     @Injected() private var apsManager: APSManager!
     @Injected() private var apsManager: APSManager!
@@ -104,6 +117,12 @@ final class TelemetryClient: Injectable {
     /// Arms (or re-arms) the 24h send timer. Idempotent. Bails out without
     /// Arms (or re-arms) the 24h send timer. Idempotent. Bails out without
     /// scheduling if the user hasn't decided on consent yet or has opted out
     /// scheduling if the user hasn't decided on consent yet or has opted out
     /// — there's nothing for the timer to do.
     /// — there's nothing for the timer to do.
+    ///
+    /// Best-effort fallback only. GCD timers don't advance while the app is
+    /// suspended, so on iOS this effectively means "fires only if the app
+    /// stays foregrounded for 24h." The reliable cadence driver is
+    /// `checkAndSendIfOverdue()` called on every foreground transition and
+    /// cold launch.
     func scheduleRecurring() {
     func scheduleRecurring() {
         guard PropertyPersistentFlags.shared.telemetryConsentDecisionMade == true,
         guard PropertyPersistentFlags.shared.telemetryConsentDecisionMade == true,
               PropertyPersistentFlags.shared.telemetryEnabled == true
               PropertyPersistentFlags.shared.telemetryEnabled == true
@@ -124,6 +143,31 @@ final class TelemetryClient: Injectable {
         }
         }
     }
     }
 
 
+    /// If consent is set and we haven't successfully sent within the last 24h
+    /// (or have never sent), fire a send. Called on foreground transitions
+    /// and from the cold-launch path so daily cadence is kept.
+    ///
+    /// Mirrors the pattern used by LoopFollow's `TaskScheduler.checkTasksNow()`:
+    /// wall-clock comparison against `telemetryLastSentAt`, fire-and-forget
+    /// if overdue. Safe to call repeatedly — if a send already fired within
+    /// the window, this is a no-op.
+    func checkAndSendIfOverdue() {
+        guard PropertyPersistentFlags.shared.telemetryConsentDecisionMade == true,
+              PropertyPersistentFlags.shared.telemetryEnabled == true
+        else {
+            return
+        }
+
+        let lastSent = PropertyPersistentFlags.shared.telemetryLastSentAt
+        let overdue: Bool = {
+            guard let lastSent else { return true }
+            return Date().timeIntervalSince(lastSent) >= Self.dailyInterval
+        }()
+        guard overdue else { return }
+
+        Task.detached { await self.maybeSend() }
+    }
+
     /// Single entry point for all sends (scheduler tick, consent-yes, startup
     /// Single entry point for all sends (scheduler tick, consent-yes, startup
     /// SHA-change). Gated on consent + opt-in. *When* to send is the caller's
     /// SHA-change). Gated on consent + opt-in. *When* to send is the caller's
     /// decision — startup handles the SHA-change shortcut, the timer handles
     /// decision — startup handles the SHA-change shortcut, the timer handles
@@ -150,6 +194,7 @@ final class TelemetryClient: Injectable {
         var payload: [String: Any] = [:]
         var payload: [String: Any] = [:]
 
 
         if let v = info["CFBundleShortVersionString"] as? String { payload["appVersion"] = v }
         if let v = info["CFBundleShortVersionString"] as? String { payload["appVersion"] = v }
+        payload["appName"] = TelemetryClient.telemetryAppName
         // appDevVersion is Trio's 4-component dev counter (e.g. "0.7.0.14") —
         // appDevVersion is Trio's 4-component dev counter (e.g. "0.7.0.14") —
         // the most precise build identifier we have. Always emit, even when
         // the most precise build identifier we have. Always emit, even when
         // the Info.plist key is missing, so dashboards can rely on the field.
         // the Info.plist key is missing, so dashboards can rely on the field.
@@ -157,10 +202,10 @@ final class TelemetryClient: Injectable {
         payload["commitSha"] = bd.trioCommitSHA
         payload["commitSha"] = bd.trioCommitSHA
         payload["branch"] = bd.trioBranch
         payload["branch"] = bd.trioBranch
 
 
-        // Date-only prefix of the build-date string. Keeps the field a
-        // low-resolution build identifier, not a precise timestamp.
-        if let raw = bd.buildDateString, raw.count >= 10 {
-            payload["buildDate"] = String(raw.prefix(10))
+        // Date-only (yyyy-MM-dd, UTC) build identifier, parsed from the
+        // "Tue May 26 12:34:56 UTC 2025" form added in BuildDetails.plist.
+        if let date = bd.buildDate() {
+            payload["buildDate"] = Self.buildDateFormatter.string(from: date)
         }
         }
 
 
         payload["isTestFlight"] = bd.isTestFlightBuild()
         payload["isTestFlight"] = bd.isTestFlightBuild()
@@ -173,6 +218,8 @@ final class TelemetryClient: Injectable {
         payload["device"] = Self.hardwareIdentifier()
         payload["device"] = Self.hardwareIdentifier()
         payload["platform"] = Self.detectPlatform()
         payload["platform"] = Self.detectPlatform()
         payload["osVersion"] = UIDevice.current.systemVersion
         payload["osVersion"] = UIDevice.current.systemVersion
+        payload["locale"] = Locale.current.identifier
+        payload["timeZone"] = TimeZone.current.identifier
 
 
         // Pump model — omitted entirely when no pump is paired.
         // Pump model — omitted entirely when no pump is paired.
         if let pump = apsManager?.pumpManager {
         if let pump = apsManager?.pumpManager {

+ 1 - 1
scripts/capture-build-details.sh

@@ -16,7 +16,7 @@ fi
 echo "Gathering build details..."
 echo "Gathering build details..."
 
 
 # Capture the current date
 # Capture the current date
-plutil -replace com-trio-build-date -string "$(date -u '+%a %b %e %H:%M:%S UTC %Y')" "${info_plist_path}"
+plutil -replace com-trio-build-date -string "$(LC_ALL=C date -u '+%a %b %e %H:%M:%S UTC %Y')" "${info_plist_path}"
 
 
 # --- Root repo details ---
 # --- Root repo details ---
 # Retrieve current branch (or tag) and commit SHA.
 # Retrieve current branch (or tag) and commit SHA.

+ 2 - 1
scripts/swiftformat.sh

@@ -112,4 +112,5 @@ trailingClosures \
   MinimedKit, \
   MinimedKit, \
   TidepoolService, \
   TidepoolService, \
   DanaKit, \
   DanaKit, \
-  MedtrumKit
+  MedtrumKit, \
+  OmnipodKit