~not/FerryTimetable3

628400f97f257c8a099e8efe94ee163fd8c5f16c — b123400 3 years ago f481700 watch-kit
Basic watch kit app
30 files changed, 1385 insertions(+), 10 deletions(-)

M FerryTimeTable3.xcodeproj/project.pbxproj
M FerryTimeTable3/Core/Model/Timetable.swift
M FerryTimeTable3/Core/ModelManager.swift
M FerryTimeTable3/DetailViewController.swift
A Watch App WatchKit App/Assets.xcassets/AccentColor.colorset/Contents.json
A Watch App WatchKit App/Assets.xcassets/AppIcon.appiconset/Contents.json
A Watch App WatchKit App/Assets.xcassets/Contents.json
A Watch App WatchKit App/Base.lproj/Interface.storyboard
A Watch App WatchKit App/Info.plist
A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json
A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Contents.json
A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json
A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json
A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json
A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json
A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json
A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json
A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json
A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json
A Watch App WatchKit Extension/Assets.xcassets/Contents.json
A Watch App WatchKit Extension/ComplicationController.swift
A Watch App WatchKit Extension/DetailInterfaceController.swift
A Watch App WatchKit Extension/ExtensionDelegate.swift
A Watch App WatchKit Extension/FerryDateRow.swift
A Watch App WatchKit Extension/Info.plist
A Watch App WatchKit Extension/InterfaceController.swift
A Watch App WatchKit Extension/IslandTableRow.swift
A Watch App WatchKit Extension/NotificationController.swift
A Watch App WatchKit Extension/PushNotificationPayload.apns
A WatchApp/Base.lproj/Interface.storyboard
M FerryTimeTable3.xcodeproj/project.pbxproj => FerryTimeTable3.xcodeproj/project.pbxproj +414 -1
@@ 10,11 10,22 @@
		2591E34C087E3064794BC894 /* Pods_FerryTimetable3_FerryTimetable3UITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E6698103004970AB6AC217F5 /* Pods_FerryTimetable3_FerryTimetable3UITests.framework */; };
		432CEF209522394D98AC8A09 /* Pods_FerryTimetable3Tests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 317E4EC52F99BAA92F729BD5 /* Pods_FerryTimetable3Tests.framework */; };
		9B01E7F38944B31B915AB281 /* Pods_Ferry_widget.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 651A9080258F8BFFA627DE18 /* Pods_Ferry_widget.framework */; };
		CF0C8EFC264955CA00E4E135 /* FerryDateRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF0C8EFB264955CA00E4E135 /* FerryDateRow.swift */; };
		CF0C8EFD2649581E00E4E135 /* raws.json in Resources */ = {isa = PBXBuildFile; fileRef = CF547F8224C339F9007DCF39 /* raws.json */; };
		CF0C8F00264958C300E4E135 /* holidays.json in Resources */ = {isa = PBXBuildFile; fileRef = CFADD6BF24D878D500473F8D /* holidays.json */; };
		CF0C8F01264958C300E4E135 /* metadatas.json in Resources */ = {isa = PBXBuildFile; fileRef = CFA05449256B90CF00351CE3 /* metadatas.json */; };
		CF0FF14124CAEE5300CB9676 /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CF0FF14024CAEE5300CB9676 /* NotificationCenter.framework */; };
		CF0FF14424CAEE5300CB9676 /* TodayViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF0FF14324CAEE5300CB9676 /* TodayViewController.swift */; };
		CF0FF14724CAEE5300CB9676 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CF0FF14524CAEE5300CB9676 /* MainInterface.storyboard */; };
		CF0FF14B24CAEE5300CB9676 /* Ferry Timetable.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = CF0FF13E24CAEE5300CB9676 /* Ferry Timetable.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
		CF1341A026492207005373BC /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = CF13419F26492207005373BC /* Alamofire */; };
		CF1E4A4324ACDC9300D98F41 /* LeftAlignedCollectionViewFlowLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF1E4A4224ACDC9300D98F41 /* LeftAlignedCollectionViewFlowLayout.swift */; };
		CF411D6F2649202900797601 /* Metadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFA0543C256AD89400351CE3 /* Metadata.swift */; };
		CF411D702649202900797601 /* Json.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFEF2C1324CADCCE00DA70A4 /* Json.swift */; };
		CF411D712649202900797601 /* ModelManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF8CABCC24ACFD4700E7FCB4 /* ModelManager.swift */; };
		CF411D722649202900797601 /* Holiday.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFADD6BC24D875E900473F8D /* Holiday.swift */; };
		CF411D732649202900797601 /* Schedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF547F8424C33C46007DCF39 /* Schedule.swift */; };
		CF411D742649202900797601 /* Timetable.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF6B6EEC24AF1A9600C18FD2 /* Timetable.swift */; };
		CF547F8324C339F9007DCF39 /* raws.json in Resources */ = {isa = PBXBuildFile; fileRef = CF547F8224C339F9007DCF39 /* raws.json */; };
		CF547F8524C33C46007DCF39 /* Schedule.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF547F8424C33C46007DCF39 /* Schedule.swift */; };
		CF547F8824C359A0007DCF39 /* MenuCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CF547F8724C359A0007DCF39 /* MenuCell.swift */; };


@@ 54,6 65,17 @@
		CFB5806A24AB7AE200DC3C63 /* FerryTimetable3Tests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFB5806924AB7AE200DC3C63 /* FerryTimetable3Tests.swift */; };
		CFB5807524AB7AE200DC3C63 /* FerryTimetable3UITests.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFB5807424AB7AE200DC3C63 /* FerryTimetable3UITests.swift */; };
		CFB5808324AB884F00DC3C63 /* MenuCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFB5808224AB884F00DC3C63 /* MenuCollectionViewCell.swift */; };
		CFC58A572649096600FAEBAD /* Watch App WatchKit App.app in Embed Watch Content */ = {isa = PBXBuildFile; fileRef = CFC58A562649096600FAEBAD /* Watch App WatchKit App.app */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
		CFC58A5D2649096600FAEBAD /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CFC58A5B2649096600FAEBAD /* Interface.storyboard */; };
		CFC58A5F2649096700FAEBAD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CFC58A5E2649096700FAEBAD /* Assets.xcassets */; };
		CFC58A662649096700FAEBAD /* Watch App WatchKit Extension.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = CFC58A652649096700FAEBAD /* Watch App WatchKit Extension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; };
		CFC58A6B2649096800FAEBAD /* InterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFC58A6A2649096800FAEBAD /* InterfaceController.swift */; };
		CFC58A6D2649096800FAEBAD /* ExtensionDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFC58A6C2649096800FAEBAD /* ExtensionDelegate.swift */; };
		CFC58A6F2649096800FAEBAD /* NotificationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFC58A6E2649096800FAEBAD /* NotificationController.swift */; };
		CFC58A712649096800FAEBAD /* ComplicationController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFC58A702649096800FAEBAD /* ComplicationController.swift */; };
		CFC58A732649096800FAEBAD /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CFC58A722649096800FAEBAD /* Assets.xcassets */; };
		CFC58A8226490BC500FAEBAD /* IslandTableRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFC58A8126490BC500FAEBAD /* IslandTableRow.swift */; };
		CFC58A8426490FDB00FAEBAD /* DetailInterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CFC58A8326490FDB00FAEBAD /* DetailInterfaceController.swift */; };
		CFC73E6024D8336E00CA4F41 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CFC73E5E24D8336E00CA4F41 /* Localizable.strings */; };
		CFC73E6324D8336E00CA4F41 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CFC73E6124D8336E00CA4F41 /* Localizable.strings */; };
		CFC73E6624D8369B00CA4F41 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = CFC73E6424D8369B00CA4F41 /* InfoPlist.strings */; };


