Sfoglia il codice sorgente

Release/0.1.8 (#17)

* Do not fetch if network is unreachable

* looping not depends on NS fetching for now

* fixed glucose text size

* Bump version
Ivan 5 anni fa
parent
commit
0d2a40e413

+ 35 - 6
FreeAPS.xcodeproj/project.pbxproj

@@ -92,6 +92,10 @@
 		3811DF0525CAA62600A708ED /* DependeciesContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3811DF0425CAA62600A708ED /* DependeciesContainer.swift */; };
 		3811DF0525CAA62600A708ED /* DependeciesContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3811DF0425CAA62600A708ED /* DependeciesContainer.swift */; };
 		3811DF0825CAAA4700A708ED /* ServiceContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3811DF0725CAAA4700A708ED /* ServiceContainer.swift */; };
 		3811DF0825CAAA4700A708ED /* ServiceContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3811DF0725CAAA4700A708ED /* ServiceContainer.swift */; };
 		3811DF1025CAAAE200A708ED /* APSManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3811DF0F25CAAAE200A708ED /* APSManager.swift */; };
 		3811DF1025CAAAE200A708ED /* APSManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3811DF0F25CAAAE200A708ED /* APSManager.swift */; };
+		38192E01261B826A0094D973 /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = 38192E00261B826A0094D973 /* Alamofire */; };
+		38192E04261B82FA0094D973 /* ReachabilityManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38192E03261B82FA0094D973 /* ReachabilityManager.swift */; };
+		38192E07261BA9960094D973 /* FetchTreatmentsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38192E06261BA9960094D973 /* FetchTreatmentsManager.swift */; };
+		38192E0D261BAF980094D973 /* ConvenienceExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38192E0C261BAF980094D973 /* ConvenienceExtensions.swift */; };
 		3821ED4C25DD18BA00BC42AD /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3821ED4B25DD18BA00BC42AD /* Constants.swift */; };
 		3821ED4C25DD18BA00BC42AD /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3821ED4B25DD18BA00BC42AD /* Constants.swift */; };
 		382C133725F13A1E00715CE1 /* InsulinSensitivities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382C133625F13A1E00715CE1 /* InsulinSensitivities.swift */; };
 		382C133725F13A1E00715CE1 /* InsulinSensitivities.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382C133625F13A1E00715CE1 /* InsulinSensitivities.swift */; };
 		382C134B25F14E3700715CE1 /* BGTargets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382C134A25F14E3700715CE1 /* BGTargets.swift */; };
 		382C134B25F14E3700715CE1 /* BGTargets.swift in Sources */ = {isa = PBXBuildFile; fileRef = 382C134A25F14E3700715CE1 /* BGTargets.swift */; };
@@ -184,7 +188,7 @@
 		38D0B3B625EBE24900CB6E88 /* Battery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38D0B3B525EBE24900CB6E88 /* Battery.swift */; };
 		38D0B3B625EBE24900CB6E88 /* Battery.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38D0B3B525EBE24900CB6E88 /* Battery.swift */; };
 		38D0B3D925EC07C400CB6E88 /* CarbsEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38D0B3D825EC07C400CB6E88 /* CarbsEntry.swift */; };
 		38D0B3D925EC07C400CB6E88 /* CarbsEntry.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38D0B3D825EC07C400CB6E88 /* CarbsEntry.swift */; };
 		38DAB280260CBB7F00F74C1A /* PumpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38DAB27F260CBB7F00F74C1A /* PumpView.swift */; };
 		38DAB280260CBB7F00F74C1A /* PumpView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38DAB27F260CBB7F00F74C1A /* PumpView.swift */; };
-		38DAB28A260D349500F74C1A /* GlucoseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38DAB289260D349500F74C1A /* GlucoseManager.swift */; };
+		38DAB28A260D349500F74C1A /* FetchGlucoseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38DAB289260D349500F74C1A /* FetchGlucoseManager.swift */; };
 		38E989DD25F5021400C0CED0 /* PumpStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E989DC25F5021400C0CED0 /* PumpStatus.swift */; };
 		38E989DD25F5021400C0CED0 /* PumpStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E989DC25F5021400C0CED0 /* PumpStatus.swift */; };
 		38E98A2325F52C9300C0CED0 /* Signpost.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E98A1B25F52C9300C0CED0 /* Signpost.swift */; };
 		38E98A2325F52C9300C0CED0 /* Signpost.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E98A1B25F52C9300C0CED0 /* Signpost.swift */; };
 		38E98A2425F52C9300C0CED0 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E98A1C25F52C9300C0CED0 /* Logger.swift */; };
 		38E98A2425F52C9300C0CED0 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E98A1C25F52C9300C0CED0 /* Logger.swift */; };
