소스 검색

Watch app template

Ivan Valkou 4 년 전
부모
커밋
1c97ffd8f8
30개의 변경된 파일1118개의 추가작업 그리고 1개의 파일을 삭제
  1. 359 1
      FreeAPS.xcodeproj/project.pbxproj
  2. 15 0
      FreeAPS.xcodeproj/xcuserdata/i.valkou.xcuserdatad/xcschemes/xcschememanagement.plist
  3. 1 0
      FreeAPS/Sources/Application/FreeAPSApp.swift
  4. 1 0
      FreeAPS/Sources/Assemblies/ServiceAssembly.swift
  5. 34 0
      FreeAPS/Sources/Services/WatchManager/WatchManager.swift
  6. 25 0
      FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json
  7. 53 0
      FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Contents.json
  8. 25 0
      FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json
  9. 20 0
      FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json
  10. 20 0
      FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json
  11. 20 0
      FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json
  12. 25 0
      FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json
  13. 20 0
      FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json
  14. 25 0
      FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json
  15. 25 0
      FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json
  16. 6 0
      FreeAPSWatch WatchKit Extension/Assets.xcassets/Contents.json
  17. 59 0
      FreeAPSWatch WatchKit Extension/ComplicationController.swift
  18. 3 0
      FreeAPSWatch WatchKit Extension/DataFlow.swift
  19. 13 0
      FreeAPSWatch WatchKit Extension/FreeAPSApp.swift
  20. 16 0
      FreeAPSWatch WatchKit Extension/Info.plist
  21. 25 0
      FreeAPSWatch WatchKit Extension/NotificationController.swift
  22. 13 0
      FreeAPSWatch WatchKit Extension/NotificationView.swift
  23. 6 0
      FreeAPSWatch WatchKit Extension/Preview Content/Preview Assets.xcassets/Contents.json
  24. 20 0
      FreeAPSWatch WatchKit Extension/PushNotificationPayload.apns
  25. 69 0
      FreeAPSWatch WatchKit Extension/Views/CarbsView.swift
  26. 58 0
      FreeAPSWatch WatchKit Extension/Views/MainView.swift
  27. 36 0
      FreeAPSWatch WatchKit Extension/Views/WatchStateModel.swift
  28. 11 0
      FreeAPSWatch/Assets.xcassets/AccentColor.colorset/Contents.json
  29. 109 0
      FreeAPSWatch/Assets.xcassets/AppIcon.appiconset/Contents.json
  30. 6 0
      FreeAPSWatch/Assets.xcassets/Contents.json

+ 359 - 1
FreeAPS.xcodeproj/project.pbxproj

@@ -180,6 +180,23 @@
 		38E87401274F77E400975559 /* CoreNFC.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38E873FD274F761800975559 /* CoreNFC.framework */; settings = {ATTRIBUTES = (Weak, ); }; };
 		38E87403274F78C000975559 /* libswiftCoreNFC.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = 38E87402274F78C000975559 /* libswiftCoreNFC.tbd */; settings = {ATTRIBUTES = (Weak, ); }; };
 		38E87408274F9AD000975559 /* UserNotificationsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E87407274F9AD000975559 /* UserNotificationsManager.swift */; };
+		38E8751F27554D5700975559 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 38E8751E27554D5700975559 /* Assets.xcassets */; };
+		38E8752527554D5700975559 /* FreeAPSWatch WatchKit Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 38E8752427554D5700975559 /* FreeAPSWatch WatchKit Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
+		38E8752A27554D5700975559 /* FreeAPSApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E8752927554D5700975559 /* FreeAPSApp.swift */; };
+		38E8752C27554D5700975559 /* MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E8752B27554D5700975559 /* MainView.swift */; };
+		38E8752E27554D5700975559 /* NotificationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E8752D27554D5700975559 /* NotificationController.swift */; };
+		38E8753027554D5700975559 /* NotificationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E8752F27554D5700975559 /* NotificationView.swift */; };
+		38E8753227554D5700975559 /* ComplicationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E8753127554D5700975559 /* ComplicationController.swift */; };
+		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 */; };
+		38E8754F275556FA00975559 /* WatchManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E8754E275556FA00975559 /* WatchManager.swift */; };
+		38E8755127555D0500975559 /* DataFlow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E8755027555D0500975559 /* DataFlow.swift */; };
 		38E989DD25F5021400C0CED0 /* PumpStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E989DC25F5021400C0CED0 /* PumpStatus.swift */; };
 		38E98A2325F52C9300C0CED0 /* Signpost.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E98A1B25F52C9300C0CED0 /* Signpost.swift */; };
 		38E98A2425F52C9300C0CED0 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 38E98A1C25F52C9300C0CED0 /* Logger.swift */; };