@@ 92,6 114,20 @@
			remoteGlobalIDString = CFB5804C24AB7AE000DC3C63;
			remoteInfo = FerryTimetable3;
		};
		CFC58A582649096600FAEBAD /* PBXContainerItemProxy */ = {
			isa = PBXContainerItemProxy;
			containerPortal = CFB5804524AB7AE000DC3C63 /* Project object */;
			proxyType = 1;
			remoteGlobalIDString = CFC58A552649096600FAEBAD;
			remoteInfo = "Watch App WatchKit App";
		};
		CFC58A672649096700FAEBAD /* PBXContainerItemProxy */ = {
			isa = PBXContainerItemProxy;
			containerPortal = CFB5804524AB7AE000DC3C63 /* Project object */;
			proxyType = 1;
			remoteGlobalIDString = CFC58A642649096700FAEBAD;
			remoteInfo = "Watch App WatchKit Extension";
		};
/* End PBXContainerItemProxy section */

/* Begin PBXCopyFilesBuildPhase section */


@@ 106,6 142,28 @@
			name = "Embed App Extensions";
			runOnlyForDeploymentPostprocessing = 0;
		};
		CFC58A782649096800FAEBAD /* Embed Watch Content */ = {
			isa = PBXCopyFilesBuildPhase;
			buildActionMask = 2147483647;
			dstPath = "$(CONTENTS_FOLDER_PATH)/Watch";
			dstSubfolderSpec = 16;
			files = (
				CFC58A572649096600FAEBAD /* Watch App WatchKit App.app in Embed Watch Content */,
			);
			name = "Embed Watch Content";
			runOnlyForDeploymentPostprocessing = 0;
		};
		CFC58A7B2649096800FAEBAD /* Embed App Extensions */ = {
			isa = PBXCopyFilesBuildPhase;
			buildActionMask = 2147483647;
			dstPath = "";
			dstSubfolderSpec = 13;
			files = (
				CFC58A662649096700FAEBAD /* Watch App WatchKit Extension.appex in Embed App Extensions */,
			);
			name = "Embed App Extensions";
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXCopyFilesBuildPhase section */

/* Begin PBXFileReference section */


@@ 119,6 177,7 @@
		85654B12E7EC603666BFC3D5 /* Pods-FerryTimetable3-FerryTimetable3UITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FerryTimetable3-FerryTimetable3UITests.debug.xcconfig"; path = "Target Support Files/Pods-FerryTimetable3-FerryTimetable3UITests/Pods-FerryTimetable3-FerryTimetable3UITests.debug.xcconfig"; sourceTree = "<group>"; };
		A5945BE56A9DE1E51BB46169 /* Pods-FerryTimetable3.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FerryTimetable3.debug.xcconfig"; path = "Target Support Files/Pods-FerryTimetable3/Pods-FerryTimetable3.debug.xcconfig"; sourceTree = "<group>"; };
		BFD56B463AE99EE32B831115 /* Pods-FerryTimetable3Tests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-FerryTimetable3Tests.release.xcconfig"; path = "Target Support Files/Pods-FerryTimetable3Tests/Pods-FerryTimetable3Tests.release.xcconfig"; sourceTree = "<group>"; };
		CF0C8EFB264955CA00E4E135 /* FerryDateRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FerryDateRow.swift; sourceTree = "<group>"; };
		CF0FF13E24CAEE5300CB9676 /* Ferry Timetable.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Ferry Timetable.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
		CF0FF14024CAEE5300CB9676 /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; };
		CF0FF14324CAEE5300CB9676 /* TodayViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TodayViewController.swift; sourceTree = "<group>"; };


@@ 158,6 217,21 @@
		CFB5807424AB7AE200DC3C63 /* FerryTimetable3UITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FerryTimetable3UITests.swift; sourceTree = "<group>"; };
		CFB5807624AB7AE200DC3C63 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
		CFB5808224AB884F00DC3C63 /* MenuCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MenuCollectionViewCell.swift; sourceTree = "<group>"; };
		CFC58A532649096600FAEBAD /* Watch App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Watch App.app"; sourceTree = BUILT_PRODUCTS_DIR; };
		CFC58A562649096600FAEBAD /* Watch App WatchKit App.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Watch App WatchKit App.app"; sourceTree = BUILT_PRODUCTS_DIR; };
		CFC58A5C2649096600FAEBAD /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Interface.storyboard; sourceTree = "<group>"; };
		CFC58A5E2649096700FAEBAD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
		CFC58A602649096700FAEBAD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
		CFC58A652649096700FAEBAD /* Watch App WatchKit Extension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Watch App WatchKit Extension.appex"; sourceTree = BUILT_PRODUCTS_DIR; };
		CFC58A6A2649096800FAEBAD /* InterfaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InterfaceController.swift; sourceTree = "<group>"; };
		CFC58A6C2649096800FAEBAD /* ExtensionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionDelegate.swift; sourceTree = "<group>"; };
		CFC58A6E2649096800FAEBAD /* NotificationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationController.swift; sourceTree = "<group>"; };
		CFC58A702649096800FAEBAD /* ComplicationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplicationController.swift; sourceTree = "<group>"; };
		CFC58A722649096800FAEBAD /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
		CFC58A742649096800FAEBAD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
		CFC58A752649096800FAEBAD /* PushNotificationPayload.apns */ = {isa = PBXFileReference; lastKnownFileType = text; path = PushNotificationPayload.apns; sourceTree = "<group>"; };
		CFC58A8126490BC500FAEBAD /* IslandTableRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IslandTableRow.swift; sourceTree = "<group>"; };
		CFC58A8326490FDB00FAEBAD /* DetailInterfaceController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DetailInterfaceController.swift; sourceTree = "<group>"; };
		CFC73E5824D8308700CA4F41 /* zh-HK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-HK"; path = "zh-HK.lproj/Main.strings"; sourceTree = "<group>"; };
		CFC73E5924D8308700CA4F41 /* zh-HK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-HK"; path = "zh-HK.lproj/LaunchScreen.strings"; sourceTree = "<group>"; };
		CFC73E5A24D8308700CA4F41 /* zh-HK */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = "zh-HK"; path = "zh-HK.lproj/MainInterface.strings"; sourceTree = "<group>"; };


@@ 185,6 259,20 @@
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
		0A65C3A53EC4A66CE9C2B125 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		261369AB6940810678F76F50 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		CF0FF13B24CAEE5300CB9676 /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;