@@ -382,6 +386,9 @@
 		3811DF0425CAA62600A708ED /* DependeciesContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DependeciesContainer.swift; sourceTree = "<group>"; };
 		3811DF0425CAA62600A708ED /* DependeciesContainer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DependeciesContainer.swift; sourceTree = "<group>"; };
 		3811DF0725CAAA4700A708ED /* ServiceContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceContainer.swift; sourceTree = "<group>"; };
 		3811DF0725CAAA4700A708ED /* ServiceContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServiceContainer.swift; sourceTree = "<group>"; };
 		3811DF0F25CAAAE200A708ED /* APSManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APSManager.swift; sourceTree = "<group>"; };
 		3811DF0F25CAAAE200A708ED /* APSManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APSManager.swift; sourceTree = "<group>"; };
+		38192E03261B82FA0094D973 /* ReachabilityManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReachabilityManager.swift; sourceTree = "<group>"; };
+		38192E06261BA9960094D973 /* FetchTreatmentsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchTreatmentsManager.swift; sourceTree = "<group>"; };
+		38192E0C261BAF980094D973 /* ConvenienceExtensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ConvenienceExtensions.swift; sourceTree = "<group>"; };
 		3821ED4B25DD18BA00BC42AD /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
 		3821ED4B25DD18BA00BC42AD /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
 		382C133625F13A1E00715CE1 /* InsulinSensitivities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinSensitivities.swift; sourceTree = "<group>"; };
 		382C133625F13A1E00715CE1 /* InsulinSensitivities.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsulinSensitivities.swift; sourceTree = "<group>"; };
 		382C134A25F14E3700715CE1 /* BGTargets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGTargets.swift; sourceTree = "<group>"; };
 		382C134A25F14E3700715CE1 /* BGTargets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGTargets.swift; sourceTree = "<group>"; };
@@ -462,7 +469,7 @@
 		38D0B3B525EBE24900CB6E88 /* Battery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Battery.swift; sourceTree = "<group>"; };
 		38D0B3B525EBE24900CB6E88 /* Battery.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Battery.swift; sourceTree = "<group>"; };
 		38D0B3D825EC07C400CB6E88 /* CarbsEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbsEntry.swift; sourceTree = "<group>"; };
 		38D0B3D825EC07C400CB6E88 /* CarbsEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbsEntry.swift; sourceTree = "<group>"; };
 		38DAB27F260CBB7F00F74C1A /* PumpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PumpView.swift; sourceTree = "<group>"; };
 		38DAB27F260CBB7F00F74C1A /* PumpView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PumpView.swift; sourceTree = "<group>"; };
-		38DAB289260D349500F74C1A /* GlucoseManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GlucoseManager.swift; sourceTree = "<group>"; };
+		38DAB289260D349500F74C1A /* FetchGlucoseManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FetchGlucoseManager.swift; sourceTree = "<group>"; };
 		38E989DC25F5021400C0CED0 /* PumpStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PumpStatus.swift; sourceTree = "<group>"; };
 		38E989DC25F5021400C0CED0 /* PumpStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PumpStatus.swift; sourceTree = "<group>"; };
 		38E98A1B25F52C9300C0CED0 /* Signpost.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signpost.swift; sourceTree = "<group>"; };
 		38E98A1B25F52C9300C0CED0 /* Signpost.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Signpost.swift; sourceTree = "<group>"; };
 		38E98A1C25F52C9300C0CED0 /* Logger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
 		38E98A1C25F52C9300C0CED0 /* Logger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
@@ -554,6 +561,7 @@
 				38887DF225F61F7500944304 /* NightscoutUploadKit.framework in Frameworks */,
 				38887DF225F61F7500944304 /* NightscoutUploadKit.framework in Frameworks */,
 				38887DE825F61F7500944304 /* MockKitUI.framework in Frameworks */,
 				38887DE825F61F7500944304 /* MockKitUI.framework in Frameworks */,
 				3811DE1025C9D37700A708ED /* Swinject in Frameworks */,
 				3811DE1025C9D37700A708ED /* Swinject in Frameworks */,
+				38192E01261B826A0094D973 /* Alamofire in Frameworks */,
 				383948D325CD4D6D00E91849 /* Disk in Frameworks */,
 				383948D325CD4D6D00E91849 /* Disk in Frameworks */,
 				38887DF825F61F7600944304 /* RileyLinkBLEKit.framework in Frameworks */,
 				38887DF825F61F7600944304 /* RileyLinkBLEKit.framework in Frameworks */,
 				38887DEC25F61F7500944304 /* Crypto.framework in Frameworks */,
 				38887DEC25F61F7500944304 /* Crypto.framework in Frameworks */,