@@ -276,6 +293,20 @@
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
+		38E8752627554D5700975559 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 388E595025AD948C0019842D /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 38E8752327554D5700975559;
+			remoteInfo = "FreeAPSWatch WatchKit Extension";
+		};
+		38E8753A27554D5900975559 /* PBXContainerItemProxy */ = {
+			isa = PBXContainerItemProxy;
+			containerPortal = 388E595025AD948C0019842D /* Project object */;
+			proxyType = 1;
+			remoteGlobalIDString = 38E8751B27554D5500975559;
+			remoteInfo = FreeAPSWatch;
+		};
 		38FCF3F225E9028E0078B0D1 /* PBXContainerItemProxy */ = {
 			isa = PBXContainerItemProxy;
 			containerPortal = 388E595025AD948C0019842D /* Project object */;
@@ -310,6 +341,28 @@
 			name = "Embed Frameworks";
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		38E8753D27554D5900975559 /* Embed Watch Content */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
+			dstSubfolderSpec = 16;
+			files = (
+				38E8753C27554D5900975559 /* FreeAPSWatch.app in Embed Watch Content */,
+			);
+			name = "Embed Watch Content";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		38E8754027554D5900975559 /* Embed App Extensions */ = {
+			isa = PBXCopyFilesBuildPhase;
+			buildActionMask = 2147483647;
+			dstPath = "";
+			dstSubfolderSpec = 13;
+			files = (
+				38E8752527554D5700975559 /* FreeAPSWatch WatchKit Extension.appex in Embed App Extensions */,
+			);
+			name = "Embed App Extensions";
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 /* End PBXCopyFilesBuildPhase section */
 
 /* Begin PBXFileReference section */
@@ -509,6 +562,22 @@
 		38E873FD274F761800975559 /* CoreNFC.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreNFC.framework; path = System/Library/Frameworks/CoreNFC.framework; sourceTree = SDKROOT; };
 		38E87402274F78C000975559 /* libswiftCoreNFC.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = libswiftCoreNFC.tbd; path = usr/lib/swift/libswiftCoreNFC.tbd; sourceTree = SDKROOT; };
 		38E87407274F9AD000975559 /* UserNotificationsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserNotificationsManager.swift; sourceTree = "<group>"; };
+		38E8751C27554D5500975559 /* FreeAPSWatch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FreeAPSWatch.app; sourceTree = BUILT_PRODUCTS_DIR; };
+		38E8751E27554D5700975559 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		38E8752427554D5700975559 /* FreeAPSWatch WatchKit Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "FreeAPSWatch WatchKit Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
+		38E8752927554D5700975559 /* FreeAPSApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FreeAPSApp.swift; sourceTree = "<group>"; };
+		38E8752B27554D5700975559 /* MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MainView.swift; sourceTree = "<group>"; };
+		38E8752D27554D5700975559 /* NotificationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationController.swift; sourceTree = "<group>"; };
+		38E8752F27554D5700975559 /* NotificationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationView.swift; sourceTree = "<group>"; };
+		38E8753127554D5700975559 /* ComplicationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplicationController.swift; sourceTree = "<group>"; };
+		38E8753327554D5800975559 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
+		38E8753627554D5800975559 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
+		38E8753827554D5900975559 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
+		38E8753927554D5900975559 /* PushNotificationPayload.apns */ = {isa = PBXFileReference; lastKnownFileType = text; path = PushNotificationPayload.apns; sourceTree = "<group>"; };
+		38E87549275550BB00975559 /* CarbsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarbsView.swift; sourceTree = "<group>"; };
+		38E8754B2755548F00975559 /* WatchStateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchStateModel.swift; sourceTree = "<group>"; };
+		38E8754E275556FA00975559 /* WatchManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchManager.swift; sourceTree = "<group>"; };
+		38E8755027555D0500975559 /* DataFlow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DataFlow.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>"; };
 		38E98A1C25F52C9300C0CED0 /* Logger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = "<group>"; };
@@ -637,6 +706,13 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		38E8752127554D5700975559 /* Frameworks */ = {
+			isa = PBXFrameworksBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		38FCF3EA25E9028E0078B0D1 /* Frameworks */ = {
 			isa = PBXFrameworksBuildPhase;
 			buildActionMask = 2147483647;
@@ -856,6 +932,7 @@
 		3811DE9125C9D88200A708ED /* Services */ = {
 			isa = PBXGroup;
 			children = (
+				38E8754D275556E100975559 /* WatchManager */,
 				38E87406274F9AA500975559 /* UserNotifiactions */,
 				3862CC2C2743F9DC00BF832C /* Calendar */,
 				38AEE75025F021F10013F05B /* SettingsManager */,
@@ -1076,6 +1153,8 @@
 				388E595A25AD948C0019842D /* FreeAPS */,
 				38FCF3EE25E9028E0078B0D1 /* FreeAPSTests */,
 				3818AA44274C229000843DB3 /* Packages */,
+				38E8751D27554D5500975559 /* FreeAPSWatch */,
+				38E8752827554D5700975559 /* FreeAPSWatch WatchKit Extension */,
 				388E595925AD948C0019842D /* Products */,
 				3818AA48274C267000843DB3 /* Frameworks */,
 			);
@@ -1086,6 +1165,8 @@
 			children = (
 				388E595825AD948C0019842D /* FreeAPS.app */,
 				38FCF3ED25E9028E0078B0D1 /* FreeAPSTests.xctest */,
+				38E8751C27554D5500975559 /* FreeAPSWatch.app */,
+				38E8752427554D5700975559 /* FreeAPSWatch WatchKit Extension.appex */,
 			);
 			name = Products;
 			sourceTree = "<group>";
@@ -1241,6 +1322,57 @@
 			path = UserNotifiactions;
 			sourceTree = "<group>";
 		};
+		38E8751D27554D5500975559 /* FreeAPSWatch */ = {
+			isa = PBXGroup;
+			children = (
+				38E8751E27554D5700975559 /* Assets.xcassets */,
+			);
+			path = FreeAPSWatch;
+			sourceTree = "<group>";
+		};
+		38E8752827554D5700975559 /* FreeAPSWatch WatchKit Extension */ = {
+			isa = PBXGroup;
+			children = (
+				38E875482755505800975559 /* Views */,
+				38E8752927554D5700975559 /* FreeAPSApp.swift */,
+				38E8752D27554D5700975559 /* NotificationController.swift */,
+				38E8752F27554D5700975559 /* NotificationView.swift */,
+				38E8753127554D5700975559 /* ComplicationController.swift */,
+				38E8753327554D5800975559 /* Assets.xcassets */,
+				38E8753827554D5900975559 /* Info.plist */,
+				38E8753927554D5900975559 /* PushNotificationPayload.apns */,
+				38E8753527554D5800975559 /* Preview Content */,
+				38E8755027555D0500975559 /* DataFlow.swift */,
+			);
+			path = "FreeAPSWatch WatchKit Extension";
+			sourceTree = "<group>";
+		};
+		38E8753527554D5800975559 /* Preview Content */ = {
+			isa = PBXGroup;
+			children = (
+				38E8753627554D5800975559 /* Preview Assets.xcassets */,
+			);
+			path = "Preview Content";
+			sourceTree = "<group>";
+		};
+		38E875482755505800975559 /* Views */ = {
+			isa = PBXGroup;
+			children = (
+				38E8752B27554D5700975559 /* MainView.swift */,
+				38E8754B2755548F00975559 /* WatchStateModel.swift */,
+				38E87549275550BB00975559 /* CarbsView.swift */,
+			);
+			path = Views;
+			sourceTree = "<group>";
+		};
+		38E8754D275556E100975559 /* WatchManager */ = {
+			isa = PBXGroup;
+			children = (
+				38E8754E275556FA00975559 /* WatchManager.swift */,
+			);
+			path = WatchManager;
+			sourceTree = "<group>";
+		};
 		38E98A1A25F52C9300C0CED0 /* Logger */ = {
 			isa = PBXGroup;
 			children = (
@@ -1625,10 +1757,12 @@
 				388E595525AD948C0019842D /* Frameworks */,
 				388E595625AD948C0019842D /* Resources */,
 				3821ECD025DC703C00BC42AD /* Embed Frameworks */,
+				38E8753D27554D5900975559 /* Embed Watch Content */,
 			);
 			buildRules = (
 			);
 			dependencies = (
+				38E8753B27554D5900975559 /* PBXTargetDependency */,
 			);
 			name = FreeAPS;
 			packageProductDependencies = (
@@ -1641,6 +1775,40 @@
 			productReference = 388E595825AD948C0019842D /* FreeAPS.app */;
 			productType = "com.apple.product-type.application";
 		};
+		38E8751B27554D5500975559 /* FreeAPSWatch */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 38E8754427554D5900975559 /* Build configuration list for PBXNativeTarget "FreeAPSWatch" */;
+			buildPhases = (
+				38E8751A27554D5500975559 /* Resources */,
+				38E8754027554D5900975559 /* Embed App Extensions */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+				38E8752727554D5700975559 /* PBXTargetDependency */,
+			);
+			name = FreeAPSWatch;
+			productName = FreeAPSWatch;
+			productReference = 38E8751C27554D5500975559 /* FreeAPSWatch.app */;
+			productType = "com.apple.product-type.application.watchapp2";
+		};
+		38E8752327554D5700975559 /* FreeAPSWatch WatchKit Extension */ = {
+			isa = PBXNativeTarget;
+			buildConfigurationList = 38E8754327554D5900975559 /* Build configuration list for PBXNativeTarget "FreeAPSWatch WatchKit Extension" */;
+			buildPhases = (
+				38E8752027554D5700975559 /* Sources */,
+				38E8752127554D5700975559 /* Frameworks */,
+				38E8752227554D5700975559 /* Resources */,
+			);
+			buildRules = (
+			);
+			dependencies = (
+			);
+			name = "FreeAPSWatch WatchKit Extension";
+			productName = "FreeAPSWatch WatchKit Extension";
+			productReference = 38E8752427554D5700975559 /* FreeAPSWatch WatchKit Extension.appex */;
+			productType = "com.apple.product-type.watchkit2-extension";
+		};
 		38FCF3EC25E9028E0078B0D1 /* FreeAPSTests */ = {
 			isa = PBXNativeTarget;
 			buildConfigurationList = 38FCF3F425E9028E0078B0D1 /* Build configuration list for PBXNativeTarget "FreeAPSTests" */;
@@ -1665,12 +1833,18 @@
 		388E595025AD948C0019842D /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
-				LastSwiftUpdateCheck = 1240;
+				LastSwiftUpdateCheck = 1310;
 				LastUpgradeCheck = 1240;
 				TargetAttributes = {
 					388E595725AD948C0019842D = {
 						CreatedOnToolsVersion = 12.3;
 					};
+					38E8751B27554D5500975559 = {
+						CreatedOnToolsVersion = 13.1;
+					};
+					38E8752327554D5700975559 = {
+						CreatedOnToolsVersion = 13.1;
+					};
 					38FCF3EC25E9028E0078B0D1 = {
 						CreatedOnToolsVersion = 12.4;
 						TestTargetID = 388E595725AD948C0019842D;
@@ -1716,6 +1890,8 @@
 			targets = (
 				388E595725AD948C0019842D /* FreeAPS */,
 				38FCF3EC25E9028E0078B0D1 /* FreeAPSTests */,
+				38E8751B27554D5500975559 /* FreeAPSWatch */,
+				38E8752327554D5700975559 /* FreeAPSWatch WatchKit Extension */,
 			);
 		};
 /* End PBXProject section */
@@ -1733,6 +1909,25 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		38E8751A27554D5500975559 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				38E8754527554D8800975559 /* Assets.xcassets in Resources */,
+				38E8751F27554D5700975559 /* Assets.xcassets in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
+		38E8752227554D5700975559 /* Resources */ = {
+			isa = PBXResourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				38E8753727554D5900975559 /* Preview Assets.xcassets in Resources */,
+				38E8754627554D8A00975559 /* Assets.xcassets in Resources */,
+				38E8753427554D5800975559 /* Assets.xcassets in Resources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		38FCF3EB25E9028E0078B0D1 /* Resources */ = {
 			isa = PBXResourcesBuildPhase;
 			buildActionMask = 2147483647;
@@ -1936,6 +2131,7 @@
 				5075C1608E6249A51495C422 /* TargetsEditorProvider.swift in Sources */,
 				E13B7DAB2A435F57066AF02E /* TargetsEditorStateModel.swift in Sources */,
 				9702FF92A09C53942F20D7EA /* TargetsEditorRootView.swift in Sources */,
+				38E8754F275556FA00975559 /* WatchManager.swift in Sources */,
 				A228DF96647338139F152B15 /* PreferencesEditorDataFlow.swift in Sources */,
 				389ECE052601144100D86C4F /* ConcurrentMap.swift in Sources */,
 				E4984C5262A90469788754BB /* PreferencesEditorProvider.swift in Sources */,
@@ -1997,6 +2193,22 @@
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
+		38E8752027554D5700975559 /* Sources */ = {
+			isa = PBXSourcesBuildPhase;
+			buildActionMask = 2147483647;
+			files = (
+				38E8752E27554D5700975559 /* NotificationController.swift in Sources */,
+				38E8754C2755548F00975559 /* WatchStateModel.swift in Sources */,
+				38E8754A275550BB00975559 /* CarbsView.swift in Sources */,
+				38E8752C27554D5700975559 /* MainView.swift in Sources */,
+				38E8755127555D0500975559 /* DataFlow.swift in Sources */,
+				38E8753227554D5700975559 /* ComplicationController.swift in Sources */,
+				38E8752A27554D5700975559 /* FreeAPSApp.swift in Sources */,
+				38E8753027554D5700975559 /* NotificationView.swift in Sources */,
+				38E8754727554DF100975559 /* Color+Extensions.swift in Sources */,
+			);
+			runOnlyForDeploymentPostprocessing = 0;
+		};
 		38FCF3E925E9028E0078B0D1 /* Sources */ = {
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
@@ -2008,6 +2220,16 @@
 /* End PBXSourcesBuildPhase section */
 
 /* Begin PBXTargetDependency section */
+		38E8752727554D5700975559 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 38E8752327554D5700975559 /* FreeAPSWatch WatchKit Extension */;
+			targetProxy = 38E8752627554D5700975559 /* PBXContainerItemProxy */;
+		};
+		38E8753B27554D5900975559 /* PBXTargetDependency */ = {
+			isa = PBXTargetDependency;
+			target = 38E8751B27554D5500975559 /* FreeAPSWatch */;
+			targetProxy = 38E8753A27554D5900975559 /* PBXContainerItemProxy */;
+		};
 		38FCF3F325E9028E0078B0D1 /* PBXTargetDependency */ = {
 			isa = PBXTargetDependency;
 			target = 388E595725AD948C0019842D /* FreeAPS */;
@@ -2263,6 +2485,124 @@
 			};
 			name = Release;
 		};
+		38E8753E27554D5900975559 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 0.2.4;
+				DEVELOPMENT_TEAM = "${DEVELOPER_TEAM}";
+				GENERATE_INFOPLIST_FILE = YES;
+				IBSC_MODULE = FreeAPSWatch_WatchKit_Extension;
+				INFOPLIST_KEY_CFBundleDisplayName = FreeAPSWatch;
+				INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
+				INFOPLIST_KEY_WKCompanionAppBundleIdentifier = ru.artpancreas.FreeAPS;
+				MARKETING_VERSION = 1;
+				PRODUCT_BUNDLE_IDENTIFIER = ru.artpancreas.FreeAPS.watchkitapp;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = watchos;
+				SKIP_INSTALL = YES;
+				SWIFT_EMIT_LOC_STRINGS = YES;
+				SWIFT_VERSION = 5.0;
+				TARGETED_DEVICE_FAMILY = 4;
+				WATCHOS_DEPLOYMENT_TARGET = 8.0;
+			};
+			name = Debug;
+		};
+		38E8753F27554D5900975559 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
+				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 0.2.4;
+				DEVELOPMENT_TEAM = "${DEVELOPER_TEAM}";
+				GENERATE_INFOPLIST_FILE = YES;
+				IBSC_MODULE = FreeAPSWatch_WatchKit_Extension;
+				INFOPLIST_KEY_CFBundleDisplayName = FreeAPSWatch;
+				INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
+				INFOPLIST_KEY_WKCompanionAppBundleIdentifier = ru.artpancreas.FreeAPS;
+				MARKETING_VERSION = 1;
+				PRODUCT_BUNDLE_IDENTIFIER = ru.artpancreas.FreeAPS.watchkitapp;
+				PRODUCT_NAME = "$(TARGET_NAME)";
+				SDKROOT = watchos;
+				SKIP_INSTALL = YES;
+				SWIFT_EMIT_LOC_STRINGS = YES;
+				SWIFT_VERSION = 5.0;
+				TARGETED_DEVICE_FAMILY = 4;
+				WATCHOS_DEPLOYMENT_TARGET = 8.0;
+			};
+			name = Release;
+		};
+		38E8754127554D5900975559 /* Debug */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 0.2.4;
+				DEVELOPMENT_ASSET_PATHS = "\"FreeAPSWatch WatchKit Extension/Preview Content\"";
+				DEVELOPMENT_TEAM = BA7ZHP4963;
+				ENABLE_PREVIEWS = YES;
+				GENERATE_INFOPLIST_FILE = YES;
+				INFOPLIST_FILE = "FreeAPSWatch WatchKit Extension/Info.plist";
+				INFOPLIST_KEY_CFBundleDisplayName = "FreeAPSWatch WatchKit Extension";
+				INFOPLIST_KEY_CLKComplicationPrincipalClass = FreeAPSWatch_WatchKit_Extension.ComplicationController;
+				INFOPLIST_KEY_NSHumanReadableCopyright = "";
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+					"@executable_path/../../Frameworks",
+				);
+				MARKETING_VERSION = 1;
+				PRODUCT_BUNDLE_IDENTIFIER = ru.artpancreas.FreeAPS.watchkitapp.watchkitextension;
+				PRODUCT_NAME = "${TARGET_NAME}";
+				SDKROOT = watchos;
+				SKIP_INSTALL = YES;
+				SWIFT_EMIT_LOC_STRINGS = YES;
+				SWIFT_VERSION = 5.0;
+				TARGETED_DEVICE_FAMILY = 4;
+				WATCHOS_DEPLOYMENT_TARGET = 8.0;
+			};
+			name = Debug;
+		};
+		38E8754227554D5900975559 /* Release */ = {
+			isa = XCBuildConfiguration;
+			buildSettings = {
+				ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication;
+				CLANG_CXX_LANGUAGE_STANDARD = "gnu++17";
+				CODE_SIGN_STYLE = Automatic;
+				CURRENT_PROJECT_VERSION = 0.2.4;
+				DEVELOPMENT_ASSET_PATHS = "\"FreeAPSWatch WatchKit Extension/Preview Content\"";
+				DEVELOPMENT_TEAM = BA7ZHP4963;
+				ENABLE_PREVIEWS = YES;
+				GENERATE_INFOPLIST_FILE = YES;
+				INFOPLIST_FILE = "FreeAPSWatch WatchKit Extension/Info.plist";
+				INFOPLIST_KEY_CFBundleDisplayName = "FreeAPSWatch WatchKit Extension";
+				INFOPLIST_KEY_CLKComplicationPrincipalClass = FreeAPSWatch_WatchKit_Extension.ComplicationController;
+				INFOPLIST_KEY_NSHumanReadableCopyright = "";
+				LD_RUNPATH_SEARCH_PATHS = (
+					"$(inherited)",
+					"@executable_path/Frameworks",
+					"@executable_path/../../Frameworks",
+				);
+				MARKETING_VERSION = 1;
+				PRODUCT_BUNDLE_IDENTIFIER = ru.artpancreas.FreeAPS.watchkitapp.watchkitextension;
+				PRODUCT_NAME = "${TARGET_NAME}";
+				SDKROOT = watchos;
+				SKIP_INSTALL = YES;
+				SWIFT_EMIT_LOC_STRINGS = YES;
+				SWIFT_VERSION = 5.0;
+				TARGETED_DEVICE_FAMILY = 4;
+				WATCHOS_DEPLOYMENT_TARGET = 8.0;
+			};
+			name = Release;
+		};
 		38FCF3F525E9028E0078B0D1 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