@@ 222,6 310,14 @@
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		CFC58A622649096700FAEBAD /* Frameworks */ = {
			isa = PBXFrameworksBuildPhase;
			buildActionMask = 2147483647;
			files = (
				CF1341A026492207005373BC /* Alamofire in Frameworks */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */


@@ 303,6 399,8 @@
				CFB5806824AB7AE200DC3C63 /* FerryTimetable3Tests */,
				CFB5807324AB7AE200DC3C63 /* FerryTimetable3UITests */,
				CF0FF14224CAEE5300CB9676 /* Ferry widget */,
				CFC58A5A2649096600FAEBAD /* Watch App WatchKit App */,
				CFC58A692649096800FAEBAD /* Watch App WatchKit Extension */,
				CF0FF13F24CAEE5300CB9676 /* Frameworks */,
				CFB5804E24AB7AE000DC3C63 /* Products */,
				99FA93FC9DAE8A8D35C1EAC9 /* Pods */,


@@ 316,6 414,9 @@
				CFB5806524AB7AE200DC3C63 /* FerryTimetable3Tests.xctest */,
				CFB5807024AB7AE200DC3C63 /* FerryTimetable3UITests.xctest */,
				CF0FF13E24CAEE5300CB9676 /* Ferry Timetable.appex */,
				CFC58A532649096600FAEBAD /* Watch App.app */,
				CFC58A562649096600FAEBAD /* Watch App WatchKit App.app */,
				CFC58A652649096700FAEBAD /* Watch App WatchKit Extension.appex */,
			);
			name = Products;
			sourceTree = "<group>";


@@ 383,6 484,33 @@
			path = "UI Components";
			sourceTree = "<group>";
		};
		CFC58A5A2649096600FAEBAD /* Watch App WatchKit App */ = {
			isa = PBXGroup;
			children = (
				CFC58A5B2649096600FAEBAD /* Interface.storyboard */,
				CFC58A5E2649096700FAEBAD /* Assets.xcassets */,
				CFC58A602649096700FAEBAD /* Info.plist */,
			);
			path = "Watch App WatchKit App";
			sourceTree = "<group>";
		};
		CFC58A692649096800FAEBAD /* Watch App WatchKit Extension */ = {
			isa = PBXGroup;
			children = (
				CFC58A6A2649096800FAEBAD /* InterfaceController.swift */,
				CFC58A6C2649096800FAEBAD /* ExtensionDelegate.swift */,
				CFC58A6E2649096800FAEBAD /* NotificationController.swift */,
				CFC58A702649096800FAEBAD /* ComplicationController.swift */,
				CFC58A8126490BC500FAEBAD /* IslandTableRow.swift */,
				CFC58A8326490FDB00FAEBAD /* DetailInterfaceController.swift */,
				CF0C8EFB264955CA00E4E135 /* FerryDateRow.swift */,
				CFC58A722649096800FAEBAD /* Assets.xcassets */,
				CFC58A742649096800FAEBAD /* Info.plist */,
				CFC58A752649096800FAEBAD /* PushNotificationPayload.apns */,
			);
			path = "Watch App WatchKit Extension";
			sourceTree = "<group>";
		};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */


@@ 472,13 600,69 @@
			productReference = CFB5807024AB7AE200DC3C63 /* FerryTimetable3UITests.xctest */;
			productType = "com.apple.product-type.bundle.ui-testing";
		};
		CFC58A522649096600FAEBAD /* Watch App */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = CFC58A802649096800FAEBAD /* Build configuration list for PBXNativeTarget "Watch App" */;
			buildPhases = (
				CFC58A512649096600FAEBAD /* Resources */,
				CFC58A782649096800FAEBAD /* Embed Watch Content */,
				261369AB6940810678F76F50 /* Frameworks */,
			);
			buildRules = (
			);
			dependencies = (
				CFC58A592649096600FAEBAD /* PBXTargetDependency */,
			);
			name = "Watch App";
			productName = "Watch App";
			productReference = CFC58A532649096600FAEBAD /* Watch App.app */;
			productType = "com.apple.product-type.application.watchapp2-container";
		};
		CFC58A552649096600FAEBAD /* Watch App WatchKit App */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = CFC58A7F2649096800FAEBAD /* Build configuration list for PBXNativeTarget "Watch App WatchKit App" */;
			buildPhases = (
				CFC58A542649096600FAEBAD /* Resources */,
				CFC58A7B2649096800FAEBAD /* Embed App Extensions */,
				0A65C3A53EC4A66CE9C2B125 /* Frameworks */,
			);
			buildRules = (
			);
			dependencies = (
				CFC58A682649096700FAEBAD /* PBXTargetDependency */,
			);
			name = "Watch App WatchKit App";
			productName = "Watch App WatchKit App";
			productReference = CFC58A562649096600FAEBAD /* Watch App WatchKit App.app */;
			productType = "com.apple.product-type.application.watchapp2";
		};
		CFC58A642649096700FAEBAD /* Watch App WatchKit Extension */ = {
			isa = PBXNativeTarget;
			buildConfigurationList = CFC58A7E2649096800FAEBAD /* Build configuration list for PBXNativeTarget "Watch App WatchKit Extension" */;
			buildPhases = (
				CFC58A612649096700FAEBAD /* Sources */,
				CFC58A622649096700FAEBAD /* Frameworks */,
				CFC58A632649096700FAEBAD /* Resources */,
			);
			buildRules = (
			);
			dependencies = (
			);
			name = "Watch App WatchKit Extension";
			packageProductDependencies = (
				CF13419F26492207005373BC /* Alamofire */,
			);
			productName = "Watch App WatchKit Extension";
			productReference = CFC58A652649096700FAEBAD /* Watch App WatchKit Extension.appex */;
			productType = "com.apple.product-type.watchkit2-extension";
		};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
		CFB5804524AB7AE000DC3C63 /* Project object */ = {
			isa = PBXProject;
			attributes = {
				LastSwiftUpdateCheck = 1160;
				LastSwiftUpdateCheck = 1250;
				LastUpgradeCheck = 1130;
				ORGANIZATIONNAME = b123400;
				TargetAttributes = {


@@ 496,6 680,15 @@
						CreatedOnToolsVersion = 11.3.1;
						TestTargetID = CFB5804C24AB7AE000DC3C63;
					};
					CFC58A522649096600FAEBAD = {
						CreatedOnToolsVersion = 12.5;
					};
					CFC58A552649096600FAEBAD = {
						CreatedOnToolsVersion = 12.5;
					};
					CFC58A642649096700FAEBAD = {
						CreatedOnToolsVersion = 12.5;
					};
				};
			};
			buildConfigurationList = CFB5804824AB7AE000DC3C63 /* Build configuration list for PBXProject "FerryTimetable3" */;


@@ 521,6 714,9 @@
				CFB5806424AB7AE200DC3C63 /* FerryTimetable3Tests */,
				CFB5806F24AB7AE200DC3C63 /* FerryTimetable3UITests */,
				CF0FF13D24CAEE5300CB9676 /* Ferry widget */,
				CFC58A522649096600FAEBAD /* Watch App */,
				CFC58A552649096600FAEBAD /* Watch App WatchKit App */,
				CFC58A642649096700FAEBAD /* Watch App WatchKit Extension */,
			);
		};
/* End PBXProject section */