@@ -853,6 +861,7 @@
 		3811DE9425C9D88200A708ED /* Network */ = {
 		3811DE9425C9D88200A708ED /* Network */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
+				38192E03261B82FA0094D973 /* ReachabilityManager.swift */,
 				3811DE9625C9D88300A708ED /* HTTPResponseStatus.swift */,
 				3811DE9625C9D88300A708ED /* HTTPResponseStatus.swift */,
 				3811DE9725C9D88300A708ED /* NightscoutManager.swift */,
 				3811DE9725C9D88300A708ED /* NightscoutManager.swift */,
 				38FE826925CC82DB001FF17A /* NetworkService.swift */,
 				38FE826925CC82DB001FF17A /* NetworkService.swift */,
@@ -957,7 +966,8 @@
 			children = (
 			children = (
 				3811DF0F25CAAAE200A708ED /* APSManager.swift */,
 				3811DF0F25CAAAE200A708ED /* APSManager.swift */,
 				38BF021E25E7F0DE00579895 /* DeviceDataManager.swift */,
 				38BF021E25E7F0DE00579895 /* DeviceDataManager.swift */,
-				38DAB289260D349500F74C1A /* GlucoseManager.swift */,
+				38DAB289260D349500F74C1A /* FetchGlucoseManager.swift */,
+				38192E06261BA9960094D973 /* FetchTreatmentsManager.swift */,
 				38A504F625DDA0E200C5B9E8 /* Extensions */,
 				38A504F625DDA0E200C5B9E8 /* Extensions */,
 				388E5A5825B6F0070019842D /* OpenAPS */,
 				388E5A5825B6F0070019842D /* OpenAPS */,
 				38A0362725ECF05300FCBB52 /* Storage */,
 				38A0362725ECF05300FCBB52 /* Storage */,
@@ -1068,11 +1078,12 @@
 		388E5A5A25B6F05F0019842D /* Helpers */ = {
 		388E5A5A25B6F05F0019842D /* Helpers */ = {
 			isa = PBXGroup;
 			isa = PBXGroup;
 			children = (
 			children = (
-				389487392614928B004DF424 /* DispatchTimer.swift */,
 				38F37827261260DC009DB701 /* Color+Extensions.swift */,
 				38F37827261260DC009DB701 /* Color+Extensions.swift */,
 				389ECE042601144100D86C4F /* ConcurrentMap.swift */,
 				389ECE042601144100D86C4F /* ConcurrentMap.swift */,
+				38192E0C261BAF980094D973 /* ConvenienceExtensions.swift */,
 				3871F39E25ED895A0013ECB5 /* Decimal+Extensions.swift */,
 				3871F39E25ED895A0013ECB5 /* Decimal+Extensions.swift */,
 				38C4D33625E9A1A200D30B77 /* DispatchQueue+Extensions.swift */,
 				38C4D33625E9A1A200D30B77 /* DispatchQueue+Extensions.swift */,
+				389487392614928B004DF424 /* DispatchTimer.swift */,
 				3811DE5425C9D4D500A708ED /* Formatters.swift */,
 				3811DE5425C9D4D500A708ED /* Formatters.swift */,
 				38B4F3AE25E2979F00E76A18 /* IndexedCollection.swift */,
 				38B4F3AE25E2979F00E76A18 /* IndexedCollection.swift */,
 				389A571F26079BAA00BC102F /* Interpolation.swift */,
 				389A571F26079BAA00BC102F /* Interpolation.swift */,
@@ -1082,9 +1093,9 @@
 				38E98A2C25F52DC400C0CED0 /* NSLocking+Extensions.swift */,
 				38E98A2C25F52DC400C0CED0 /* NSLocking+Extensions.swift */,
 				38C4D33925E9A1ED00D30B77 /* NSObject+AssociatedValues.swift */,
 				38C4D33925E9A1ED00D30B77 /* NSObject+AssociatedValues.swift */,
 				3811DE5725C9D4D500A708ED /* ProgressBar.swift */,
 				3811DE5725C9D4D500A708ED /* ProgressBar.swift */,
+				3811DEE325CA063400A708ED /* PropertyWrappers */,
 				3811DE5525C9D4D500A708ED /* Publisher.swift */,
 				3811DE5525C9D4D500A708ED /* Publisher.swift */,
 				38E98A3625F5509500C0CED0 /* String+Extensions.swift */,
 				38E98A3625F5509500C0CED0 /* String+Extensions.swift */,
-				3811DEE325CA063400A708ED /* PropertyWrappers */,
 			);
 			);
 			path = Helpers;
 			path = Helpers;
 			sourceTree = "<group>";
 			sourceTree = "<group>";
@@ -1487,6 +1498,7 @@
 				383948D225CD4D6D00E91849 /* Disk */,
 				383948D225CD4D6D00E91849 /* Disk */,
 				38B17B6525DD90E0005CAE3D /* SwiftDate */,
 				38B17B6525DD90E0005CAE3D /* SwiftDate */,
 				3833B46C26012030003021B3 /* Algorithms */,
 				3833B46C26012030003021B3 /* Algorithms */,
+				38192E00261B826A0094D973 /* Alamofire */,
 			);
 			);
 			productName = FreeAPS;
 			productName = FreeAPS;
 			productReference = 388E595825AD948C0019842D /* FreeAPS.app */;
 			productReference = 388E595825AD948C0019842D /* FreeAPS.app */;
@@ -1542,6 +1554,7 @@
 				383948D125CD4D6D00E91849 /* XCRemoteSwiftPackageReference "Disk" */,
 				383948D125CD4D6D00E91849 /* XCRemoteSwiftPackageReference "Disk" */,
 				38B17B6425DD90E0005CAE3D /* XCRemoteSwiftPackageReference "SwiftDate" */,
 				38B17B6425DD90E0005CAE3D /* XCRemoteSwiftPackageReference "SwiftDate" */,
 				3833B46B26012030003021B3 /* XCRemoteSwiftPackageReference "swift-algorithms" */,
 				3833B46B26012030003021B3 /* XCRemoteSwiftPackageReference "swift-algorithms" */,
+				38192DFF261B826A0094D973 /* XCRemoteSwiftPackageReference "Alamofire" */,
 			);
 			);
 			productRefGroup = 388E595925AD948C0019842D /* Products */;
 			productRefGroup = 388E595925AD948C0019842D /* Products */;
 			projectDirPath = "";
 			projectDirPath = "";
@@ -1645,6 +1658,7 @@
 				3811DE7B25C9D6D300A708ED /* LoginProvider.swift in Sources */,
 				3811DE7B25C9D6D300A708ED /* LoginProvider.swift in Sources */,
 				383948D625CD4D8900E91849 /* FileStorage.swift in Sources */,
 				383948D625CD4D8900E91849 /* FileStorage.swift in Sources */,
 				3811DE4125C9D4A100A708ED /* SettingsRootView.swift in Sources */,
 				3811DE4125C9D4A100A708ED /* SettingsRootView.swift in Sources */,
+				38192E04261B82FA0094D973 /* ReachabilityManager.swift in Sources */,
 				388E595C25AD948C0019842D /* FreeAPSApp.swift in Sources */,
 				388E595C25AD948C0019842D /* FreeAPSApp.swift in Sources */,
 				3811DE8925C9D6DD00A708ED /* RequestPermissionsProvider.swift in Sources */,
 				3811DE8925C9D6DD00A708ED /* RequestPermissionsProvider.swift in Sources */,
 				3811DE4225C9D4A100A708ED /* SettingsDataFlow.swift in Sources */,
 				3811DE4225C9D4A100A708ED /* SettingsDataFlow.swift in Sources */,
@@ -1710,7 +1724,7 @@
 				38FE826A25CC82DB001FF17A /* NetworkService.swift in Sources */,
 				38FE826A25CC82DB001FF17A /* NetworkService.swift in Sources */,
 				3883581C25EE79BB00E024B2 /* DecimalTextField.swift in Sources */,
 				3883581C25EE79BB00E024B2 /* DecimalTextField.swift in Sources */,
 				3811DE6C25C9D62600A708ED /* OnboardingDataFlow.swift in Sources */,
 				3811DE6C25C9D62600A708ED /* OnboardingDataFlow.swift in Sources */,
-				38DAB28A260D349500F74C1A /* GlucoseManager.swift in Sources */,
+				38DAB28A260D349500F74C1A /* FetchGlucoseManager.swift in Sources */,
 				3811DE2425C9D48300A708ED /* MainViewModel.swift in Sources */,
 				3811DE2425C9D48300A708ED /* MainViewModel.swift in Sources */,
 				38F37828261260DC009DB701 /* Color+Extensions.swift in Sources */,
 				38F37828261260DC009DB701 /* Color+Extensions.swift in Sources */,
 				3811DE3F25C9D4A100A708ED /* SettingsViewModel.swift in Sources */,
 				3811DE3F25C9D4A100A708ED /* SettingsViewModel.swift in Sources */,
@@ -1761,9 +1775,11 @@
 				38E98A2425F52C9300C0CED0 /* Logger.swift in Sources */,
 				38E98A2425F52C9300C0CED0 /* Logger.swift in Sources */,
 				CA370FC152BC98B3D1832968 /* BasalProfileEditorRootView.swift in Sources */,
 				CA370FC152BC98B3D1832968 /* BasalProfileEditorRootView.swift in Sources */,
 				F215CAB49BA4B5A01C3BC6B6 /* ISFEditorBuilder.swift in Sources */,
 				F215CAB49BA4B5A01C3BC6B6 /* ISFEditorBuilder.swift in Sources */,
+				38192E07261BA9960094D973 /* FetchTreatmentsManager.swift in Sources */,
 				6632A0DC746872439A858B44 /* ISFEditorDataFlow.swift in Sources */,
 				6632A0DC746872439A858B44 /* ISFEditorDataFlow.swift in Sources */,
 				DBA5254DBB2586C98F61220C /* ISFEditorProvider.swift in Sources */,
 				DBA5254DBB2586C98F61220C /* ISFEditorProvider.swift in Sources */,
 				1BBB001DAD60F3B8CEA4B1C7 /* ISFEditorViewModel.swift in Sources */,
 				1BBB001DAD60F3B8CEA4B1C7 /* ISFEditorViewModel.swift in Sources */,
+				38192E0D261BAF980094D973 /* ConvenienceExtensions.swift in Sources */,
 				88AB39B23C9552BD6E0C9461 /* ISFEditorRootView.swift in Sources */,
 				88AB39B23C9552BD6E0C9461 /* ISFEditorRootView.swift in Sources */,
 				3BD663A04B4CA5278B0260B4 /* CREditorBuilder.swift in Sources */,
 				3BD663A04B4CA5278B0260B4 /* CREditorBuilder.swift in Sources */,
 				A33352ED40476125EBAC6EE0 /* CREditorDataFlow.swift in Sources */,
 				A33352ED40476125EBAC6EE0 /* CREditorDataFlow.swift in Sources */,
@@ -2093,6 +2109,14 @@
 				minimumVersion = 2.7.1;
 				minimumVersion = 2.7.1;
 			};
 			};
 		};
 		};