@@ -2326,6 +2666,24 @@
 			defaultConfigurationIsVisible = 0;
 			defaultConfigurationName = Release;
 		};
+		38E8754327554D5900975559 /* Build configuration list for PBXNativeTarget "FreeAPSWatch WatchKit Extension" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				38E8754127554D5900975559 /* Debug */,
+				38E8754227554D5900975559 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
+		38E8754427554D5900975559 /* Build configuration list for PBXNativeTarget "FreeAPSWatch" */ = {
+			isa = XCConfigurationList;
+			buildConfigurations = (
+				38E8753E27554D5900975559 /* Debug */,
+				38E8753F27554D5900975559 /* Release */,
+			);
+			defaultConfigurationIsVisible = 0;
+			defaultConfigurationName = Release;
+		};
 		38FCF3F425E9028E0078B0D1 /* Build configuration list for PBXNativeTarget "FreeAPSTests" */ = {
 			isa = XCConfigurationList;
 			buildConfigurations = (

+ 15 - 0
FreeAPS.xcodeproj/xcuserdata/i.valkou.xcuserdatad/xcschemes/xcschememanagement.plist

@@ -30,6 +30,21 @@
 			<key>orderHint</key>
 			<integer>0</integer>
 		</dict>
+		<key>FreeAPSWatch (Complication).xcscheme_^#shared#^_</key>
+		<dict>
+			<key>orderHint</key>
+			<integer>114</integer>
+		</dict>
+		<key>FreeAPSWatch (Notification).xcscheme_^#shared#^_</key>
+		<dict>
+			<key>orderHint</key>
+			<integer>113</integer>
+		</dict>
+		<key>FreeAPSWatch.xcscheme_^#shared#^_</key>
+		<dict>
+			<key>orderHint</key>
+			<integer>112</integer>
+		</dict>
 		<key>ReactiveSwift (Playground) 1.xcscheme</key>
 		<dict>
 			<key>isShown</key>

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

@@ -37,6 +37,7 @@ import Swinject
         _ = resolver.resolve(FetchAnnouncementsManager.self)!
         _ = resolver.resolve(CalendarManager.self)!
         _ = resolver.resolve(UserNotificationsManager.self)!
+        _ = resolver.resolve(WatchManager.self)!
     }
 
     init() {

+ 1 - 0
FreeAPS/Sources/Assemblies/ServiceAssembly.swift

@@ -15,5 +15,6 @@ final class ServiceAssembly: Assembly {
         }
         container.register(CalendarManager.self) { r in BaseCalendarManager(resolver: r) }
         container.register(UserNotificationsManager.self) { r in BaseUserNotificationsManager(resolver: r) }
+        container.register(WatchManager.self) { _ in BaseWatchManager() }
     }
 }