@@ 567,6 763,33 @@
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		CFC58A512649096600FAEBAD /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		CFC58A542649096600FAEBAD /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				CFC58A5F2649096700FAEBAD /* Assets.xcassets in Resources */,
				CFC58A5D2649096600FAEBAD /* Interface.storyboard in Resources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		CFC58A632649096700FAEBAD /* Resources */ = {
			isa = PBXResourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				CF0C8F00264958C300E4E135 /* holidays.json in Resources */,
				CF0C8F01264958C300E4E135 /* metadatas.json in Resources */,
				CF0C8EFD2649581E00E4E135 /* raws.json in Resources */,
				CFC58A732649096800FAEBAD /* Assets.xcassets in Resources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXResourcesBuildPhase section */

/* Begin PBXShellScriptBuildPhase section */


@@ 761,6 984,26 @@
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
		CFC58A612649096700FAEBAD /* Sources */ = {
			isa = PBXSourcesBuildPhase;
			buildActionMask = 2147483647;
			files = (
				CF411D6F2649202900797601 /* Metadata.swift in Sources */,
				CF0C8EFC264955CA00E4E135 /* FerryDateRow.swift in Sources */,
				CFC58A8426490FDB00FAEBAD /* DetailInterfaceController.swift in Sources */,
				CF411D732649202900797601 /* Schedule.swift in Sources */,
				CFC58A8226490BC500FAEBAD /* IslandTableRow.swift in Sources */,
				CFC58A6F2649096800FAEBAD /* NotificationController.swift in Sources */,
				CF411D742649202900797601 /* Timetable.swift in Sources */,
				CFC58A712649096800FAEBAD /* ComplicationController.swift in Sources */,
				CF411D712649202900797601 /* ModelManager.swift in Sources */,
				CF411D722649202900797601 /* Holiday.swift in Sources */,
				CFC58A6D2649096800FAEBAD /* ExtensionDelegate.swift in Sources */,
				CFC58A6B2649096800FAEBAD /* InterfaceController.swift in Sources */,
				CF411D702649202900797601 /* Json.swift in Sources */,
			);
			runOnlyForDeploymentPostprocessing = 0;
		};
/* End PBXSourcesBuildPhase section */

/* Begin PBXTargetDependency section */


@@ 779,6 1022,16 @@
			target = CFB5804C24AB7AE000DC3C63 /* FerryTimetable3 */;
			targetProxy = CFB5807124AB7AE200DC3C63 /* PBXContainerItemProxy */;
		};
		CFC58A592649096600FAEBAD /* PBXTargetDependency */ = {
			isa = PBXTargetDependency;
			target = CFC58A552649096600FAEBAD /* Watch App WatchKit App */;
			targetProxy = CFC58A582649096600FAEBAD /* PBXContainerItemProxy */;
		};
		CFC58A682649096700FAEBAD /* PBXTargetDependency */ = {
			isa = PBXTargetDependency;
			target = CFC58A642649096700FAEBAD /* Watch App WatchKit Extension */;
			targetProxy = CFC58A672649096700FAEBAD /* PBXContainerItemProxy */;
		};
/* End PBXTargetDependency section */

/* Begin PBXVariantGroup section */


@@ 812,6 1065,14 @@
			name = LaunchScreen.storyboard;
			sourceTree = "<group>";
		};
		CFC58A5B2649096600FAEBAD /* Interface.storyboard */ = {
			isa = PBXVariantGroup;
			children = (
				CFC58A5C2649096600FAEBAD /* Base */,
			);
			name = Interface.storyboard;
			sourceTree = "<group>";
		};
		CFC73E5E24D8336E00CA4F41 /* Localizable.strings */ = {
			isa = PBXVariantGroup;
			children = (


@@ 1150,6 1411,126 @@
			};
			name = Release;
		};
		CFC58A762649096800FAEBAD /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
				CODE_SIGN_STYLE = Automatic;
				CURRENT_PROJECT_VERSION = 1;
				DEVELOPMENT_TEAM = CC63FD9H8S;
				MARKETING_VERSION = 3.3.0;
				PRODUCT_BUNDLE_IDENTIFIER = "net.b123400.ferriestimetable.Watch-App";
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_VERSION = 5.0;
			};
			name = Debug;
		};
		CFC58A772649096800FAEBAD /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
				CODE_SIGN_STYLE = Automatic;
				CURRENT_PROJECT_VERSION = 1;
				DEVELOPMENT_TEAM = CC63FD9H8S;
				MARKETING_VERSION = 3.3.0;
				PRODUCT_BUNDLE_IDENTIFIER = "net.b123400.ferriestimetable.Watch-App";
				PRODUCT_NAME = "$(TARGET_NAME)";
				SWIFT_VERSION = 5.0;
			};
			name = Release;
		};
		CFC58A792649096800FAEBAD /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
				CODE_SIGN_STYLE = Automatic;
				DEVELOPMENT_TEAM = CC63FD9H8S;
				IBSC_MODULE = Watch_App_WatchKit_Extension;
				INFOPLIST_FILE = "Watch App WatchKit App/Info.plist";
				MARKETING_VERSION = 3.3.0;
				PRODUCT_BUNDLE_IDENTIFIER = "net.b123400.ferriestimetable.Watch-App.watchkitapp";
				PRODUCT_NAME = "$(TARGET_NAME)";
				SDKROOT = watchos;
				SKIP_INSTALL = YES;
				SWIFT_VERSION = 5.0;
				TARGETED_DEVICE_FAMILY = 4;
				WATCHOS_DEPLOYMENT_TARGET = 7.4;
			};
			name = Debug;
		};
		CFC58A7A2649096800FAEBAD /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
				ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
				ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
				CODE_SIGN_STYLE = Automatic;
				DEVELOPMENT_TEAM = CC63FD9H8S;
				IBSC_MODULE = Watch_App_WatchKit_Extension;
				INFOPLIST_FILE = "Watch App WatchKit App/Info.plist";
				MARKETING_VERSION = 3.3.0;
				PRODUCT_BUNDLE_IDENTIFIER = "net.b123400.ferriestimetable.Watch-App.watchkitapp";
				PRODUCT_NAME = "$(TARGET_NAME)";
				SDKROOT = watchos;
				SKIP_INSTALL = YES;
				SWIFT_VERSION = 5.0;
				TARGETED_DEVICE_FAMILY = 4;
				WATCHOS_DEPLOYMENT_TARGET = 7.4;
			};
			name = Release;
		};
		CFC58A7C2649096800FAEBAD /* Debug */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication;
				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
				CODE_SIGN_STYLE = Automatic;
				DEVELOPMENT_TEAM = CC63FD9H8S;
				INFOPLIST_FILE = "Watch App WatchKit Extension/Info.plist";
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/Frameworks",
					"@executable_path/../../Frameworks",
				);
				MARKETING_VERSION = 3.3.0;
				PRODUCT_BUNDLE_IDENTIFIER = "net.b123400.ferriestimetable.Watch-App.watchkitapp.watchkitextension";
				PRODUCT_NAME = "${TARGET_NAME}";
				SDKROOT = watchos;
				SKIP_INSTALL = YES;
				SWIFT_VERSION = 5.0;
				TARGETED_DEVICE_FAMILY = 4;
				WATCHOS_DEPLOYMENT_TARGET = 7.4;
			};
			name = Debug;
		};
		CFC58A7D2649096800FAEBAD /* Release */ = {
			isa = XCBuildConfiguration;
			buildSettings = {
				ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication;
				CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
				CODE_SIGN_STYLE = Automatic;
				DEVELOPMENT_TEAM = CC63FD9H8S;
				INFOPLIST_FILE = "Watch App WatchKit Extension/Info.plist";
				LD_RUNPATH_SEARCH_PATHS = (
					"$(inherited)",
					"@executable_path/Frameworks",
					"@executable_path/../../Frameworks",
				);
				MARKETING_VERSION = 3.3.0;
				PRODUCT_BUNDLE_IDENTIFIER = "net.b123400.ferriestimetable.Watch-App.watchkitapp.watchkitextension";
				PRODUCT_NAME = "${TARGET_NAME}";
				SDKROOT = watchos;
				SKIP_INSTALL = YES;
				SWIFT_VERSION = 5.0;
				TARGETED_DEVICE_FAMILY = 4;
				WATCHOS_DEPLOYMENT_TARGET = 7.4;
			};
			name = Release;
		};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */


@@ 1198,6 1579,33 @@
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		CFC58A7E2649096800FAEBAD /* Build configuration list for PBXNativeTarget "Watch App WatchKit Extension" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				CFC58A7C2649096800FAEBAD /* Debug */,
				CFC58A7D2649096800FAEBAD /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		CFC58A7F2649096800FAEBAD /* Build configuration list for PBXNativeTarget "Watch App WatchKit App" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				CFC58A792649096800FAEBAD /* Debug */,
				CFC58A7A2649096800FAEBAD /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
		CFC58A802649096800FAEBAD /* Build configuration list for PBXNativeTarget "Watch App" */ = {
			isa = XCConfigurationList;
			buildConfigurations = (
				CFC58A762649096800FAEBAD /* Debug */,
				CFC58A772649096800FAEBAD /* Release */,
			);
			defaultConfigurationIsVisible = 0;
			defaultConfigurationName = Release;
		};
/* End XCConfigurationList section */

/* Begin XCRemoteSwiftPackageReference section */


@@ 1220,6 1628,11 @@
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
		CF13419F26492207005373BC /* Alamofire */ = {
			isa = XCSwiftPackageProductDependency;
			package = CF9C10EE24AE58F8001D13EC /* XCRemoteSwiftPackageReference "Alamofire" */;
			productName = Alamofire;
		};
		CF5A5AD924CAFBE200DDF6BB /* Alamofire */ = {
			isa = XCSwiftPackageProductDependency;
			package = CF9C10EE24AE58F8001D13EC /* XCRemoteSwiftPackageReference "Alamofire" */;

M FerryTimeTable3/Core/Model/Timetable.swift => FerryTimeTable3/Core/Model/Timetable.swift +31 -6
@@ 155,13 155,25 @@ struct Ferry<T> {
    
    var color: UIColor {
        if modifiers.contains(.optionalFerry) {
            return .systemYellow
            #if os(watchOS)
                return .yellow
            #else
                return .systemYellow
            #endif
        }
        if modifiers.contains(.fastFerry) {
            return UIColor.systemRed
            #if os(watchOS)
                return .red
            #else
                return UIColor.systemRed
            #endif
        }
        if modifiers.contains(.slowFerry) {
            return UIColor.systemGreen
            #if os(watchOS)
                return .green
            #else
                return UIColor.systemGreen
            #endif
        }
        return .clear
    }


@@ 171,6 183,10 @@ extension Ferry: Codable where T: Codable {}
extension Timetable: Codable where T: Codable {}
extension Route: Codable where T: Codable {}

func haveSpeedDifference<T>(ferries: [Ferry<T>]) -> Bool {
    return ferries.first?.modifiers.contains { [.fastFerry, .slowFerry, .optionalFerry].contains($0) } ?? false
}

enum Modifier: String, Codable, Equatable {
    case fastFerry = "FastFerry"
    case slowFerry = "SlowFerry"


@@ 191,20 207,29 @@ enum Modifier: String, Codable, Equatable {
    }
    
    func toAttributedString() -> NSAttributedString {
        #if os(watchOS)
            let red = UIColor.red
            let green = UIColor.green
            let yellow = UIColor.yellow
        #else
            let red = UIColor.systemRed
            let green = UIColor.systemGreen
            let yellow = UIColor.systemYellow
        #endif
        switch self {
        case .fastFerry:
            return NSAttributedString(string: self.toString(),
                                      attributes: [.backgroundColor : UIColor.systemRed,
                                      attributes: [.backgroundColor : red,
                                                   .foregroundColor: UIColor.white
                                      ])
        case .slowFerry:
            return NSAttributedString(string: self.toString(),
                                      attributes: [.backgroundColor : UIColor.systemGreen,
                                      attributes: [.backgroundColor : green,
                                                   .foregroundColor: UIColor.white
                                      ])
        case .optionalFerry:
            return NSAttributedString(string: self.toString(),
                                      attributes: [.backgroundColor : UIColor.systemYellow,
                                      attributes: [.backgroundColor : yellow,
                                                   .foregroundColor: UIColor.white
                                      ])
        case .freight:

M FerryTimeTable3/Core/ModelManager.swift => FerryTimeTable3/Core/ModelManager.swift +2 -2
@@ 156,7 156,7 @@ class ModelManager {
    func saveRaws() -> AnyPublisher<[Route<TimeInterval>], Error> {
        fetchRaws()
            .mapError { $0 }
            .flatMap { routes in
            .flatMap { (routes: [Route<TimeInterval>]) -> Future<[Route<TimeInterval>], Error> in
                Future { promise in
                    self._raws = routes
                    NotificationCenter.default.post(Notification(name: .timetableUpdated))


@@ 226,7 226,7 @@ class ModelManager {
    func saveMetadatas() -> AnyPublisher<[Island: Metadata], Error> {
        fetchMetadatas()
            .mapError({ $0 })
            .flatMap { metadatas in
            .flatMap { (metadatas: [Island: Metadata]) -> Future<[Island: Metadata], Error> in
                Future { promise in
                    self._metadata = metadatas
                    NotificationCenter.default.post(Notification(name: .metadataUpdated))

M FerryTimeTable3/DetailViewController.swift => FerryTimeTable3/DetailViewController.swift +1 -1
@@ 172,7 172,7 @@ class DetailViewController:
    }
    
    func shouldShowTypeHintFor(ferries: [Ferry<Date>]) -> Bool {
        let routeHasSpeedDifference = ferries.first?.modifiers.contains { [.fastFerry, .slowFerry, .optionalFerry].contains($0) } ?? false
        let routeHasSpeedDifference = haveSpeedDifference(ferries: ferries)
        if !routeHasSpeedDifference {
            return false
        }

A Watch App WatchKit App/Assets.xcassets/AccentColor.colorset/Contents.json => Watch App WatchKit App/Assets.xcassets/AccentColor.colorset/Contents.json +11 -0
@@ 0,0 1,11 @@
{
  "colors" : [
    {
      "idiom" : "universal"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A Watch App WatchKit App/Assets.xcassets/AppIcon.appiconset/Contents.json => Watch App WatchKit App/Assets.xcassets/AppIcon.appiconset/Contents.json +81 -0
@@ 0,0 1,81 @@
{
  "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" : "appLauncher",
      "scale" : "2x",
      "size" : "40x40",
      "subtype" : "38mm"
    },
    {
      "idiom" : "watch",
      "role" : "appLauncher",
      "scale" : "2x",
      "size" : "44x44",
      "subtype" : "40mm"
    },
    {
      "idiom" : "watch",
      "role" : "appLauncher",
      "scale" : "2x",
      "size" : "50x50",
      "subtype" : "44mm"
    },
    {
      "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-marketing",
      "scale" : "1x",
      "size" : "1024x1024"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A Watch App WatchKit App/Assets.xcassets/Contents.json => Watch App WatchKit App/Assets.xcassets/Contents.json +6 -0
@@ 0,0 1,6 @@
{
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A Watch App WatchKit App/Base.lproj/Interface.storyboard => Watch App WatchKit App/Base.lproj/Interface.storyboard +138 -0
@@ 0,0 1,138 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="18122" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="AgC-eL-Hgc">
    <device id="watch38"/>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="18022"/>
        <capability name="Named colors" minToolsVersion="9.0"/>
    </dependencies>
    <scenes>
        <!--Routes-->
        <scene sceneID="aou-V4-d1y">
            <objects>
                <controller title="Routes" id="AgC-eL-Hgc" customClass="InterfaceController" customModule="Watch_App_WatchKit_App" customModuleProvider="target">
                    <items>
                        <table alignment="left" id="eSo-mi-LWW">
                            <items>
                                <tableRow identifier="IslandTableRow" id="88r-F4-MdF" customClass="IslandTableRow" customModule="Watch_App_WatchKit_Extension">
                                    <group key="rootItem" width="1" alignment="left" id="PGV-ek-gak">
                                        <items>
                                            <label alignment="left" verticalAlignment="center" text="Label" numberOfLines="0" id="taI-xh-WJQ"/>
                                        </items>
                                    </group>
                                    <connections>
                                        <outlet property="nameLabel" destination="taI-xh-WJQ" id="MXx-Ep-wUY"/>
                                        <segue destination="E46-cO-Fji" kind="modal" identifier="detail" id="DOo-bZ-1jz"/>
                                    </connections>
                                </tableRow>
                            </items>
                        </table>
                    </items>
                    <connections>
                        <outlet property="islandsTable" destination="eSo-mi-LWW" id="203-fz-BUq"/>
                    </connections>
                </controller>
            </objects>
            <point key="canvasLocation" x="142" y="971"/>
        </scene>
        <!--From ...-->
        <scene sceneID="uni-ol-x4e">
            <objects>
                <controller title="From ..." alwaysBounce="YES" id="E46-cO-Fji" customClass="DetailInterfaceController" customModule="Watch_App_WatchKit_Extension">
                    <items>
                        <table alignment="left" id="2GP-fk-AgU">
                            <items>
                                <tableRow identifier="FerryDateRow" id="khQ-JH-cdN" customClass="FerryDateRow" customModule="Watch_App_WatchKit_Extension">
                                    <group key="rootItem" width="1" alignment="left" id="2ZB-A2-AXc">
                                        <items>
                                            <label alignment="left" verticalAlignment="center" text="Label" id="6gB-wJ-o0D"/>
                                            <group width="10" height="10" alignment="right" verticalAlignment="center" radius="5" spacing="0.0" id="JGy-aU-TAl">
                                                <color key="backgroundColor" name="AccentColor"/>
                                            </group>
                                        </items>
                                    </group>
                                    <connections>
                                        <outlet property="colourDot" destination="JGy-aU-TAl" id="WB7-N8-Dgk"/>
                                        <outlet property="timeLabel" destination="6gB-wJ-o0D" id="S1a-Iu-89v"/>
                                    </connections>
                                </tableRow>
                            </items>
                        </table>
                    </items>
                    <connections>
                        <outlet property="tableView" destination="2GP-fk-AgU" id="TvR-H7-RcV"/>
                        <segue destination="tkj-H9-oM0" kind="relationship" relationship="nextPage" id="Hsp-nN-pdv"/>
                    </connections>
                </controller>
            </objects>
            <point key="canvasLocation" x="488" y="971"/>
        </scene>
        <!--To ...-->
        <scene sceneID="y1a-Wc-6tp">
            <objects>
                <controller title="To ..." id="tkj-H9-oM0" customClass="DetailInterfaceController" customModule="Watch_App_WatchKit_Extension">
                    <items>
                        <table alignment="left" id="d0j-j7-lE9">
                            <items>
                                <tableRow identifier="FerryDateRow" id="1RL-oe-KQb" customClass="FerryDateRow" customModule="Watch_App_WatchKit_Extension">
                                    <group key="rootItem" width="1" alignment="left" id="3yk-5f-z96">
                                        <items>
                                            <label alignment="left" verticalAlignment="center" text="Label" id="rWu-Jd-0P9"/>
                                            <group width="10" height="10" alignment="right" verticalAlignment="center" radius="5" spacing="0.0" id="ncs-NV-MBP">
                                                <color key="backgroundColor" name="AccentColor"/>
                                            </group>
                                        </items>
                                    </group>
                                    <connections>
                                        <outlet property="colourDot" destination="ncs-NV-MBP" id="Dtm-n0-UIP"/>
                                        <outlet property="timeLabel" destination="rWu-Jd-0P9" id="k6l-ka-0aN"/>
                                    </connections>
                                </tableRow>
                            </items>
                        </table>
                    </items>
                    <connections>
                        <outlet property="tableView" destination="d0j-j7-lE9" id="Zej-DV-OzV"/>
                    </connections>
                </controller>
            </objects>
            <point key="canvasLocation" x="796" y="971"/>
        </scene>
        <!--Static Notification Interface Controller-->
        <scene sceneID="AEw-b0-oYE">
            <objects>
                <notificationController id="YCC-NB-fut">
                    <items>
                        <label alignment="left" text="Alert Label" numberOfLines="0" id="IdU-wH-bcW"/>
                    </items>
                    <notificationCategory key="notificationCategory" identifier="myCategory" id="JfB-70-Muf"/>
                    <connections>
                        <outlet property="notificationAlertLabel" destination="IdU-wH-bcW" id="JKC-fr-R95"/>
                        <segue destination="4sK-HA-Art" kind="relationship" relationship="dynamicNotificationInterface" id="kXh-Jw-8B1"/>
                        <segue destination="eXb-UN-Cd0" kind="relationship" relationship="dynamicInteractiveNotificationInterface" id="mpB-YA-K8N"/>
                    </connections>
                </notificationController>
            </objects>
            <point key="canvasLocation" x="157" y="479"/>
        </scene>
        <!--Notification Controller-->
        <scene sceneID="ZPc-GJ-vnh">
            <objects>
                <controller id="4sK-HA-Art" customClass="NotificationController" customModule="Watch_App_WatchKit_App" customModuleProvider="target"/>
            </objects>
            <point key="canvasLocation" x="468" y="643"/>
        </scene>
        <!--Notification Controller-->
        <scene sceneID="Niz-AI-uX2">
            <objects>
                <controller id="eXb-UN-Cd0" customClass="NotificationController" customModule="Watch_App_WatchKit_App" customModuleProvider="target"/>
            </objects>
            <point key="canvasLocation" x="468" y="345"/>
        </scene>
    </scenes>
    <resources>
        <namedColor name="AccentColor">
            <color red="0.0" green="0.46000000000000002" blue="0.89000000000000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
        </namedColor>
    </resources>
</document>

A Watch App WatchKit App/Info.plist => Watch App WatchKit App/Info.plist +31 -0
@@ 0,0 1,31 @@
<?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>CFBundleDevelopmentRegion</key>
	<string>$(DEVELOPMENT_LANGUAGE)</string>
	<key>CFBundleDisplayName</key>
	<string>Watch App WatchKit App</string>
	<key>CFBundleExecutable</key>
	<string>$(EXECUTABLE_NAME)</string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>$(PRODUCT_NAME)</string>
	<key>CFBundlePackageType</key>
	<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
	<key>CFBundleShortVersionString</key>
	<string>$(MARKETING_VERSION)</string>
	<key>CFBundleVersion</key>
	<string>1</string>
	<key>UISupportedInterfaceOrientations</key>
	<array>
		<string>UIInterfaceOrientationPortrait</string>
		<string>UIInterfaceOrientationPortraitUpsideDown</string>
	</array>
	<key>WKWatchKitApp</key>
	<true/>
</dict>
</plist>

A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json => Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json +28 -0
@@ 0,0 1,28 @@
{
  "images" : [
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : "<=145"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">161"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">145"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">183"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Contents.json => Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Contents.json +53 -0
@@ 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
  }
}

A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json => Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json +28 -0
@@ 0,0 1,28 @@
{
  "images" : [
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : "<=145"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">161"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">145"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">183"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json => Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json +18 -0
@@ 0,0 1,18 @@
{
  "images" : [
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">161"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">183"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json => Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json +18 -0
@@ 0,0 1,18 @@
{
  "images" : [
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">161"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">183"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json => Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json +18 -0
@@ 0,0 1,18 @@
{
  "images" : [
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">161"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">183"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json => Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json +28 -0
@@ 0,0 1,28 @@
{
  "images" : [
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : "<=145"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">161"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">145"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">183"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json => Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json +18 -0
@@ 0,0 1,18 @@
{
  "images" : [
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">161"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">183"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json => Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json +28 -0
@@ 0,0 1,28 @@
{
  "images" : [
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : "<=145"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">161"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">145"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">183"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json => Watch App WatchKit Extension/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json +28 -0
@@ 0,0 1,28 @@
{
  "images" : [
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : "<=145"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">161"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">145"
    },
    {
      "idiom" : "watch",
      "scale" : "2x",
      "screen-width" : ">183"
    }
  ],
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A Watch App WatchKit Extension/Assets.xcassets/Contents.json => Watch App WatchKit Extension/Assets.xcassets/Contents.json +6 -0
@@ 0,0 1,6 @@
{
  "info" : {
    "author" : "xcode",
    "version" : 1
  }
}

A Watch App WatchKit Extension/ComplicationController.swift => Watch App WatchKit Extension/ComplicationController.swift +60 -0
@@ 0,0 1,60 @@
//
//  ComplicationController.swift
//  Watch App WatchKit Extension
//
//  Created by b123400 on 2021/05/10.
//  Copyright © 2021 b123400. All rights reserved.
//

import ClockKit


class ComplicationController: NSObject, CLKComplicationDataSource {
    
    // MARK: - Complication Configuration

    func getComplicationDescriptors(handler: @escaping ([CLKComplicationDescriptor]) -> Void) {
        let descriptors = [
            CLKComplicationDescriptor(identifier: "complication", displayName: "FerryTimetable3", 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(_ complicationDescriptors: [CLKComplicationDescriptor]) {
        // Do any necessary work to support these newly shared complication descriptors
    }

    // MARK: - Timeline Configuration
    
    func getTimelineEndDate(for complication: 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 complication: 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 complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTimelineEntry?) -> Void) {
        // Call the handler with the current timeline entry
        handler(nil)
    }
    
    func getTimelineEntries(for complication: CLKComplication, after date: 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 complication: CLKComplication, withHandler handler: @escaping (CLKComplicationTemplate?) -> Void) {
        // This method will be called once per supported complication, and the results will be cached
        handler(nil)
    }
}

A Watch App WatchKit Extension/DetailInterfaceController.swift => Watch App WatchKit Extension/DetailInterfaceController.swift +49 -0
@@ 0,0 1,49 @@
//
//  DetailInterfaceController.swift
//  Watch App WatchKit Extension
//
//  Created by b123400 on 2021/05/10.
//  Copyright © 2021 b123400. All rights reserved.
//

import WatchKit
import Foundation

class DetailInterfaceController: WKInterfaceController {
    
    public struct Context {
        let direction: Direction
        let island: Island
    }
    
    @IBOutlet weak var tableView: WKInterfaceTable!
    
    let schedule = Schedule(raws: ModelManager.shared.getRaws())

    override func awake(withContext context: Any?) {
        guard let c = context as? Context else { return }
        switch (c.direction) {
        case .fromPrimary:
            self.setTitle(String(format: NSLocalizedString("To %@", comment: ""), c.island.secondaryName))
        case .toPrimary:
            self.setTitle(String(format: NSLocalizedString("From %@", comment: ""), c.island.secondaryName))
        }
        
        let formatter = DateFormatter()
        formatter.dateStyle = .none
        formatter.timeStyle = .short
        let ferries = schedule.upcomingFerries(island: c.island, direction: c.direction, count: 20)
        tableView.setNumberOfRows(ferries.count, withRowType: "FerryDateRow")
        let haveSpeedDiff = haveSpeedDifference(ferries: ferries)
        for i in 0..<ferries.count {
            let row = tableView.rowController(at: i) as! FerryDateRow
            let ferry = ferries[i]
            row.timeLabel.setText(formatter.string(from: ferry.time))
            if (haveSpeedDiff) {
                row.colourDot.setBackgroundColor(ferry.color)
            } else {
                row.colourDot.setBackgroundColor(.clear)
            }
        }
    }
}

A Watch App WatchKit Extension/ExtensionDelegate.swift => Watch App WatchKit Extension/ExtensionDelegate.swift +56 -0
@@ 0,0 1,56 @@
//
//  ExtensionDelegate.swift
//  Watch App WatchKit Extension
//
//  Created by b123400 on 2021/05/10.
//  Copyright © 2021 b123400. All rights reserved.
//

import WatchKit

class ExtensionDelegate: NSObject, WKExtensionDelegate {

    func applicationDidFinishLaunching() {
        // Perform any final initialization of your application.
    }

    func applicationDidBecomeActive() {
        // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
    }

    func applicationWillResignActive() {
        // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
        // Use this method to pause ongoing tasks, disable timers, etc.
    }

    func handle(_ backgroundTasks: Set<WKRefreshBackgroundTask>) {
        // Sent when the system needs to launch the application in the background to process tasks. Tasks arrive in a set, so loop through and process each one.
        for task in backgroundTasks {
            // Use a switch statement to check the task type
            switch task {
            case let backgroundTask as WKApplicationRefreshBackgroundTask:
                // Be sure to complete the background task once you’re done.
                backgroundTask.setTaskCompletedWithSnapshot(false)
            case let snapshotTask as WKSnapshotRefreshBackgroundTask:
                // Snapshot tasks have a unique completion call, make sure to set your expiration date
                snapshotTask.setTaskCompleted(restoredDefaultState: true, estimatedSnapshotExpiration: Date.distantFuture, userInfo: nil)
            case let connectivityTask as WKWatchConnectivityRefreshBackgroundTask:
                // Be sure to complete the connectivity task once you’re done.
                connectivityTask.setTaskCompletedWithSnapshot(false)
            case let urlSessionTask as WKURLSessionRefreshBackgroundTask:
                // Be sure to complete the URL session task once you’re done.
                urlSessionTask.setTaskCompletedWithSnapshot(false)
            case let relevantShortcutTask as WKRelevantShortcutRefreshBackgroundTask:
                // Be sure to complete the relevant-shortcut task once you're done.
                relevantShortcutTask.setTaskCompletedWithSnapshot(false)
            case let intentDidRunTask as WKIntentDidRunRefreshBackgroundTask:
                // Be sure to complete the intent-did-run task once you're done.
                intentDidRunTask.setTaskCompletedWithSnapshot(false)
            default:
                // make sure to complete unhandled task types
                task.setTaskCompletedWithSnapshot(false)
            }
        }
    }

}

A Watch App WatchKit Extension/FerryDateRow.swift => Watch App WatchKit Extension/FerryDateRow.swift +14 -0
@@ 0,0 1,14 @@
//
//  FerryDateRow.swift
//  Watch App WatchKit Extension
//
//  Created by b123400 on 2021/05/10.
//  Copyright © 2021 b123400. All rights reserved.
//

import WatchKit

class FerryDateRow: NSObject {
    @IBOutlet weak var timeLabel: WKInterfaceLabel!
    @IBOutlet weak var colourDot: WKInterfaceGroup!
}

A Watch App WatchKit Extension/Info.plist => Watch App WatchKit Extension/Info.plist +40 -0
@@ 0,0 1,40 @@
<?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>CFBundleDevelopmentRegion</key>
	<string>$(DEVELOPMENT_LANGUAGE)</string>
	<key>CFBundleDisplayName</key>
	<string>Watch App WatchKit Extension</string>
	<key>CFBundleExecutable</key>
	<string>$(EXECUTABLE_NAME)</string>
	<key>CFBundleIdentifier</key>
	<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>$(PRODUCT_NAME)</string>
	<key>CFBundlePackageType</key>
	<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
	<key>CFBundleShortVersionString</key>
	<string>$(MARKETING_VERSION)</string>
	<key>CFBundleVersion</key>
	<string>1</string>
	<key>CLKComplicationPrincipalClass</key>
	<string>$(PRODUCT_MODULE_NAME).ComplicationController</string>
	<key>NSExtension</key>
	<dict>
		<key>NSExtensionAttributes</key>
		<dict>
			<key>WKAppBundleIdentifier</key>
			<string>net.b123400.ferriestimetable.Watch-App.watchkitapp</string>
		</dict>
		<key>NSExtensionPointIdentifier</key>
		<string>com.apple.watchkit</string>
	</dict>
	<key>WKExtensionDelegateClassName</key>
	<string>$(PRODUCT_MODULE_NAME).ExtensionDelegate</string>
	<key>WKWatchOnly</key>
	<true/>
</dict>
</plist>

A Watch App WatchKit Extension/InterfaceController.swift => Watch App WatchKit Extension/InterfaceController.swift +46 -0
@@ 0,0 1,46 @@
//
//  InterfaceController.swift
//  Watch App WatchKit Extension
//
//  Created by b123400 on 2021/05/10.
//  Copyright © 2021 b123400. All rights reserved.
//

import WatchKit
import Foundation


class InterfaceController: WKInterfaceController {
    @IBOutlet weak var islandsTable: WKInterfaceTable!
    
    override func awake(withContext context: Any?) {
        // Configure interface objects here.
        islandsTable.setNumberOfRows(Island.allCases.count, withRowType: "IslandTableRow")
        for i in 0..<Island.allCases.count {
            let island = Island.allCases[i]
            let row = self.islandsTable.rowController(at: i) as! IslandTableRow
            row.nameLabel.setText(island.fullName)
        }
    }
    
    override func table(_ table: WKInterfaceTable, didSelectRowAt rowIndex: Int) {
        islandsTable.performSegue(forRow: rowIndex)
    }
    
    override func contextsForSegue(withIdentifier segueIdentifier: String, in table: WKInterfaceTable, rowIndex: Int) -> [Any]? {
        let island = Island.allCases[rowIndex]
        return [
            DetailInterfaceController.Context(direction: .fromPrimary, island: island),
            DetailInterfaceController.Context(direction: .toPrimary, island: island)
        ]
    }
    
    override func willActivate() {
        // This method is called when watch view controller is about to be visible to user
    }
    
    override func didDeactivate() {
        // This method is called when watch view controller is no longer visible
    }

}

A Watch App WatchKit Extension/IslandTableRow.swift => Watch App WatchKit Extension/IslandTableRow.swift +14 -0
@@ 0,0 1,14 @@
//
//  IslandTableRow.swift
//  Watch App WatchKit Extension
//
//  Created by b123400 on 2021/05/10.
//  Copyright © 2021 b123400. All rights reserved.
//

import WatchKit

class IslandTableRow: NSObject {
    
    @IBOutlet weak var nameLabel: WKInterfaceLabel!
}

A Watch App WatchKit Extension/NotificationController.swift => Watch App WatchKit Extension/NotificationController.swift +35 -0
@@ 0,0 1,35 @@
//
//  NotificationController.swift
//  Watch App WatchKit Extension
//
//  Created by b123400 on 2021/05/10.
//  Copyright © 2021 b123400. All rights reserved.
//

import WatchKit
import Foundation
import UserNotifications

class NotificationController: WKUserNotificationInterfaceController {

    override init() {
        // Initialize variables here.
        super.init()
        
        // Configure interface objects here.
    }

    override func willActivate() {
        // This method is called when watch view controller is about to be visible to user
    }

    override func didDeactivate() {
        // This method is called when watch view controller is no longer visible
    }

    override func didReceive(_ notification: 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.
    }
}

A Watch App WatchKit Extension/PushNotificationPayload.apns => Watch App WatchKit Extension/PushNotificationPayload.apns +20 -0
@@ 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."
}

A WatchApp/Base.lproj/Interface.storyboard => WatchApp/Base.lproj/Interface.storyboard +65 -0
@@ 0,0 1,65 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder.WatchKit.Storyboard" version="3.0" toolsVersion="18122" targetRuntime="watchKit" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="AgC-eL-Hgc">
    <device id="watch38"/>
    <dependencies>
        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
        <plugIn identifier="com.apple.InterfaceBuilder.IBWatchKitPlugin" version="18022"/>
    </dependencies>
    <scenes>
        <!--Interface Controller-->
        <scene sceneID="aou-V4-d1y">
            <objects>
                <controller id="AgC-eL-Hgc" customClass="InterfaceController" customModule="WatchApp" customModuleProvider="target">
                    <items>
                        <table alignment="left" id="aOt-vk-4g3">
                            <items>
                                <tableRow id="xCF-hu-mnT">
                                    <group key="rootItem" width="1" alignment="left" id="k4T-C0-u9L">
                                        <items>
                                            <label alignment="left" text="Label" id="CVm-Md-abg"/>
                                        </items>
                                    </group>
                                </tableRow>
                            </items>
                        </table>
                    </items>
                    <connections>
                        <outlet property="islandsTable" destination="aOt-vk-4g3" id="71b-lW-NLx"/>
                    </connections>
                </controller>
            </objects>
            <point key="canvasLocation" x="220" y="963"/>
        </scene>
        <!--Static Notification Interface Controller-->
        <scene sceneID="AEw-b0-oYE">
            <objects>
                <notificationController id="YCC-NB-fut">
                    <items>
                        <label alignment="left" text="Alert Label" numberOfLines="0" id="IdU-wH-bcW"/>
                    </items>
                    <notificationCategory key="notificationCategory" identifier="myCategory" id="JfB-70-Muf"/>
                    <connections>
                        <outlet property="notificationAlertLabel" destination="IdU-wH-bcW" id="JKC-fr-R95"/>
                        <segue destination="4sK-HA-Art" kind="relationship" relationship="dynamicNotificationInterface" id="kXh-Jw-8B1"/>
                        <segue destination="eXb-UN-Cd0" kind="relationship" relationship="dynamicInteractiveNotificationInterface" id="mpB-YA-K8N"/>
                    </connections>
                </notificationController>
            </objects>
            <point key="canvasLocation" x="220" y="643"/>
        </scene>
        <!--Notification Controller-->
        <scene sceneID="ZPc-GJ-vnh">
            <objects>
                <controller id="4sK-HA-Art" customClass="NotificationController" customModule="WatchApp" customModuleProvider="target"/>
            </objects>
            <point key="canvasLocation" x="468" y="643"/>
        </scene>
        <!--Notification Controller-->
        <scene sceneID="Niz-AI-uX2">
            <objects>
                <controller id="eXb-UN-Cd0" customClass="NotificationController" customModule="WatchApp" customModuleProvider="target"/>
            </objects>
            <point key="canvasLocation" x="468" y="345"/>
        </scene>
    </scenes>
</document>