+		38192DFF261B826A0094D973 /* XCRemoteSwiftPackageReference "Alamofire" */ = {
+			isa = XCRemoteSwiftPackageReference;
+			repositoryURL = "https://github.com/Alamofire/Alamofire";
+			requirement = {
+				kind = upToNextMajorVersion;
+				minimumVersion = 5.4.2;
+			};
+		};
 		3833B46B26012030003021B3 /* XCRemoteSwiftPackageReference "swift-algorithms" */ = {
 		3833B46B26012030003021B3 /* XCRemoteSwiftPackageReference "swift-algorithms" */ = {
 			isa = XCRemoteSwiftPackageReference;
 			isa = XCRemoteSwiftPackageReference;
 			repositoryURL = "https://github.com/apple/swift-algorithms";
 			repositoryURL = "https://github.com/apple/swift-algorithms";
@@ -2125,6 +2149,11 @@
 			package = 3811DE0E25C9D37700A708ED /* XCRemoteSwiftPackageReference "Swinject" */;
 			package = 3811DE0E25C9D37700A708ED /* XCRemoteSwiftPackageReference "Swinject" */;
 			productName = Swinject;
 			productName = Swinject;
 		};
 		};
+		38192E00261B826A0094D973 /* Alamofire */ = {
+			isa = XCSwiftPackageProductDependency;
+			package = 38192DFF261B826A0094D973 /* XCRemoteSwiftPackageReference "Alamofire" */;
+			productName = Alamofire;
+		};
 		3833B46C26012030003021B3 /* Algorithms */ = {
 		3833B46C26012030003021B3 /* Algorithms */ = {
 			isa = XCSwiftPackageProductDependency;
 			isa = XCSwiftPackageProductDependency;
 			package = 3833B46B26012030003021B3 /* XCRemoteSwiftPackageReference "swift-algorithms" */;
 			package = 3833B46B26012030003021B3 /* XCRemoteSwiftPackageReference "swift-algorithms" */;

+ 9 - 0
FreeAPS.xcworkspace/xcshareddata/swiftpm/Package.resolved

@@ -2,6 +2,15 @@
   "object": {
   "object": {
     "pins": [
     "pins": [
       {
       {
+        "package": "Alamofire",
+        "repositoryURL": "https://github.com/Alamofire/Alamofire",
+        "state": {
+          "branch": null,
+          "revision": "4d19ad82f80cc71ff829b941ded114c56f4f604c",
+          "version": "5.4.2"
+        }
+      },
+      {
         "package": "Disk",
         "package": "Disk",
         "repositoryURL": "https://github.com/saoudrizwan/Disk",
         "repositoryURL": "https://github.com/saoudrizwan/Disk",
         "state": {
         "state": {

+ 1 - 1
FreeAPS/Resources/Config.xcconfig

@@ -1 +1 @@
-BUILD_VERSION = 0.1.7
+BUILD_VERSION = 0.1.8

+ 13 - 17
FreeAPS/Sources/APS/APSManager.swift

@@ -105,26 +105,22 @@ final class BaseAPSManager: APSManager, Injectable {
     private func loop() {
     private func loop() {
         debug(.apsManager, "Starting loop")
         debug(.apsManager, "Starting loop")
         isLooping.send(true)
         isLooping.send(true)
-        Publishers.CombineLatest(
-            nightscout.fetchCarbs(),
-            nightscout.fetchTempTargets()
-        )
-        .flatMap { _ in self.determineBasal() }
-        .sink { _ in } receiveValue: { [weak self] ok in
-            guard let self = self else { return }
-
-            if ok {
-                self.nightscout.uploadStatus()
-                if self.settings.closedLoop {
-                    self.enactSuggested()
+        determineBasal()
+            .sink { _ in } receiveValue: { [weak self] ok in
+                guard let self = self else { return }
+
+                if ok {
+                    self.nightscout.uploadStatus()
+                    if self.settings.closedLoop {
+                        self.enactSuggested()
+                    } else {
+                        self.isLooping.send(false)
+                        self.lastLoopDate.send(Date())
+                    }
                 } else {
                 } else {
                     self.isLooping.send(false)
                     self.isLooping.send(false)
-                    self.lastLoopDate.send(Date())
                 }
                 }
-            } else {
-                self.isLooping.send(false)
-            }
-        }.store(in: &lifetime)
+            }.store(in: &lifetime)
     }
     }
 
 
     private func verifyStatus() -> Bool {
     private func verifyStatus() -> Bool {

+ 5 - 5
FreeAPS/Sources/APS/GlucoseManager.swift

@@ -3,9 +3,9 @@ import Foundation
 import SwiftDate
 import SwiftDate
 import Swinject
 import Swinject
 
 
-protocol GlucoseManager {}
+protocol FetchGlucoseManager {}
 
 
-final class BaseGlucoseManager: GlucoseManager, Injectable {
+final class BaseFetchGlucoseManager: FetchGlucoseManager, Injectable {
     private let processQueue = DispatchQueue(label: "BaseGlucoseManager.processQueue")
     private let processQueue = DispatchQueue(label: "BaseGlucoseManager.processQueue")
     @Injected() var glucoseStorage: GlucoseStorage!
     @Injected() var glucoseStorage: GlucoseStorage!
     @Injected() var nightscoutManager: NightscoutManager!
     @Injected() var nightscoutManager: NightscoutManager!
@@ -23,14 +23,14 @@ final class BaseGlucoseManager: GlucoseManager, Injectable {
         timer.publisher
         timer.publisher
             .receive(on: processQueue)
             .receive(on: processQueue)
             .flatMap { date -> AnyPublisher<(Date, Date, [BloodGlucose]), Never> in
             .flatMap { date -> AnyPublisher<(Date, Date, [BloodGlucose]), Never> in
-                debug(.nightscout, "Glucose manager heartbeat")
+                debug(.nightscout, "FetchGlucoseManager heartbeat")
                 debug(.nightscout, "Start fetching glucose")
                 debug(.nightscout, "Start fetching glucose")
                 return Publishers.CombineLatest3(
                 return Publishers.CombineLatest3(
                     Just(date),
                     Just(date),
                     Just(self.glucoseStorage.syncDate()),
                     Just(self.glucoseStorage.syncDate()),
                     Publishers.CombineLatest(
                     Publishers.CombineLatest(
                         self.nightscoutManager.fetchGlucose(),
                         self.nightscoutManager.fetchGlucose(),
-                        self.fetchGlucoseFromSgaredGroup()
+                        self.fetchGlucoseFromSharedGroup()
                     )
                     )
                     .map { [$0, $1].flatMap { $0 } }
                     .map { [$0, $1].flatMap { $0 } }
                     .eraseToAnyPublisher()
                     .eraseToAnyPublisher()
@@ -51,7 +51,7 @@ final class BaseGlucoseManager: GlucoseManager, Injectable {
         timer.resume()
         timer.resume()
     }
     }
 
 
-    private func fetchGlucoseFromSgaredGroup() -> AnyPublisher<[BloodGlucose], Never> {
+    private func fetchGlucoseFromSharedGroup() -> AnyPublisher<[BloodGlucose], Never> {
         guard let suiteName = Bundle.main.appGroupSuiteName,
         guard let suiteName = Bundle.main.appGroupSuiteName,
               let sharedDefaults = UserDefaults(suiteName: suiteName)
               let sharedDefaults = UserDefaults(suiteName: suiteName)
         else {
         else {

+ 40 - 0
FreeAPS/Sources/APS/FetchTreatmentsManager.swift

@@ -0,0 +1,40 @@
+import Combine
+import Foundation
+import SwiftDate
+import Swinject
+
+protocol FetchTreatmentsManager {}
+
+final class BaseFetchTreatmentsManager: FetchTreatmentsManager, Injectable {
+    private let processQueue = DispatchQueue(label: "BaseFetchTreatmentsManager.processQueue")
+    @Injected() var nightscoutManager: NightscoutManager!
+    @Injected() var tempTargetsStorage: TempTargetsStorage!
+    @Injected() var carbsStorage: CarbsStorage!
+
+    private var lifetime = Set<AnyCancellable>()
+    private let timer = DispatchTimer(timeInterval: 1.minutes.timeInterval)
+
+    init(resolver: Resolver) {
+        injectServices(resolver)
+        subscribe()
+    }
+
+    private func subscribe() {
+        timer.publisher
+            .receive(on: processQueue)
+            .flatMap { _ -> AnyPublisher<([CarbsEntry], [TempTarget]), Never> in
+                debug(.nightscout, "FetchTreatmentsManager heartbeat")
+                debug(.nightscout, "Start fetching carbs and temptargets")
+                return Publishers.CombineLatest(
+                    self.nightscoutManager.fetchCarbs(),
+                    self.nightscoutManager.fetchTempTargets()
+                ).eraseToAnyPublisher()
+            }
+            .sink { carbs, targets in
+                self.carbsStorage.storeCarbs(carbs)
+                self.tempTargetsStorage.storeTempTargets(targets)
+            }
+            .store(in: &lifetime)
+        timer.resume()
+    }
+}

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

@@ -29,7 +29,8 @@ private extension Swinject.Resolver {
         resolver.resolve(AppearanceManager.self)!.setupGlobalAppearance()
         resolver.resolve(AppearanceManager.self)!.setupGlobalAppearance()
         _ = resolver.resolve(DeviceDataManager.self)!
         _ = resolver.resolve(DeviceDataManager.self)!
         _ = resolver.resolve(APSManager.self)!
         _ = resolver.resolve(APSManager.self)!
-        _ = resolver.resolve(GlucoseManager.self)!
+        _ = resolver.resolve(FetchGlucoseManager.self)!
+        _ = resolver.resolve(FetchTreatmentsManager.self)!
     }
     }
 
 
     var body: some Scene {
     var body: some Scene {

+ 2 - 1
FreeAPS/Sources/Containers/APSContainer.swift

@@ -7,6 +7,7 @@ enum APSContainer: DependeciesContainer {
     static func register(container: Container) {
     static func register(container: Container) {
         container.register(DeviceDataManager.self) { _ in BaseDeviceDataManager(resolver: resolver) }
         container.register(DeviceDataManager.self) { _ in BaseDeviceDataManager(resolver: resolver) }
         container.register(APSManager.self) { _ in BaseAPSManager(resolver: resolver) }
         container.register(APSManager.self) { _ in BaseAPSManager(resolver: resolver) }
-        container.register(GlucoseManager.self) { _ in BaseGlucoseManager(resolver: resolver) }
+        container.register(FetchGlucoseManager.self) { _ in BaseFetchGlucoseManager(resolver: resolver) }
+        container.register(FetchTreatmentsManager.self) { _ in BaseFetchTreatmentsManager(resolver: resolver) }
     }
     }
 }
 }

+ 5 - 0
FreeAPS/Sources/Containers/NetworkContainer.swift

@@ -1,3 +1,4 @@
+import Alamofire
 import Swinject
 import Swinject
 import UIKit
 import UIKit
 
 
@@ -5,6 +6,10 @@ private let resolver = FreeAPSApp.resolver
 
 
 enum NetworkContainer: DependeciesContainer {
 enum NetworkContainer: DependeciesContainer {
     static func register(container: Container) {
     static func register(container: Container) {
+        container.register(ReachabilityManager.self) { _ in
+            NetworkReachabilityManager()!
+        }.inObjectScope(.transient)
+
         container.register(NightscoutManager.self) { _ in BaseNightscoutManager(resolver: resolver) }
         container.register(NightscoutManager.self) { _ in BaseNightscoutManager(resolver: resolver) }
         container.register(AuthorizationManager.self) { _ in BaseAuthorizationManager(resolver: resolver) }
         container.register(AuthorizationManager.self) { _ in BaseAuthorizationManager(resolver: resolver) }
     }
     }

+ 44 - 0
FreeAPS/Sources/Helpers/ConvenienceExtensions.swift

@@ -0,0 +1,44 @@
+import UIKit
+
+protocol Occupiable {
+    var isEmpty: Bool { get }
+    var isNotEmpty: Bool { get }
+
+    var nonEmpty: Self? { get }
+}
+
+// Give a default implementation of isNotEmpty, so conformance only requires one implementation
+extension Occupiable {
+    var isNotEmpty: Bool {
+        !isEmpty
+    }
+
+    var nonEmpty: Self? {
+        isEmpty ? nil : self
+    }
+}
+
+extension String: Occupiable {}
+
+extension Array: Occupiable {}
+extension ArraySlice: Occupiable {}
+extension CGRect: Occupiable {}
+extension Data: Occupiable {}
+extension Dictionary: Occupiable {}
+extension Set: Occupiable {}
+
+// Extend the idea of occupiability to optionals. Specifically, optionals wrapping occupiable things.
+extension Optional where Wrapped: Occupiable {
+    var isNilOrEmpty: Bool {
+        switch self {
+        case .none:
+            return true
+        case let .some(value):
+            return value.isEmpty
+        }
+    }
+
+    var isNotNilNotEmpty: Bool {
+        !isNilOrEmpty
+    }
+}

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

@@ -5,7 +5,7 @@ struct CarbsEntry: JSON, Equatable {
     let carbs: Decimal
     let carbs: Decimal
     let enteredBy: String?
     let enteredBy: String?
 
 
-    static let manual = "freeaps-x://manual"
+    static let manual = "freeaps-x"
 }
 }
 
 
 extension CarbsEntry {
 extension CarbsEntry {

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

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

+ 8 - 2
FreeAPS/Sources/Models/TempTarget.swift

@@ -2,16 +2,21 @@ import Foundation
 
 
 struct TempTarget: JSON, Identifiable, Equatable {
 struct TempTarget: JSON, Identifiable, Equatable {
     var id = UUID().uuidString
     var id = UUID().uuidString
-    let name: String
+    let name: String?
     var createdAt: Date
     var createdAt: Date
     let targetTop: Decimal
     let targetTop: Decimal
     let targetBottom: Decimal
     let targetBottom: Decimal
     let duration: Decimal
     let duration: Decimal
     let enteredBy: String?
     let enteredBy: String?
+    let reason: String?
 
 
-    static let manual = "freeaps-x://manual"
+    static let manual = "freeaps-x"
     static let custom = "Temp target"
     static let custom = "Temp target"
     static let cancel = "Cancel"
     static let cancel = "Cancel"
+
+    var displayName: String {
+        name ?? reason ?? TempTarget.custom
+    }
 }
 }
 
 
 extension TempTarget {
 extension TempTarget {
@@ -23,5 +28,6 @@ extension TempTarget {
         case targetBottom
         case targetBottom
         case duration
         case duration
         case enteredBy
         case enteredBy
+        case reason
     }
     }
 }
 }

+ 6 - 3
FreeAPS/Sources/Modules/AddTempTarget/AddTempTargetViewModel.swift

@@ -37,7 +37,8 @@ extension AddTempTarget {
                 targetTop: highTarget,
                 targetTop: highTarget,
                 targetBottom: lowTarget,
                 targetBottom: lowTarget,
                 duration: duration,
                 duration: duration,
-                enteredBy: TempTarget.manual
+                enteredBy: TempTarget.manual,
+                reason: TempTarget.custom
             )
             )
             storage.storeTempTargets([entry])
             storage.storeTempTargets([entry])
             apsManager.determineBasal().sink { _ in }.store(in: &lifetime)
             apsManager.determineBasal().sink { _ in }.store(in: &lifetime)
@@ -52,7 +53,8 @@ extension AddTempTarget {
                 targetTop: 0,
                 targetTop: 0,
                 targetBottom: 0,
                 targetBottom: 0,
                 duration: 0,
                 duration: 0,
-                enteredBy: TempTarget.manual
+                enteredBy: TempTarget.manual,
+                reason: TempTarget.cancel
             )
             )
             storage.storeTempTargets([entry])
             storage.storeTempTargets([entry])
             apsManager.determineBasal().sink { _ in }.store(in: &lifetime)
             apsManager.determineBasal().sink { _ in }.store(in: &lifetime)
@@ -77,7 +79,8 @@ extension AddTempTarget {
                 targetTop: highTarget,
                 targetTop: highTarget,
                 targetBottom: lowTarget,
                 targetBottom: lowTarget,
                 duration: duration,
                 duration: duration,
-                enteredBy: TempTarget.manual
+                enteredBy: TempTarget.manual,
+                reason: newPresetName.isEmpty ? TempTarget.custom : newPresetName
             )
             )
 
 
             presets.append(entry)
             presets.append(entry)

+ 2 - 2
FreeAPS/Sources/Modules/AddTempTarget/View/AddTempTargetRootView.swift

@@ -84,7 +84,7 @@ extension AddTempTarget {
             return HStack {
             return HStack {
                 VStack {
                 VStack {
                     HStack {
                     HStack {
-                        Text(preset.name)
+                        Text(preset.displayName)
                         Spacer()
                         Spacer()
                     }
                     }
                     HStack {
                     HStack {
@@ -114,7 +114,7 @@ extension AddTempTarget {
                     .onTapGesture {
                     .onTapGesture {
                         removeAlert = Alert(
                         removeAlert = Alert(
                             title: Text("A you sure?"),
                             title: Text("A you sure?"),
-                            message: Text("Delete preset \"\(preset.name)\""),
+                            message: Text("Delete preset \"\(preset.displayName)\""),
                             primaryButton: .destructive(Text("Delete"), action: { viewModel.removePreset(id: preset.id) }),
                             primaryButton: .destructive(Text("Delete"), action: { viewModel.removePreset(id: preset.id) }),
                             secondaryButton: .cancel()
                             secondaryButton: .cancel()
                         )
                         )

+ 1 - 1
FreeAPS/Sources/Modules/Home/View/Header/CurrentGlucoseView.swift

@@ -41,7 +41,7 @@ struct CurrentGlucoseView: View {
                         ?? "--"
                         ?? "--"
                 )
                 )
                 .font(.system(size: 24, weight: .bold))
                 .font(.system(size: 24, weight: .bold))
-                .minimumScaleFactor(0.5)
+                .fixedSize()
                 image.padding(.bottom, 2)
                 image.padding(.bottom, 2)
 
 
             }.padding(.leading, 4)
             }.padding(.leading, 4)

+ 1 - 1
FreeAPS/Sources/Modules/Home/View/HomeRootView.swift

@@ -87,7 +87,7 @@ extension Home {
                 }
                 }
 
 
                 if let tempTarget = viewModel.tempTarget {
                 if let tempTarget = viewModel.tempTarget {
-                    Text(tempTarget.name).font(.caption).foregroundColor(.secondary)
+                    Text(tempTarget.displayName).font(.caption).foregroundColor(.secondary)
                     if viewModel.units == .mmolL {
                     if viewModel.units == .mmolL {
                         Text(
                         Text(
                             targetFormatter
                             targetFormatter

+ 3 - 2
FreeAPS/Sources/Services/Network/NightscoutAPI.swift

@@ -31,7 +31,7 @@ extension NightscoutAPI {
     func checkConnection() -> AnyPublisher<Void, Swift.Error> {
     func checkConnection() -> AnyPublisher<Void, Swift.Error> {
         struct Check: Codable, Equatable {
         struct Check: Codable, Equatable {
             var eventType = "Note"
             var eventType = "Note"
-            var enteredBy = "freeaps-x://"
+            var enteredBy = "freeaps-x"
             var notes = "FreeAPS X connected"
             var notes = "FreeAPS X connected"
         }
         }
         let check = Check()
         let check = Check()
@@ -171,7 +171,8 @@ extension NightscoutAPI {
             URLQueryItem(
             URLQueryItem(
                 name: "find[enteredBy][$ne]",
                 name: "find[enteredBy][$ne]",
                 value: NigtscoutTreatment.local.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
                 value: NigtscoutTreatment.local.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed)
-            )
+            ),
+            URLQueryItem(name: "find[duration][$exists]", value: "true")
         ]
         ]
         if let date = sinceDate {
         if let date = sinceDate {
             let dateItem = URLQueryItem(
             let dateItem = URLQueryItem(

+ 16 - 17
FreeAPS/Sources/Services/Network/NightscoutManager.swift

@@ -5,8 +5,8 @@ import UIKit
 
 
 protocol NightscoutManager {
 protocol NightscoutManager {
     func fetchGlucose() -> AnyPublisher<[BloodGlucose], Never>
     func fetchGlucose() -> AnyPublisher<[BloodGlucose], Never>
-    func fetchCarbs() -> AnyPublisher<Void, Never>
-    func fetchTempTargets() -> AnyPublisher<Void, Never>
+    func fetchCarbs() -> AnyPublisher<[CarbsEntry], Never>
+    func fetchTempTargets() -> AnyPublisher<[TempTarget], Never>
     func fetchAnnouncements() -> AnyPublisher<Void, Never>
     func fetchAnnouncements() -> AnyPublisher<Void, Never>
     func deleteCarbs(at date: Date)
     func deleteCarbs(at date: Date)
     func uploadStatus()
     func uploadStatus()
@@ -23,11 +23,16 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
     @Injected() private var announcementsStorage: AnnouncementsStorage!
     @Injected() private var announcementsStorage: AnnouncementsStorage!
     @Injected() private var settingsManager: SettingsManager!
     @Injected() private var settingsManager: SettingsManager!
     @Injected() private var broadcaster: Broadcaster!
     @Injected() private var broadcaster: Broadcaster!
+    @Injected() private var reachabilityManager: ReachabilityManager!
 
 
     private let processQueue = DispatchQueue(label: "BaseNetworkManager.processQueue")
     private let processQueue = DispatchQueue(label: "BaseNetworkManager.processQueue")
 
 
     private var lifetime = Set<AnyCancellable>()
     private var lifetime = Set<AnyCancellable>()
 
 
+    private var isNetworkReachable: Bool {
+        reachabilityManager.isReachable
+    }
+
     private var isUploadEnabled: Bool {
     private var isUploadEnabled: Bool {
         settingsManager.settings.isUploadEnabled ?? false
         settingsManager.settings.isUploadEnabled ?? false
     }
     }
@@ -86,36 +91,30 @@ final class BaseNightscoutManager: NightscoutManager, Injectable {
             .eraseToAnyPublisher()
             .eraseToAnyPublisher()
     }
     }
 
 
-    func fetchCarbs() -> AnyPublisher<Void, Never> {
-        guard let nightscout = nightscoutAPI else {
-            return Just(()).eraseToAnyPublisher()
+    func fetchCarbs() -> AnyPublisher<[CarbsEntry], Never> {
+        guard let nightscout = nightscoutAPI, isNetworkReachable else {
+            return Just([]).eraseToAnyPublisher()
         }
         }
 
 
         let since = carbsStorage.syncDate()
         let since = carbsStorage.syncDate()
         return nightscout.fetchCarbs(sinceDate: since)
         return nightscout.fetchCarbs(sinceDate: since)
             .replaceError(with: [])
             .replaceError(with: [])
-            .map {
-                self.carbsStorage.storeCarbs($0)
-                return ()
-            }.eraseToAnyPublisher()
+            .eraseToAnyPublisher()
     }
     }
 
 
-    func fetchTempTargets() -> AnyPublisher<Void, Never> {
-        guard let nightscout = nightscoutAPI else {
-            return Just(()).eraseToAnyPublisher()
+    func fetchTempTargets() -> AnyPublisher<[TempTarget], Never> {
+        guard let nightscout = nightscoutAPI, isNetworkReachable else {
+            return Just([]).eraseToAnyPublisher()
         }
         }
 
 
         let since = tempTargetsStorage.syncDate()
         let since = tempTargetsStorage.syncDate()
         return nightscout.fetchTempTargets(sinceDate: since)
         return nightscout.fetchTempTargets(sinceDate: since)
             .replaceError(with: [])
             .replaceError(with: [])
-            .map {
-                self.tempTargetsStorage.storeTempTargets($0)
-                return ()
-            }.eraseToAnyPublisher()
+            .eraseToAnyPublisher()
     }
     }
 
 
     func fetchAnnouncements() -> AnyPublisher<Void, Never> {
     func fetchAnnouncements() -> AnyPublisher<Void, Never> {
-        guard let nightscout = nightscoutAPI else {
+        guard let nightscout = nightscoutAPI, isNetworkReachable else {
             return Just(()).eraseToAnyPublisher()
             return Just(()).eraseToAnyPublisher()
         }
         }
 
 

+ 27 - 0
FreeAPS/Sources/Services/Network/ReachabilityManager.swift

@@ -0,0 +1,27 @@
+import Alamofire
+import Foundation
+
+typealias ReachabilityStatus = NetworkReachabilityManager.NetworkReachabilityStatus
+typealias Listener = NetworkReachabilityManager.Listener
+
+protocol ReachabilityManager: AnyObject {
+    var status: ReachabilityStatus { get }
+    var isReachable: Bool { get }
+    func startListening(onQueue: DispatchQueue, onUpdatePerforming: @escaping Listener) -> Bool
+    func stopListening()
+}
+
+extension NetworkReachabilityManager: ReachabilityManager {}
+
+extension ReachabilityStatus: CustomStringConvertible {
+    public var description: String {
+        switch self {
+        case .unknown:
+            return "unknown"
+        case .notReachable:
+            return "NOT reachable"
+        case let .reachable(connectionType):
+            return "reachable by " + (connectionType == .cellular ? "Cellular" : "WiFi")
+        }
+    }
+}