+ 34 - 0
FreeAPS/Sources/Services/WatchManager/WatchManager.swift

@@ -0,0 +1,34 @@
+import Foundation
+import WatchConnectivity
+
+protocol WatchManager {}
+
+final class BaseWatchManager: NSObject, WatchManager {
+    var session: WCSession
+
+    init(session: WCSession = .default) {
+        self.session = session
+        super.init()
+
+        if WCSession.isSupported() {
+            session.delegate = self
+            session.activate()
+        }
+    }
+}
+
+extension BaseWatchManager: WCSessionDelegate {
+    func sessionDidBecomeInactive(_: WCSession) {}
+
+    func sessionDidDeactivate(_: WCSession) {}
+
+    func session(_: WCSession, activationDidCompleteWith state: WCSessionActivationState, error _: Error?) {
+        print("ASDF state \(state.rawValue)")
+    }
+
+    func session(_ session: WCSession, didReceiveMessage message: [String: Any]) {
+        print("ASDF message \(message)")
+        session.sendMessage(["message": "It works!"], replyHandler: nil) { _ in
+        }
+    }
+}

+ 25 - 0
FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json

@@ -0,0 +1,25 @@
+{
+  "images" : [
+    {
+      "idiom" : "watch",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "watch",
+      "scale" : "2x",
+      "screen-width" : "<=145"
+    },
+    {
+      "idiom" : "watch",
+      "scale" : "2x",
+      "screen-width" : ">183"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "auto-scaling" : "auto"
+  }
+}

+ 53 - 0
FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Contents.json

@@ -0,0 +1,53 @@
+{
+  "assets" : [
+    {
+      "filename" : "Circular.imageset",
+      "idiom" : "watch",
+      "role" : "circular"
+    },
+    {
+      "filename" : "Extra Large.imageset",
+      "idiom" : "watch",
+      "role" : "extra-large"
+    },
+    {
+      "filename" : "Graphic Bezel.imageset",
+      "idiom" : "watch",
+      "role" : "graphic-bezel"
+    },
+    {
+      "filename" : "Graphic Circular.imageset",
+      "idiom" : "watch",
+      "role" : "graphic-circular"
+    },
+    {
+      "filename" : "Graphic Corner.imageset",
+      "idiom" : "watch",
+      "role" : "graphic-corner"
+    },
+    {
+      "filename" : "Graphic Extra Large.imageset",
+      "idiom" : "watch",
+      "role" : "graphic-extra-large"
+    },
+    {
+      "filename" : "Graphic Large Rectangular.imageset",
+      "idiom" : "watch",
+      "role" : "graphic-large-rectangular"
+    },
+    {
+      "filename" : "Modular.imageset",
+      "idiom" : "watch",
+      "role" : "modular"
+    },
+    {
+      "filename" : "Utilitarian.imageset",
+      "idiom" : "watch",
+      "role" : "utilitarian"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 25 - 0
FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json

@@ -0,0 +1,25 @@
+{
+  "images" : [
+    {
+      "idiom" : "watch",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "watch",
+      "scale" : "2x",
+      "screen-width" : "<=145"
+    },
+    {
+      "idiom" : "watch",
+      "scale" : "2x",
+      "screen-width" : ">183"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "auto-scaling" : "auto"
+  }
+}

+ 20 - 0
FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "idiom" : "watch",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "watch",
+      "scale" : "2x",
+      "screen-width" : ">183"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "auto-scaling" : "auto"
+  }
+}

+ 20 - 0
FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "idiom" : "watch",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "watch",
+      "scale" : "2x",
+      "screen-width" : ">183"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "auto-scaling" : "auto"
+  }
+}

+ 20 - 0
FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "idiom" : "watch",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "watch",
+      "scale" : "2x",
+      "screen-width" : ">183"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "auto-scaling" : "auto"
+  }
+}

+ 25 - 0
FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json

@@ -0,0 +1,25 @@
+{
+  "images" : [
+    {
+      "idiom" : "watch",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "watch",
+      "scale" : "2x",
+      "screen-width" : "<=145"
+    },
+    {
+      "idiom" : "watch",
+      "scale" : "2x",
+      "screen-width" : ">183"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "auto-scaling" : "auto"
+  }
+}

+ 20 - 0
FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json

@@ -0,0 +1,20 @@
+{
+  "images" : [
+    {
+      "idiom" : "watch",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "watch",
+      "scale" : "2x",
+      "screen-width" : ">183"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "auto-scaling" : "auto"
+  }
+}

+ 25 - 0
FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json

@@ -0,0 +1,25 @@
+{
+  "images" : [
+    {
+      "idiom" : "watch",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "watch",
+      "scale" : "2x",
+      "screen-width" : "<=145"
+    },
+    {
+      "idiom" : "watch",
+      "scale" : "2x",
+      "screen-width" : ">183"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "auto-scaling" : "auto"
+  }
+}

+ 25 - 0
FreeAPSWatch WatchKit Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json

@@ -0,0 +1,25 @@
+{
+  "images" : [
+    {
+      "idiom" : "watch",
+      "scale" : "2x"
+    },
+    {
+      "idiom" : "watch",
+      "scale" : "2x",
+      "screen-width" : "<=145"
+    },
+    {
+      "idiom" : "watch",
+      "scale" : "2x",
+      "screen-width" : ">183"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  },
+  "properties" : {
+    "auto-scaling" : "auto"
+  }
+}

+ 6 - 0
FreeAPSWatch WatchKit Extension/Assets.xcassets/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 59 - 0
FreeAPSWatch WatchKit Extension/ComplicationController.swift

@@ -0,0 +1,59 @@
+import ClockKit
+
+class ComplicationController: NSObject, CLKComplicationDataSource {
+    // MARK: - Complication Configuration
+
+    func getComplicationDescriptors(handler: @escaping ([CLKComplicationDescriptor]) -> Void) {
+        let descriptors = [
+            CLKComplicationDescriptor(
+                identifier: "complication",
+                displayName: "FreeAPS",
+                supportedFamilies: CLKComplicationFamily.allCases
+            )
+            // Multiple complication support can be added here with more descriptors
+        ]
+
+        // Call the handler with the currently supported complication descriptors
+        handler(descriptors)
+    }
+
+    func handleSharedComplicationDescriptors(_: [CLKComplicationDescriptor]) {
+        // Do any necessary work to support these newly shared complication descriptors
+    }
+
+    // MARK: - Timeline Configuration
+
+    func getTimelineEndDate(for _: CLKComplication, withHandler handler: @escaping (Date?) -> Void) {
+        // Call the handler with the last entry date you can currently provide or nil if you can't support future timelines
+        handler(nil)
+    }
+
+    func getPrivacyBehavior(for _: CLKComplication, withHandler handler: @escaping (CLKComplicationPrivacyBehavior) -> Void) {
+        // Call the handler with your desired behavior when the device is locked
+        handler(.showOnLockScreen)
+    }
+
+    // MARK: - Timeline Population
+
+    func getCurrentTimelineEntry(for _: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void) {
+        // Call the handler with the current timeline entry
+        handler(nil)
+    }
+
+    func getTimelineEntries(
+        for _: CLKComplication,
+        after _: Date,
+        limit _: Int,
+        withHandler handler: @escaping ([CLKComplicationTimelineEntry]?) -> Void
+    ) {
+        // Call the handler with the timeline entries after the given date
+        handler(nil)
+    }
+
+    // MARK: - Sample Templates
+
+    func getLocalizableSampleTemplate(for _: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
+        // This method will be called once per supported complication, and the results will be cached
+        handler(nil)
+    }
+}

+ 3 - 0
FreeAPSWatch WatchKit Extension/DataFlow.swift

@@ -0,0 +1,3 @@
+import Foundation
+
+struct Message {}

+ 13 - 0
FreeAPSWatch WatchKit Extension/FreeAPSApp.swift

@@ -0,0 +1,13 @@
+import SwiftUI
+
+@main struct FreeAPSApp: App {
+    @SceneBuilder var body: some Scene {
+        WindowGroup {
+            NavigationView {
+                MainView()
+            }
+        }
+
+        WKNotificationScene(controller: NotificationController.self, category: "myCategory")
+    }
+}

+ 16 - 0
FreeAPSWatch WatchKit Extension/Info.plist

@@ -0,0 +1,16 @@
+<?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>NSExtension</key>
+	<dict>
+		<key>NSExtensionAttributes</key>
+		<dict>
+			<key>WKAppBundleIdentifier</key>
+			<string>ru.artpancreas.FreeAPS.watchkitapp</string>
+		</dict>
+		<key>NSExtensionPointIdentifier</key>
+		<string>com.apple.watchkit</string>
+	</dict>
+</dict>
+</plist>

+ 25 - 0
FreeAPSWatch WatchKit Extension/NotificationController.swift

@@ -0,0 +1,25 @@
+import SwiftUI
+import UserNotifications
+import WatchKit
+
+class NotificationController: WKUserNotificationHostingController<NotificationView> {
+    override var body: NotificationView {
+        NotificationView()
+    }
+
+    override func willActivate() {
+        // This method is called when watch view controller is about to be visible to user
+        super.willActivate()
+    }
+
+    override func didDeactivate() {
+        // This method is called when watch view controller is no longer visible
+        super.didDeactivate()
+    }
+
+    override func didReceive(_: UNNotification) {
+        // This method is called when a notification needs to be presented.
+        // Implement it if you use a dynamic notification interface.
+        // Populate your dynamic notification interface as quickly as possible.
+    }
+}

+ 13 - 0
FreeAPSWatch WatchKit Extension/NotificationView.swift

@@ -0,0 +1,13 @@
+import SwiftUI
+
+struct NotificationView: View {
+    var body: some View {
+        Text("Hello, World!")
+    }
+}
+
+struct NotificationView_Previews: PreviewProvider {
+    static var previews: some View {
+        NotificationView()
+    }
+}

+ 6 - 0
FreeAPSWatch WatchKit Extension/Preview Content/Preview Assets.xcassets/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 20 - 0
FreeAPSWatch WatchKit Extension/PushNotificationPayload.apns

@@ -0,0 +1,20 @@
+{
+    "aps": {
+        "alert": {
+            "body": "Test message",
+            "title": "Optional title",
+            "subtitle": "Optional subtitle"
+        },
+        "category": "myCategory",
+        "thread-id": "5280"
+    },
+    
+    "WatchKit Simulator Actions": [
+        {
+            "title": "First Button",
+            "identifier": "firstButtonAction"
+        }
+    ],
+    
+    "customKey": "Use this file to define a testing payload for your notifications. The aps dictionary specifies the category, alert text and title. The WatchKit Simulator Actions array can provide info for one or more action buttons in addition to the standard Dismiss button. Any other top level keys are custom payload. If you have multiple such JSON files in your project, you'll be able to select them when choosing to debug the notification interface of your Watch App."
+}

+ 69 - 0
FreeAPSWatch WatchKit Extension/Views/CarbsView.swift

@@ -0,0 +1,69 @@
+import SwiftUI
+
+struct CarbsView: View {
+    @EnvironmentObject var state: WatchStateModel
+
+    @State var amount = 0.0
+
+    var numberFormatter: NumberFormatter {
+        let formatter = NumberFormatter()
+        formatter.numberStyle = .decimal
+        formatter.minimum = 0
+        formatter.maximum = 120
+        formatter.maximumFractionDigits = 0
+        formatter.allowsFloats = false
+        return formatter
+    }
+
+    var body: some View {
+        VStack(spacing: 16) {
+            HStack {
+                Button {
+                    let newValue = amount - 5
+                    amount = max(newValue, 0)
+                } label: { Image(systemName: "minus") }
+                    .frame(width: 50)
+                Spacer()
+                Text(numberFormatter.string(from: amount as NSNumber)! + " g")
+                    .font(.title2)
+                    .focusable(true)
+                    .digitalCrownRotation(
+                        $amount,
+                        from: 0,
+                        through: 120,
+                        by: 1,
+                        sensitivity: .medium,
+                        isContinuous: false,
+                        isHapticFeedbackEnabled: true
+                    )
+                Spacer()
+                Button {
+                    let newValue = amount + 5
+                    amount = min(newValue, 120)
+                } label: { Image(systemName: "plus") }
+                    .frame(width: 50)
+            }
+            Button {
+                state.addCarbs(10)
+            }
+            label: {
+                HStack {
+                    Image("carbs", bundle: nil)
+                        .renderingMode(.template)
+                        .resizable()
+                        .frame(width: 24, height: 24)
+                        .foregroundColor(.loopGreen)
+                    Text("Add Carbs")
+                }
+            }
+            .disabled(amount <= 0)
+        }
+        .navigationTitle("Add Carbs")
+    }
+}
+
+struct CarbsView_Previews: PreviewProvider {
+    static var previews: some View {
+        CarbsView().environmentObject(WatchStateModel())
+    }
+}

+ 58 - 0
FreeAPSWatch WatchKit Extension/Views/MainView.swift

@@ -0,0 +1,58 @@
+import SwiftUI
+
+struct MainView: View {
+    @StateObject var state = WatchStateModel()
+
+    @State var isCarbsActive = false
+    @State var isTargetsActive = false
+    @State var isBolusActive = false
+    var body: some View {
+        Form {
+            NavigationLink {
+                CarbsView()
+                    .environmentObject(state)
+            } label: {
+                HStack {
+                    Image("carbs", bundle: nil)
+                        .renderingMode(.template)
+                        .resizable()
+                        .frame(width: 24, height: 24)
+                        .foregroundColor(.loopGreen)
+                    Text("Abb Carbs")
+                }
+            }
+
+            NavigationLink {
+                EmptyView()
+            } label: {
+                HStack {
+                    Image("target", bundle: nil)
+                        .renderingMode(.template)
+                        .resizable()
+                        .frame(width: 24, height: 24)
+                        .foregroundColor(.loopYellow)
+                    Text("Temp Targets").foregroundColor(.primary)
+                }
+            }
+
+            NavigationLink {
+                EmptyView()
+            } label: {
+                HStack {
+                    Image("bolus", bundle: nil)
+                        .renderingMode(.template)
+                        .resizable()
+                        .frame(width: 24, height: 24)
+                        .foregroundColor(.insulin)
+                    Text("Enact Bolus")
+                }
+            }
+        }.padding()
+    }
+}
+
+struct ContentView_Previews: PreviewProvider {
+    static var previews: some View {
+        MainView()
+    }
+}

+ 36 - 0
FreeAPSWatch WatchKit Extension/Views/WatchStateModel.swift

@@ -0,0 +1,36 @@
+import Foundation
+import SwiftUI
+import WatchConnectivity
+
+class WatchStateModel: NSObject, ObservableObject {
+    var session: WCSession
+    @Published var result = ""
+
+    init(session: WCSession = .default) {
+        self.session = session
+        super.init()
+
+        session.delegate = self
+        session.activate()
+    }
+
+    func addCarbs(_ carbs: Int) {
+        session.sendMessage(["addCarbs": carbs], replyHandler: nil) { error in
+            print("ASDF: " + error.localizedDescription)
+        }
+    }
+}
+
+extension WatchStateModel: WCSessionDelegate {
+    func session(_: WCSession, activationDidCompleteWith state: WCSessionActivationState, error _: Error?) {
+        print("ASDF state \(state.rawValue)")
+    }
+
+    func session(_: WCSession, didReceiveMessage message: [String: Any]) {
+        if let text = message["message"] as? String {
+            DispatchQueue.main.async {
+                self.result = text
+            }
+        }
+    }
+}

+ 11 - 0
FreeAPSWatch/Assets.xcassets/AccentColor.colorset/Contents.json

@@ -0,0 +1,11 @@
+{
+  "colors" : [
+    {
+      "idiom" : "universal"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 109 - 0
FreeAPSWatch/Assets.xcassets/AppIcon.appiconset/Contents.json

@@ -0,0 +1,109 @@
+{
+  "images" : [
+    {
+      "idiom" : "watch",
+      "role" : "notificationCenter",
+      "scale" : "2x",
+      "size" : "24x24",
+      "subtype" : "38mm"
+    },
+    {
+      "idiom" : "watch",
+      "role" : "notificationCenter",
+      "scale" : "2x",
+      "size" : "27.5x27.5",
+      "subtype" : "42mm"
+    },
+    {
+      "idiom" : "watch",
+      "role" : "companionSettings",
+      "scale" : "2x",
+      "size" : "29x29"
+    },
+    {
+      "idiom" : "watch",
+      "role" : "companionSettings",
+      "scale" : "3x",
+      "size" : "29x29"
+    },
+    {
+      "idiom" : "watch",
+      "role" : "notificationCenter",
+      "scale" : "2x",
+      "size" : "33x33",
+      "subtype" : "45mm"
+    },
+    {
+      "idiom" : "watch",
+      "role" : "appLauncher",
+      "scale" : "2x",
+      "size" : "40x40",
+      "subtype" : "38mm"
+    },
+    {
+      "idiom" : "watch",
+      "role" : "appLauncher",
+      "scale" : "2x",
+      "size" : "44x44",
+      "subtype" : "40mm"
+    },
+    {
+      "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" : "quickLook",
+      "scale" : "2x",
+      "size" : "86x86",
+      "subtype" : "38mm"
+    },
+    {
+      "idiom" : "watch",
+      "role" : "quickLook",
+      "scale" : "2x",
+      "size" : "98x98",
+      "subtype" : "42mm"
+    },
+    {
+      "idiom" : "watch",
+      "role" : "quickLook",
+      "scale" : "2x",
+      "size" : "108x108",
+      "subtype" : "44mm"
+    },
+    {
+      "idiom" : "watch",
+      "role" : "quickLook",
+      "scale" : "2x",
+      "size" : "117x117",
+      "subtype" : "45mm"
+    },
+    {
+      "idiom" : "watch-marketing",
+      "scale" : "1x",
+      "size" : "1024x1024"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

+ 6 - 0
FreeAPSWatch/Assets.xcassets/Contents.json

@@ -0,0 +1,6 @@
+{
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}