diff --git a/HomeAssistant.xcodeproj/project.pbxproj b/HomeAssistant.xcodeproj/project.pbxproj index 8fc8bdcd4b..54613a43a5 100644 --- a/HomeAssistant.xcodeproj/project.pbxproj +++ b/HomeAssistant.xcodeproj/project.pbxproj @@ -243,7 +243,6 @@ 119385A7249E9F930097F497 /* StorageSensor.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 119385A6249E9F930097F497 /* StorageSensor.test.swift */; }; 11948E8924DA5D50006F5657 /* InfoLabelRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11948E8824DA5D50006F5657 /* InfoLabelRow.swift */; }; 1194B4162519BEE900AA01C3 /* MacBridgeNetworkConnectivityImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1194B4152519BEE900AA01C3 /* MacBridgeNetworkConnectivityImpl.swift */; }; - 119A172524D74DA800D1B66D /* HomeAssistant-WatchExtension-Watch.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = B6CC5D8E2159D10E00833E5D /* HomeAssistant-WatchExtension-Watch.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 119A7DF32529761800D7000D /* CLKComplication+Strings.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B6B14B215B1E86003DE2DD /* CLKComplication+Strings.swift */; }; 119A7E0E2529769A00D7000D /* UIImageView+UIActivityIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DF8BC0221C890600370A59 /* UIImageView+UIActivityIndicator.swift */; }; 119A7E0F2529769A00D7000D /* UIImageView+UIActivityIndicator.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DF8BC0221C890600370A59 /* UIImageView+UIActivityIndicator.swift */; }; @@ -480,10 +479,10 @@ 165955E006864CFE23355451 /* Pods_Tests_App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 57B9C3C07B5A002D749B5CDA /* Pods_Tests_App.framework */; }; 177E4B39B7BA296CCB68A27D /* Pods-iOS-Extensions-Widgets-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = 6723A4E97E50C3C9141428D0 /* Pods-iOS-Extensions-Widgets-metadata.plist */; }; 1A0BF50187A921289B3BA4AE /* Pods-Tests-App-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = B67C3F1DA02199833DA64AF8 /* Pods-Tests-App-metadata.plist */; }; + 1A1A813D0F64A988BBEE9BFD /* Pods_watchOS_WatchApp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B7A6C547EAAD9AF86D273FE0 /* Pods_watchOS_WatchApp.framework */; }; 20226C5AB77E1229852ADDC8 /* Pods_iOS_Extensions_Widgets.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D27653D385E4CEB58E52A350 /* Pods_iOS_Extensions_Widgets.framework */; }; 237993F7E11DC585E29EDC7C /* Pods-iOS-Extensions-NotificationService-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = 592EED7A6C2444872F11C17B /* Pods-iOS-Extensions-NotificationService-metadata.plist */; }; 2F50FC61669812D485E608EC /* Pods-iOS-Extensions-PushProvider-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = E3D5CF14402325076CA105EB /* Pods-iOS-Extensions-PushProvider-metadata.plist */; }; - 368048FC64829A4E4B82B631 /* Pods_watchOS_WatchExtension_Watch.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A90DD8FC6E4726B7E7187C59 /* Pods_watchOS_WatchExtension_Watch.framework */; }; 38A4EBA18ADEEE555AD14F52 /* Pods-iOS-App-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = 553A33E097387AA44265DB13 /* Pods-iOS-App-metadata.plist */; }; 3997926A2B7F904A00231B54 /* MobileAppConfigPushCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 399792692B7F904A00231B54 /* MobileAppConfigPushCategory.swift */; }; 3997926B2B7F904A00231B54 /* MobileAppConfigPushCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = 399792692B7F904A00231B54 /* MobileAppConfigPushCategory.swift */; }; @@ -884,7 +883,6 @@ 42C101302CD3DC0C0012BA78 /* ControlCoverValueProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C1012F2CD3DC0C0012BA78 /* ControlCoverValueProvider.swift */; }; 42C131D02D66084C00AF48E6 /* PillView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C131CF2D66084C00AF48E6 /* PillView.swift */; }; 42C3737F2BC415AC00898990 /* UIViewController+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C3737E2BC415AC00898990 /* UIViewController+Extensions.swift */; }; - 42C373B22BC5382900898990 /* HostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42C373B12BC5382900898990 /* HostingController.swift */; }; 42CB330D2DAE4FD800491DCE /* ServerSelectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42CB330C2DAE4FD800491DCE /* ServerSelectView.swift */; }; 42CB330F2DAE530400491DCE /* SettingsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42CB330E2DAE530400491DCE /* SettingsButton.swift */; }; 42CE8FA72B45D1E900C707F9 /* CoreStrings.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42CE8FA52B45D1E900C707F9 /* CoreStrings.swift */; }; @@ -920,6 +918,7 @@ 42D5ACDB2C64C82600D9C4E2 /* MagicItemAddViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42D5ACDA2C64C82600D9C4E2 /* MagicItemAddViewModel.swift */; }; 42D996E52D89863A001737A0 /* Bool+HA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42D996E42D89863A001737A0 /* Bool+HA.swift */; }; 42D996E62D89863A001737A0 /* Bool+HA.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42D996E42D89863A001737A0 /* Bool+HA.swift */; }; + 42DA945D2E37D01400D57D00 /* WatchMain.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42DA945C2E37D01400D57D00 /* WatchMain.swift */; }; 42DB4D0B2CEE292D00F6C20D /* AppEntitiesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4297ADA42C89C43F00790812 /* AppEntitiesModel.swift */; }; 42DB4D0C2CEE292D00F6C20D /* AppEntitiesModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4297ADA42C89C43F00790812 /* AppEntitiesModel.swift */; }; 42DC44332E1C06E5001046C1 /* WebRTC in Frameworks */ = {isa = PBXBuildFile; productRef = 42DC44322E1C06E5001046C1 /* WebRTC */; }; @@ -975,6 +974,7 @@ 42F1DA6D2B4ED29C002729BC /* CarPlayPaginatedListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42F1DA6C2B4ED29C002729BC /* CarPlayPaginatedListTemplate.swift */; }; 42F3E1492E1D22B400F4E6FC /* HATextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42F3E1482E1D22B400F4E6FC /* HATextField.swift */; }; 42F3E14A2E1D22B400F4E6FC /* HATextField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42F3E1482E1D22B400F4E6FC /* HATextField.swift */; }; + 42F44E102E37BAB500C597CB /* WatchHostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42F44E0F2E37BAB500C597CB /* WatchHostingController.swift */; }; 42F5CAE52B10CDC600409816 /* HACornerRadius.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42CA28AD2B101D4D0093B31A /* HACornerRadius.swift */; }; 42F5CAE72B10CDC900409816 /* CardView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42CA28AF2B101D6B0093B31A /* CardView.swift */; }; 42F5CAE82B10CDC900409816 /* HAButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42CA28B52B1022680093B31A /* HAButton.swift */; }; @@ -1031,6 +1031,7 @@ 539AA1653F4BCDB61FE7C696 /* Pods_iOS_Shared_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 213EF66D14F92AF8BF2E9E98 /* Pods_iOS_Shared_iOS.framework */; }; 5B715903CB3450FE351399BC /* Pods-iOS-Extensions-Share-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = 207E35C8F1554A9AD616FFA2 /* Pods-iOS-Extensions-Share-metadata.plist */; }; 5FFBC80F835393915C4748CF /* Pods_iOS_Extensions_PushProvider.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A370326321B07E5ACE0BCB65 /* Pods_iOS_Extensions_PushProvider.framework */; }; + 60E18AF064002291A5359166 /* Pods-watchOS-WatchApp-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4F613C4C29293CED6B9EB533 /* Pods-watchOS-WatchApp-metadata.plist */; }; 65286F3B745551AD4090EE6B /* Pods-iOS-SharedTesting-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4053903E4C54A6803204286E /* Pods-iOS-SharedTesting-metadata.plist */; }; 78BE7D5D003D9F8C7486DD69 /* Pods_iOS_Shared_iOS_Tests_Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3F4DFB087A3A43F9A526B851 /* Pods_iOS_Shared_iOS_Tests_Shared.framework */; }; 81A0C1BBDEFF4F8C5FC314BE /* Pods_iOS_Extensions_NotificationContent.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1F356D0219C7F8A24234511B /* Pods_iOS_Extensions_NotificationContent.framework */; }; @@ -1389,13 +1390,6 @@ remoteGlobalIDString = D03D891620E0A85200D4F28D; remoteInfo = "Shared-iOS"; }; - 119A172624D74DA800D1B66D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = B657A8DE1CA646EB00121384 /* Project object */; - proxyType = 1; - remoteGlobalIDString = B6CC5D8D2159D10E00833E5D; - remoteInfo = WatchAppExtension; - }; 11A31C92252128B900D50A78 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = B657A8DE1CA646EB00121384 /* Project object */; @@ -1438,6 +1432,13 @@ remoteGlobalIDString = 11DE9D8225B6103C0081C0ED; remoteInfo = Launcher; }; + 42F44E112E37BF1400C597CB /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = B657A8DE1CA646EB00121384 /* Project object */; + proxyType = 1; + remoteGlobalIDString = B67CE82322200D420034C1D0; + remoteInfo = "Shared-watchOS"; + }; 4697F4C32D8A416400C5C467 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = B657A8DE1CA646EB00121384 /* Project object */; @@ -1480,13 +1481,6 @@ remoteGlobalIDString = B66C58A4215086F0004AB261; remoteInfo = Intents; }; - B67CE82922200D420034C1D0 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = B657A8DE1CA646EB00121384 /* Project object */; - proxyType = 1; - remoteGlobalIDString = B67CE82322200D420034C1D0; - remoteInfo = "Shared-watchOS"; - }; B6AAD7A61D827DD40090B220 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = B657A8DE1CA646EB00121384 /* Project object */; @@ -1536,17 +1530,6 @@ name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; - 119A172824D74DA800D1B66D /* Embed App Extensions */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 13; - files = ( - 119A172524D74DA800D1B66D /* HomeAssistant-WatchExtension-Watch.appex in Embed App Extensions */, - ); - name = "Embed App Extensions"; - runOnlyForDeploymentPostprocessing = 0; - }; 11A31CA1252128C200D50A78 /* Embed Plugins */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -1625,6 +1608,7 @@ 0194775556E59C6E64735937 /* Pods-watchOS-Shared-watchOS.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-watchOS-Shared-watchOS.release.xcconfig"; path = "Pods/Target Support Files/Pods-watchOS-Shared-watchOS/Pods-watchOS-Shared-watchOS.release.xcconfig"; sourceTree = ""; }; 05C398FF0F9BA764B69CA36B /* Pods-iOS-Extensions-NotificationService.beta.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-Extensions-NotificationService.beta.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-Extensions-NotificationService/Pods-iOS-Extensions-NotificationService.beta.xcconfig"; sourceTree = ""; }; 05E6CF2BD91E8443547F3026 /* Pods-iOS-Extensions-Today.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-Extensions-Today.release.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-Extensions-Today/Pods-iOS-Extensions-Today.release.xcconfig"; sourceTree = ""; }; + 08F833C0E119C39117BE760A /* Pods-watchOS-WatchApp.beta.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-watchOS-WatchApp.beta.xcconfig"; path = "Pods/Target Support Files/Pods-watchOS-WatchApp/Pods-watchOS-WatchApp.beta.xcconfig"; sourceTree = ""; }; 0AC45831AE5C9F83C5B6269D /* Pods-iOS-Extensions-Share.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-Extensions-Share.debug.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-Extensions-Share/Pods-iOS-Extensions-Share.debug.xcconfig"; sourceTree = ""; }; 1100D51C2496AECE00B1073C /* PermissionStatusRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PermissionStatusRow.swift; sourceTree = ""; }; 1100D51E2496F63400B1073C /* ThemeColors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeColors.swift; sourceTree = ""; }; @@ -2360,7 +2344,6 @@ 42C131CF2D66084C00AF48E6 /* PillView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillView.swift; sourceTree = ""; }; 42C3737E2BC415AC00898990 /* UIViewController+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIViewController+Extensions.swift"; sourceTree = ""; }; 42C373AF2BC536AA00898990 /* WatchApp-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "WatchApp-Bridging-Header.h"; sourceTree = ""; }; - 42C373B12BC5382900898990 /* HostingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HostingController.swift; sourceTree = ""; }; 42CA28AD2B101D4D0093B31A /* HACornerRadius.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HACornerRadius.swift; sourceTree = ""; }; 42CA28AF2B101D6B0093B31A /* CardView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CardView.swift; sourceTree = ""; }; 42CA28B52B1022680093B31A /* HAButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HAButton.swift; sourceTree = ""; }; @@ -2386,6 +2369,7 @@ 42D5ACD82C64C0E000D9C4E2 /* MagicItemAddView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MagicItemAddView.swift; sourceTree = ""; }; 42D5ACDA2C64C82600D9C4E2 /* MagicItemAddViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MagicItemAddViewModel.swift; sourceTree = ""; }; 42D996E42D89863A001737A0 /* Bool+HA.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Bool+HA.swift"; sourceTree = ""; }; + 42DA945C2E37D01400D57D00 /* WatchMain.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchMain.swift; sourceTree = ""; }; 42DC44342E1C0791001046C1 /* WebRTCVideoPlayerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRTCVideoPlayerView.swift; sourceTree = ""; }; 42DC44352E1C0791001046C1 /* WebRTCVideoPlayerViewControls.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebRTCVideoPlayerViewControls.swift; sourceTree = ""; }; 42DC8B772E14027000D9999E /* SearchingServersAnimationView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchingServersAnimationView.swift; sourceTree = ""; }; @@ -2439,6 +2423,7 @@ 42F1DA6F2B4EE2E8002729BC /* HAAreaResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HAAreaResponse.swift; sourceTree = ""; }; 42F1DA732B4FF9F8002729BC /* MaterialDesignIcons+CarPlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MaterialDesignIcons+CarPlay.swift"; sourceTree = ""; }; 42F3E1482E1D22B400F4E6FC /* HATextField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HATextField.swift; sourceTree = ""; }; + 42F44E0F2E37BAB500C597CB /* WatchHostingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchHostingController.swift; sourceTree = ""; }; 42F5CABB2B10AE1A00409816 /* ServerFixture.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerFixture.swift; sourceTree = ""; }; 42F73F552E259A0900B704A9 /* BaseSensorUpdateSignaler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseSensorUpdateSignaler.swift; sourceTree = ""; }; 42F73F592E264A9D00B704A9 /* WebViewControllerButtons.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WebViewControllerButtons.swift; sourceTree = ""; }; @@ -2481,6 +2466,7 @@ 46F103252D721504002BC586 /* LocationHistoryListViewSnapshot.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LocationHistoryListViewSnapshot.test.swift; sourceTree = ""; }; 479C2CCB032E2A0ECDE45B87 /* Pods-Tests-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Tests-App/Pods-Tests-App.debug.xcconfig"; sourceTree = ""; }; 491E98FE25D543560077BBE3 /* LogbookEntry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogbookEntry.swift; sourceTree = ""; }; + 4F613C4C29293CED6B9EB533 /* Pods-watchOS-WatchApp-metadata.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "Pods-watchOS-WatchApp-metadata.plist"; path = "Pods/Pods-watchOS-WatchApp-metadata.plist"; sourceTree = ""; }; 553A33E097387AA44265DB13 /* Pods-iOS-App-metadata.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "Pods-iOS-App-metadata.plist"; path = "Pods/Pods-iOS-App-metadata.plist"; sourceTree = ""; }; 574F428FD5AD613411644AE4 /* Pods-iOS-Extensions-PushProvider.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-Extensions-PushProvider.release.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-Extensions-PushProvider/Pods-iOS-Extensions-PushProvider.release.xcconfig"; sourceTree = ""; }; 57B9C3C07B5A002D749B5CDA /* Pods_Tests_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Tests_App.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -2508,10 +2494,10 @@ 9C7970E308CFEAEAFA05E004 /* Pods-iOS-Extensions-NotificationContent.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-Extensions-NotificationContent.release.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-Extensions-NotificationContent/Pods-iOS-Extensions-NotificationContent.release.xcconfig"; sourceTree = ""; }; A0CE1C12B4ACF0A6876B6F7F /* Pods-iOS-Extensions-Today.beta.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-Extensions-Today.beta.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-Extensions-Today/Pods-iOS-Extensions-Today.beta.xcconfig"; sourceTree = ""; }; A370326321B07E5ACE0BCB65 /* Pods_iOS_Extensions_PushProvider.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iOS_Extensions_PushProvider.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - A90DD8FC6E4726B7E7187C59 /* Pods_watchOS_WatchExtension_Watch.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_watchOS_WatchExtension_Watch.framework; sourceTree = BUILT_PRODUCTS_DIR; }; ADC769271BB34C474C2D1E24 /* Pods-iOS-Shared-iOS-metadata.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "Pods-iOS-Shared-iOS-metadata.plist"; path = "Pods/Pods-iOS-Shared-iOS-metadata.plist"; sourceTree = ""; }; AF744211EE471EE671F7C928 /* Pods-iOS-Extensions-NotificationService.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-Extensions-NotificationService.debug.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-Extensions-NotificationService/Pods-iOS-Extensions-NotificationService.debug.xcconfig"; sourceTree = ""; }; B086E41966E89AE531E3C1A5 /* Pods-iOS-Extensions-Widgets.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-Extensions-Widgets.debug.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-Extensions-Widgets/Pods-iOS-Extensions-Widgets.debug.xcconfig"; sourceTree = ""; }; + B0E8BC2D15AF167A38B95512 /* Pods-watchOS-WatchApp.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-watchOS-WatchApp.debug.xcconfig"; path = "Pods/Target Support Files/Pods-watchOS-WatchApp/Pods-watchOS-WatchApp.debug.xcconfig"; sourceTree = ""; }; B2F5238669D8A7416FBD2B55 /* Pods-iOS-Shared-iOS-Tests-Shared-metadata.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "Pods-iOS-Shared-iOS-Tests-Shared-metadata.plist"; path = "Pods/Pods-iOS-Shared-iOS-Tests-Shared-metadata.plist"; sourceTree = ""; }; B6022212226DAC9D00E8DBFE /* ScaledFont.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScaledFont.swift; sourceTree = ""; }; B60247ED1FBD21C600998205 /* de */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = de; path = de.lproj/Localizable.strings; sourceTree = ""; }; @@ -2794,7 +2780,6 @@ B6CC5D852159D10D00833E5D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Interface.storyboard; sourceTree = ""; }; B6CC5D872159D10E00833E5D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; B6CC5D892159D10E00833E5D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - B6CC5D8E2159D10E00833E5D /* HomeAssistant-WatchExtension-Watch.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "HomeAssistant-WatchExtension-Watch.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; B6CC5D952159D10E00833E5D /* ExtensionDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExtensionDelegate.swift; sourceTree = ""; }; B6CC5D972159D10E00833E5D /* ComplicationController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComplicationController.swift; sourceTree = ""; }; B6CC5D992159D10F00833E5D /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; @@ -2829,6 +2814,7 @@ B6FD0571228411B200AC45BA /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Intents.strings; sourceTree = ""; }; B6FD0573228411B200AC45BA /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/InfoPlist.strings; sourceTree = ""; }; B6FD0574228411B200AC45BA /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; + B7A6C547EAAD9AF86D273FE0 /* Pods_watchOS_WatchApp.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_watchOS_WatchApp.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B9B49F9D3E32AD45659A0A41 /* Pods-iOS-Extensions-Matter.beta.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-Extensions-Matter.beta.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-Extensions-Matter/Pods-iOS-Extensions-Matter.beta.xcconfig"; sourceTree = ""; }; BED1F3255FAD612BC4670B45 /* Pods-iOS-Extensions-Share.beta.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-Extensions-Share.beta.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-Extensions-Share/Pods-iOS-Extensions-Share.beta.xcconfig"; sourceTree = ""; }; BEE6D44D86AC3F2F3E43950D /* Pods-watchOS-Shared-watchOS.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-watchOS-Shared-watchOS.debug.xcconfig"; path = "Pods/Target Support Files/Pods-watchOS-Shared-watchOS/Pods-watchOS-Shared-watchOS.debug.xcconfig"; sourceTree = ""; }; @@ -2885,6 +2871,7 @@ F3A0FB3BD04C582E655168D0 /* Pods-Tests-App.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Tests-App.release.xcconfig"; path = "Pods/Target Support Files/Pods-Tests-App/Pods-Tests-App.release.xcconfig"; sourceTree = ""; }; F3E55AA06795782F04D0B261 /* Pods-iOS-Extensions-Intents.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-Extensions-Intents.release.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-Extensions-Intents/Pods-iOS-Extensions-Intents.release.xcconfig"; sourceTree = ""; }; F534C18A6FD4884F258341C9 /* Pods-iOS-Shared-iOS.beta.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-Shared-iOS.beta.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-Shared-iOS/Pods-iOS-Shared-iOS.beta.xcconfig"; sourceTree = ""; }; + FC040D38430EF9564E6F6BD4 /* Pods-watchOS-WatchApp.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-watchOS-WatchApp.release.xcconfig"; path = "Pods/Target Support Files/Pods-watchOS-WatchApp/Pods-watchOS-WatchApp.release.xcconfig"; sourceTree = ""; }; FD3BC66229B9FF8F00B19FBE /* CarPlaySceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarPlaySceneDelegate.swift; sourceTree = ""; }; FD3BC66629BA003B00B19FBE /* HAEntity+CarPlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "HAEntity+CarPlay.swift"; sourceTree = ""; }; FD3BC66B29BA00D600B19FBE /* CarPlayEntitiesListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarPlayEntitiesListTemplate.swift; sourceTree = ""; }; @@ -2965,6 +2952,9 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + B67CE82B22200D420034C1D0 /* Shared.framework in Frameworks */, + 4273F7E02E258827000629F7 /* SharedPush in Frameworks */, + 1A1A813D0F64A988BBEE9BFD /* Pods_watchOS_WatchApp.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3041,16 +3031,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - B6CC5D8B2159D10E00833E5D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 4273F7E02E258827000629F7 /* SharedPush in Frameworks */, - B67CE82B22200D420034C1D0 /* Shared.framework in Frameworks */, - 368048FC64829A4E4B82B631 /* Pods_watchOS_WatchExtension_Watch.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; D03D891320E0A85200D4F28D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -3124,7 +3104,6 @@ B6AAD7A21D827DD40090B220 /* NotificationService */, 11B92968266F15A800786588 /* PushProvider */, 1155DD07250F4100003405C0 /* Share */, - B6CC5D922159D10E00833E5D /* Watch */, 1171506E24DFCDE60065E874 /* Widgets */, ); path = Extensions; @@ -3832,13 +3811,13 @@ 7A6E8DF7DED57BAD4EF47D11 /* Pods_iOS_Extensions_Today.framework */, D27653D385E4CEB58E52A350 /* Pods_iOS_Extensions_Widgets.framework */, 213EF66D14F92AF8BF2E9E98 /* Pods_iOS_Shared_iOS.framework */, - A90DD8FC6E4726B7E7187C59 /* Pods_watchOS_WatchExtension_Watch.framework */, 6F1D92E4B7A5CD1007EB0782 /* Pods_watchOS_Shared_watchOS.framework */, 3F4DFB087A3A43F9A526B851 /* Pods_iOS_Shared_iOS_Tests_Shared.framework */, 11B9290A266F145000786588 /* NetworkExtension.framework */, A370326321B07E5ACE0BCB65 /* Pods_iOS_Extensions_PushProvider.framework */, 943E024774CF54EADF771379 /* Pods_iOS_Extensions_Matter.framework */, 202360CC8C2C1193658F9359 /* Pods_iOS_SharedTesting.framework */, + B7A6C547EAAD9AF86D273FE0 /* Pods_watchOS_WatchApp.framework */, ); name = Frameworks; sourceTree = ""; @@ -5200,6 +5179,10 @@ 38BD687E2E320F27D6D576B5 /* Pods-iOS-SharedTesting.release.xcconfig */, E81F5CF42E9F5D95BD0E6019 /* Pods-iOS-SharedTesting.beta.xcconfig */, 4053903E4C54A6803204286E /* Pods-iOS-SharedTesting-metadata.plist */, + B0E8BC2D15AF167A38B95512 /* Pods-watchOS-WatchApp.debug.xcconfig */, + FC040D38430EF9564E6F6BD4 /* Pods-watchOS-WatchApp.release.xcconfig */, + 08F833C0E119C39117BE760A /* Pods-watchOS-WatchApp.beta.xcconfig */, + 4F613C4C29293CED6B9EB533 /* Pods-watchOS-WatchApp-metadata.plist */, ); name = Pods; sourceTree = ""; @@ -5408,7 +5391,6 @@ D03D894220E0BC1800D4F28D /* HomeAssistant-Tests-Shared.xctest */, B66C58A5215086F0004AB261 /* HomeAssistant-Extensions-Intents.appex */, B6CC5D822159D10D00833E5D /* HomeAssistant-WatchApp.app */, - B6CC5D8E2159D10E00833E5D /* HomeAssistant-WatchExtension-Watch.appex */, B67CE82422200D420034C1D0 /* Shared.framework */, 1171506924DFCDE60065E874 /* HomeAssistant-Extensions-Widgets.appex */, 1155DD06250F4100003405C0 /* HomeAssistant-Extensions-Share.appex */, @@ -5551,7 +5533,6 @@ B672AB592216C41000175465 /* Utilities */ = { isa = PBXGroup; children = ( - B69769832162430300FFFAD6 /* WKInterfaceDevice+Size.swift */, B672AB572216B5E000175465 /* Date+ComplicationDivination.swift */, 1178AAFF263E2DF7007BA9D0 /* WKInterfaceLabel+Additions.swift */, ); @@ -5620,24 +5601,18 @@ B6CC5D872159D10E00833E5D /* Assets.xcassets */, B6CC5D892159D10E00833E5D /* Info.plist */, 42C373AF2BC536AA00898990 /* WatchApp-Bridging-Header.h */, - ); - path = WatchApp; - sourceTree = ""; - }; - B6CC5D922159D10E00833E5D /* Watch */ = { - isa = PBXGroup; - children = ( + 42DA945C2E37D01400D57D00 /* WatchMain.swift */, + 42F44E0F2E37BAB500C597CB /* WatchHostingController.swift */, + 42C373B62BC55C3A00898990 /* Home */, 426490662C0F1A27002155CC /* Assist */, 423F451E2C19D87500766A99 /* Complication */, - 42C373B62BC55C3A00898990 /* Home */, B672AB592216C41000175465 /* Utilities */, B6CC5DAA2159D60900833E5D /* Resources */, 11FA935A263FAA7C0015F1FC /* Notifications */, B6CC5D952159D10E00833E5D /* ExtensionDelegate.swift */, 423F44FE2C186E4500766A99 /* WatchCommunicatorService.swift */, - 42C373B12BC5382900898990 /* HostingController.swift */, ); - path = Watch; + path = WatchApp; sourceTree = ""; }; B6CC5DAA2159D60900833E5D /* Resources */ = { @@ -5731,6 +5706,7 @@ D03D891820E0A85300D4F28D /* Shared */ = { isa = PBXGroup; children = ( + B69769832162430300FFFAD6 /* WKInterfaceDevice+Size.swift */, 420CFC612D3F9C15009A94F3 /* Database */, 4278CB822D01F09400CFAAC9 /* AppGesture.swift */, 424D2D0F2C89DACE00C610F1 /* HAAppEntity.swift */, @@ -6337,41 +6313,23 @@ isa = PBXNativeTarget; buildConfigurationList = B6CC5DA52159D10F00833E5D /* Build configuration list for PBXNativeTarget "WatchApp" */; buildPhases = ( + 51E510F12D587663E595658D /* [CP] Check Pods Manifest.lock */, 11A67358268D9E7B00D1AFD4 /* Fix Xcode 12.5+ Dependency Issues */, B6CC5D802159D10D00833E5D /* Resources */, 93C44648FF2FAE89B2ED8FC9 /* Frameworks */, - 119A172824D74DA800D1B66D /* Embed App Extensions */, + B6CC5D8A2159D10E00833E5D /* Sources */, + B61DA2A7221E8D8F00AADEDD /* Embed Frameworks */, + 79303F0C328034C39D5B7402 /* [CP] Embed Pods Frameworks */, ); buildRules = ( ); dependencies = ( - 119A172724D74DA800D1B66D /* PBXTargetDependency */, + 42F44E122E37BF1400C597CB /* PBXTargetDependency */, ); name = WatchApp; productName = WatchApp; productReference = B6CC5D822159D10D00833E5D /* HomeAssistant-WatchApp.app */; - productType = "com.apple.product-type.application.watchapp2"; - }; - B6CC5D8D2159D10E00833E5D /* WatchExtension-Watch */ = { - isa = PBXNativeTarget; - buildConfigurationList = B6CC5DA32159D10F00833E5D /* Build configuration list for PBXNativeTarget "WatchExtension-Watch" */; - buildPhases = ( - 59C2CF28F00F34975C1AC68B /* [CP] Check Pods Manifest.lock */, - B6CC5D8A2159D10E00833E5D /* Sources */, - B6CC5D8B2159D10E00833E5D /* Frameworks */, - B6CC5D8C2159D10E00833E5D /* Resources */, - F3E3FC23B4E5B348B92D05F4 /* [CP] Embed Pods Frameworks */, - B61DA2A7221E8D8F00AADEDD /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - B67CE82A22200D420034C1D0 /* PBXTargetDependency */, - ); - name = "WatchExtension-Watch"; - productName = "WatchApp Extension"; - productReference = B6CC5D8E2159D10E00833E5D /* HomeAssistant-WatchExtension-Watch.appex */; - productType = "com.apple.product-type.watchkit2-extension"; + productType = "com.apple.product-type.application"; }; D03D891620E0A85200D4F28D /* Shared-iOS */ = { isa = PBXNativeTarget; @@ -6427,7 +6385,7 @@ attributes = { DefaultBuildSystemTypeForWorkspace = Original; LastSwiftUpdateCheck = 1540; - LastUpgradeCheck = 1330; + LastUpgradeCheck = 2600; ORGANIZATIONNAME = "Home Assistant"; TargetAttributes = { 111711E425B29ACB003C149E = { @@ -6571,20 +6529,6 @@ }; }; }; - B6CC5D8D2159D10E00833E5D = { - CreatedOnToolsVersion = 10.0; - DevelopmentTeam = QMQYCKL255; - LastSwiftMigration = 1020; - ProvisioningStyle = Automatic; - SystemCapabilities = { - com.apple.ApplicationGroups.iOS = { - enabled = 1; - }; - com.apple.Keychain = { - enabled = 0; - }; - }; - }; D03D891620E0A85200D4F28D = { CreatedOnToolsVersion = 9.4.1; DevelopmentTeam = QMQYCKL255; @@ -6646,6 +6590,7 @@ 42B89EA62E05CC54000224A2 /* XCRemoteSwiftPackageReference "WebRTC" */, 42E00D0F2E1E7487006D140D /* XCLocalSwiftPackageReference "SharedPush" */, 4237E6372E5333370023B673 /* XCRemoteSwiftPackageReference "ZIPFoundation" */, + 42E00D0F2E1E7487006D140D /* XCLocalSwiftPackageReference "SharedPush" */, ); productRefGroup = B657A8E71CA646EB00121384 /* Products */; projectDirPath = ""; @@ -6669,7 +6614,6 @@ 11B92908266F145000786588 /* Extensions-PushProvider */, 1155DD05250F4100003405C0 /* Extensions-Share */, 1171506824DFCDE60065E874 /* Extensions-Widgets */, - B6CC5D8D2159D10E00833E5D /* WatchExtension-Watch */, ); }; /* End PBXProject section */ @@ -6951,21 +6895,15 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 426490732C0F1F36002155CC /* Colors.xcassets in Resources */, + FC8E9421FDB864726918B612 /* Pods-watchOS-WatchExtension-Watch-metadata.plist in Resources */, B6CC5D882159D10E00833E5D /* Assets.xcassets in Resources */, + 426266422C11A6700081A818 /* SharedAssets.xcassets in Resources */, 42E0D82C2DCCE5900095A245 /* Colors.xcassets in Resources */, 404C79802C3491390010EB81 /* Localizable.strings in Resources */, - B6CC5D862159D10D00833E5D /* Interface.storyboard in Resources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - B6CC5D8C2159D10E00833E5D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 426490732C0F1F36002155CC /* Colors.xcassets in Resources */, B6CC5D9A2159D10F00833E5D /* Assets.xcassets in Resources */, - FC8E9421FDB864726918B612 /* Pods-watchOS-WatchExtension-Watch-metadata.plist in Resources */, - 426266422C11A6700081A818 /* SharedAssets.xcassets in Resources */, + B6CC5D862159D10D00833E5D /* Interface.storyboard in Resources */, + 60E18AF064002291A5359166 /* Pods-watchOS-WatchApp-metadata.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -7256,7 +7194,7 @@ shellPath = /bin/sh; shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n${SRCROOT}/Tools/BuildMaterialDesignIconsFont.sh\n"; }; - 53D3FBBE96A99C3DA7040194 /* [CP] Check Pods Manifest.lock */ = { + 51E510F12D587663E595658D /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -7271,14 +7209,14 @@ outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-iOS-Extensions-PushProvider-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-watchOS-WatchApp-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - 59C2CF28F00F34975C1AC68B /* [CP] Check Pods Manifest.lock */ = { + 53D3FBBE96A99C3DA7040194 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; files = ( @@ -7293,7 +7231,7 @@ outputFileListPaths = ( ); outputPaths = ( - "$(DERIVED_FILE_DIR)/Pods-watchOS-WatchExtension-Watch-checkManifestLockResult.txt", + "$(DERIVED_FILE_DIR)/Pods-iOS-Extensions-PushProvider-checkManifestLockResult.txt", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -7322,6 +7260,23 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; + 79303F0C328034C39D5B7402 /* [CP] Embed Pods Frameworks */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + inputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-watchOS-WatchApp/Pods-watchOS-WatchApp-frameworks-${CONFIGURATION}-input-files.xcfilelist", + ); + name = "[CP] Embed Pods Frameworks"; + outputFileListPaths = ( + "${PODS_ROOT}/Target Support Files/Pods-watchOS-WatchApp/Pods-watchOS-WatchApp-frameworks-${CONFIGURATION}-output-files.xcfilelist", + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-watchOS-WatchApp/Pods-watchOS-WatchApp-frameworks.sh\"\n"; + showEnvVarsInLog = 0; + }; 7E148D7357216F7E4E7108F6 /* [CP] Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -7491,23 +7446,6 @@ shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n"; showEnvVarsInLog = 0; }; - F3E3FC23B4E5B348B92D05F4 /* [CP] Embed Pods Frameworks */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-watchOS-WatchExtension-Watch/Pods-watchOS-WatchExtension-Watch-frameworks-${CONFIGURATION}-input-files.xcfilelist", - ); - name = "[CP] Embed Pods Frameworks"; - outputFileListPaths = ( - "${PODS_ROOT}/Target Support Files/Pods-watchOS-WatchExtension-Watch/Pods-watchOS-WatchExtension-Watch-frameworks-${CONFIGURATION}-output-files.xcfilelist", - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-watchOS-WatchExtension-Watch/Pods-watchOS-WatchExtension-Watch-frameworks.sh\"\n"; - showEnvVarsInLog = 0; - }; F6F1EAA08C3E5179B7848A38 /* [CP] Embed Pods Frameworks */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -8343,6 +8281,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 42F44E102E37BAB500C597CB /* WatchHostingController.swift in Sources */, 426490772C0F2403002155CC /* WatchAudioRecorder.swift in Sources */, 423F45212C19D89100766A99 /* AssistDefaultComplication.swift in Sources */, 428830ED2C6E3A9A0012373D /* WatchHomeViewModel.swift in Sources */, @@ -8358,9 +8297,9 @@ 110D74CA2640E0DF00406078 /* NotificationSubControllerMedia.swift in Sources */, B672AB582216B5E000175465 /* Date+ComplicationDivination.swift in Sources */, 423F44F02C17238200766A99 /* ChatBubbleView.swift in Sources */, - 42C373B22BC5382900898990 /* HostingController.swift in Sources */, B6CC5D982159D10E00833E5D /* ComplicationController.swift in Sources */, 11169B7C262BDE80005EF90A /* DynamicNotificationController.swift in Sources */, + 42DA945D2E37D01400D57D00 /* WatchMain.swift in Sources */, 11684B7A263F994600B48EC3 /* NotificationSubControllerMJPEG.swift in Sources */, 42B1A7432C11E65100904548 /* WatchAssistService.swift in Sources */, 423F44FF2C186E4500766A99 /* WatchCommunicatorService.swift in Sources */, @@ -8737,11 +8676,6 @@ target = D03D891620E0A85200D4F28D /* Shared-iOS */; targetProxy = 1171507D24DFCE0D0065E874 /* PBXContainerItemProxy */; }; - 119A172724D74DA800D1B66D /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = B6CC5D8D2159D10E00833E5D /* WatchExtension-Watch */; - targetProxy = 119A172624D74DA800D1B66D /* PBXContainerItemProxy */; - }; 11A31C93252128B900D50A78 /* PBXTargetDependency */ = { isa = PBXTargetDependency; platformFilter = maccatalyst; @@ -8776,6 +8710,11 @@ target = 11DE9D8225B6103C0081C0ED /* Launcher */; targetProxy = 11DE9F9725B6173D0081C0ED /* PBXContainerItemProxy */; }; + 42F44E122E37BF1400C597CB /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = B67CE82322200D420034C1D0 /* Shared-watchOS */; + targetProxy = 42F44E112E37BF1400C597CB /* PBXContainerItemProxy */; + }; 4697F4C42D8A416400C5C467 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 46C62B872D8A3687002C0001 /* SharedTesting */; @@ -8806,11 +8745,6 @@ target = B66C58A4215086F0004AB261 /* Extensions-Intents */; targetProxy = B66C58AA215086F0004AB261 /* PBXContainerItemProxy */; }; - B67CE82A22200D420034C1D0 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = B67CE82322200D420034C1D0 /* Shared-watchOS */; - targetProxy = B67CE82922200D420034C1D0 /* PBXContainerItemProxy */; - }; B6AAD7A71D827DD40090B220 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = B6AAD7A01D827DD40090B220 /* Extensions-NotificationService */; @@ -9824,14 +9758,19 @@ }; B637243821697585006B102A /* Beta */ = { isa = XCBuildConfiguration; + baseConfigurationReference = 08F833C0E119C39117BE760A /* Pods-watchOS-WatchApp.beta.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "WatchIcon${BUNDLE_ID_SUFFIX}"; + ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; CLANG_ENABLE_MODULES = YES; - IBSC_MODULE = WatchExtension_Watch; + CODE_SIGN_ENTITLEMENTS = "Configuration/Entitlements/Extension-ios.entitlements"; INFOPLIST_FILE = Sources/WatchApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", + /usr/lib/swift, + "'@executable_path/Frameworks'", + "'@loader_path/Frameworks'", "@executable_path/Frameworks", + "@executable_path/../../Frameworks", ); PROVISIONING_SUFFIX = .watchkitapp; SDKROOT = watchos; @@ -9841,24 +9780,6 @@ }; name = Beta; }; - B637243921697585006B102A /* Beta */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 8E00CA53EFBB621A8470C22A /* Pods-watchOS-WatchExtension-Watch.beta.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; - CODE_SIGN_ENTITLEMENTS = "Configuration/Entitlements/Extension-ios.entitlements"; - INFOPLIST_FILE = Sources/Extensions/Watch/Resources/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - PROVISIONING_SUFFIX = .watchkitapp.watchkitextension; - SDKROOT = watchos; - TARGETED_DEVICE_FAMILY = 4; - }; - name = Beta; - }; B657A90E1CA646EB00121384 /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 9C4E5E21229D98220044C8EC /* HomeAssistant.debug.xcconfig */; @@ -10175,14 +10096,19 @@ }; B6CC5D9F2159D10F00833E5D /* Debug */ = { isa = XCBuildConfiguration; + baseConfigurationReference = B0E8BC2D15AF167A38B95512 /* Pods-watchOS-WatchApp.debug.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "WatchIcon${BUNDLE_ID_SUFFIX}"; + ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; CLANG_ENABLE_MODULES = YES; - IBSC_MODULE = WatchExtension_Watch; + CODE_SIGN_ENTITLEMENTS = "Configuration/Entitlements/Extension-ios.entitlements"; INFOPLIST_FILE = Sources/WatchApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", + /usr/lib/swift, + "'@executable_path/Frameworks'", + "'@loader_path/Frameworks'", "@executable_path/Frameworks", + "@executable_path/../../Frameworks", ); PROVISIONING_SUFFIX = .watchkitapp; SDKROOT = watchos; @@ -10195,14 +10121,19 @@ }; B6CC5DA02159D10F00833E5D /* Release */ = { isa = XCBuildConfiguration; + baseConfigurationReference = FC040D38430EF9564E6F6BD4 /* Pods-watchOS-WatchApp.release.xcconfig */; buildSettings = { ASSETCATALOG_COMPILER_APPICON_NAME = "WatchIcon${BUNDLE_ID_SUFFIX}"; + ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; CLANG_ENABLE_MODULES = YES; - IBSC_MODULE = WatchExtension_Watch; + CODE_SIGN_ENTITLEMENTS = "Configuration/Entitlements/Extension-ios.entitlements"; INFOPLIST_FILE = Sources/WatchApp/Info.plist; LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", + /usr/lib/swift, + "'@executable_path/Frameworks'", + "'@loader_path/Frameworks'", "@executable_path/Frameworks", + "@executable_path/../../Frameworks", ); PROVISIONING_SUFFIX = .watchkitapp; SDKROOT = watchos; @@ -10212,42 +10143,6 @@ }; name = Release; }; - B6CC5DA12159D10F00833E5D /* Debug */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 1C5C1EC99DF5FCB63422D279 /* Pods-watchOS-WatchExtension-Watch.debug.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; - CODE_SIGN_ENTITLEMENTS = "Configuration/Entitlements/Extension-ios.entitlements"; - INFOPLIST_FILE = Sources/Extensions/Watch/Resources/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - PROVISIONING_SUFFIX = .watchkitapp.watchkitextension; - SDKROOT = watchos; - TARGETED_DEVICE_FAMILY = 4; - }; - name = Debug; - }; - B6CC5DA22159D10F00833E5D /* Release */ = { - isa = XCBuildConfiguration; - baseConfigurationReference = 755DF7AFFAA21F6CE428E998 /* Pods-watchOS-WatchExtension-Watch.release.xcconfig */; - buildSettings = { - ASSETCATALOG_COMPILER_COMPLICATION_NAME = Complication; - CODE_SIGN_ENTITLEMENTS = "Configuration/Entitlements/Extension-ios.entitlements"; - INFOPLIST_FILE = Sources/Extensions/Watch/Resources/Info.plist; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@executable_path/../../Frameworks", - ); - PROVISIONING_SUFFIX = .watchkitapp.watchkitextension; - SDKROOT = watchos; - TARGETED_DEVICE_FAMILY = 4; - }; - name = Release; - }; D03D892F20E0A85300D4F28D /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 97F089744D425CAB2755F843 /* Pods-iOS-Shared-iOS.debug.xcconfig */; @@ -10489,16 +10384,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - B6CC5DA32159D10F00833E5D /* Build configuration list for PBXNativeTarget "WatchExtension-Watch" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - B6CC5DA12159D10F00833E5D /* Debug */, - B6CC5DA22159D10F00833E5D /* Release */, - B637243921697585006B102A /* Beta */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; B6CC5DA52159D10F00833E5D /* Build configuration list for PBXNativeTarget "WatchApp" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/HomeAssistant.xcodeproj/xcshareddata/xcschemes/App-Beta.xcscheme b/HomeAssistant.xcodeproj/xcshareddata/xcschemes/App-Beta.xcscheme index 63d5438a04..a4b88a1c26 100644 --- a/HomeAssistant.xcodeproj/xcshareddata/xcschemes/App-Beta.xcscheme +++ b/HomeAssistant.xcodeproj/xcshareddata/xcschemes/App-Beta.xcscheme @@ -1,6 +1,6 @@ MagicItem.Info { - viewModel.magicItemsInfo.first(where: { - $0.id == magicItem.serverUniqueId - }) ?? .init( - id: magicItem.id, - name: magicItem.id, - iconName: "" - ) - } -} diff --git a/Sources/Extensions/Watch/HostingController.swift b/Sources/Extensions/Watch/HostingController.swift deleted file mode 100644 index d6294d7f06..0000000000 --- a/Sources/Extensions/Watch/HostingController.swift +++ /dev/null @@ -1,8 +0,0 @@ -import Foundation -import SwiftUI - -final class HostingController: WKHostingController { - override var body: WatchHomeView { - WatchHomeView() - } -} diff --git a/Sources/Shared/DesignSystem/Components/AppleLikeBottomSheet.swift b/Sources/Shared/DesignSystem/Components/AppleLikeBottomSheet.swift index d2326a4478..c652df0083 100644 --- a/Sources/Shared/DesignSystem/Components/AppleLikeBottomSheet.swift +++ b/Sources/Shared/DesignSystem/Components/AppleLikeBottomSheet.swift @@ -167,6 +167,7 @@ public struct AppleLikeBottomSheet: View { ) .foregroundStyle(.gray, Color(uiColor: .secondarySystemBackground)) }) + .buttonStyle(.plain) } } .padding(.top, DesignSystem.Spaces.three) diff --git a/Sources/Shared/DesignSystem/Components/CloseButton.swift b/Sources/Shared/DesignSystem/Components/CloseButton.swift index 5af306516c..2bc53277c2 100644 --- a/Sources/Shared/DesignSystem/Components/CloseButton.swift +++ b/Sources/Shared/DesignSystem/Components/CloseButton.swift @@ -46,19 +46,29 @@ public struct CloseButton: View { } public var body: some View { - Button(action: { - if let alternativeAction { - alternativeAction() - } else { - dismiss() + if #available(iOS 26.0, *) { + Button(role: .close) { + tapAction() } - }, label: { - Image(systemSymbol: .xmarkCircleFill) - .resizable() - .frame(width: size.size, height: size.size) - .foregroundStyle(tint) - }) - .buttonStyle(.plain) + } else { + Button(action: { + tapAction() + }, label: { + Image(systemSymbol: .xmarkCircleFill) + .resizable() + .frame(width: size.size, height: size.size) + .foregroundStyle(tint) + }) + .buttonStyle(.plain) + } + } + + private func tapAction() { + if let alternativeAction { + alternativeAction() + } else { + dismiss() + } } } diff --git a/Sources/Shared/Environment/Environment.swift b/Sources/Shared/Environment/Environment.swift index de2788c057..9cafd5eeb0 100644 --- a/Sources/Shared/Environment/Environment.swift +++ b/Sources/Shared/Environment/Environment.swift @@ -4,6 +4,7 @@ import CoreMotion import Foundation import GRDB import HAKit +import NetworkExtension import PromiseKit import RealmSwift import UserNotifications @@ -445,6 +446,16 @@ public class AppEnvironment { UNUserNotificationCenter.current() } + public var networkInformation: NEHotspotNetwork? { + get async { + await withCheckedContinuation { continuation in + NEHotspotNetwork.fetchCurrent { hotspotNetwork in + continuation.resume(returning: hotspotNetwork) + } + } + } + } + #if !os(watchOS) /// Provides a way to handle Bonjour connections. Such as for scanning for Home Assistant instances. public var bonjour: () -> BonjourProtocol = { diff --git a/Sources/Extensions/Watch/Utilities/WKInterfaceDevice+Size.swift b/Sources/Shared/WKInterfaceDevice+Size.swift similarity index 100% rename from Sources/Extensions/Watch/Utilities/WKInterfaceDevice+Size.swift rename to Sources/Shared/WKInterfaceDevice+Size.swift diff --git a/Sources/Shared/Watch/InteractiveImmediateMessages.swift b/Sources/Shared/Watch/InteractiveImmediateMessages.swift index 0fd8c6778a..072f8b7ce4 100644 --- a/Sources/Shared/Watch/InteractiveImmediateMessages.swift +++ b/Sources/Shared/Watch/InteractiveImmediateMessages.swift @@ -6,7 +6,7 @@ public enum InteractiveImmediateMessages: String, CaseIterable { case magicItemPressed case pushAction = "PushAction" case assistPipelinesFetch - case assistAudioData + case assistAudioDataChunked case watchConfig } diff --git a/Sources/Watch/WatchCommunicatorService.swift b/Sources/Watch/WatchCommunicatorService.swift index 234b152cef..c0c387ea3b 100644 --- a/Sources/Watch/WatchCommunicatorService.swift +++ b/Sources/Watch/WatchCommunicatorService.swift @@ -13,6 +13,10 @@ final class WatchCommunicatorService { private var assistService: AssistServiceProtocol? private var pendingAudioData: Data? + // [sessionKey: [chunkIndex: Data]] + private var audioChunks: [String: [Int: Data]] = [:] + private var audioChunkCounts: [String: Int] = [:] + func setup() { Current.servers.add(observer: self) @@ -33,14 +37,6 @@ final class WatchCommunicatorService { setupMessages() - Blob.observations.store[.init(queue: .main)] = { [weak self] blob in - Current.Log.verbose("Received blob: \(blob.identifier)") - - if blob.identifier == InteractiveImmediateMessages.assistAudioData.rawValue { - self?.assistAudioData(blob: blob) - } - } - Context.observations.store[.init(queue: .main)] = { context in Current.Log.verbose("Received context: \(context.content.keys) \(context.content)") @@ -77,15 +73,51 @@ final class WatchCommunicatorService { pushAction(message: message) case .assistPipelinesFetch: assistPipelinesFetch(message: message) - case .assistAudioData: - // This will be handled by Blob observation due to amount of data - break + case .assistAudioDataChunked: + handleAssistAudioChunkedMessage(message) case .magicItemPressed: magicItemPressed(message: message) } } } + private func handleAssistAudioChunkedMessage(_ message: InteractiveImmediateMessage) { + guard let chunkData = message.content["chunkData"] as? Data, + let chunkIndex = message.content["chunkIndex"] as? Int, + let totalChunks = message.content["totalChunks"] as? Int, + let serverId = message.content["serverId"] as? String, + let pipelineId = message.content["pipelineId"] as? String else { + Current.Log.error("Invalid chunked message data") + return + } + let sessionKey = serverId + "_" + pipelineId + if audioChunks[sessionKey] == nil { + audioChunks[sessionKey] = [:] + } + audioChunks[sessionKey]?[chunkIndex] = chunkData + audioChunkCounts[sessionKey] = totalChunks + + // Reply acknowledging receipt of this chunk + message.reply(.init(identifier: "assistAudioChunkAck", content: [ + "acknowledged": true, + "chunkIndex": chunkIndex, + "totalChunks": totalChunks, + ])) + + // Check if all chunks are received + if let receivedChunks = audioChunks[sessionKey], + receivedChunks.count == totalChunks { + // Assemble data in order + let sortedChunks = receivedChunks.keys.sorted().compactMap { receivedChunks[$0] } + let combinedData = sortedChunks.reduce(Data(), +) + // Clean up + audioChunks.removeValue(forKey: sessionKey) + audioChunkCounts.removeValue(forKey: sessionKey) + // Call assistAudioData + assistAudioData(message: message.toImmediateMessage(), data: combinedData) + } + } + private func watchConfig(message: InteractiveImmediateMessage) { do { if let config: WatchConfig = try Current.database().read({ db in @@ -291,23 +323,22 @@ extension WatchCommunicatorService { } } - private func assistAudioData(blob: Blob) { - let serverId = blob.metadata?["serverId"] as? String + private func assistAudioData(message: ImmediateMessage, data: Data) { + let serverId = message.content["serverId"] as? String guard let server = Current.servers.all.first(where: { $0.identifier.rawValue == serverId }) ?? Current .servers.all.first else { - let errorMessage = "No server available to execute message \(blob.identifier)" + let errorMessage = "No server available to execute message \(message.identifier)" Current.Log.warning(errorMessage) return } - let pipelineId = blob.metadata?["pipelineId"] as? String - guard let sampleRate = blob.metadata?["sampleRate"] as? Double else { - let errorMessage = "No sample rate received in message \(blob.identifier)" + let pipelineId = message.content["pipelineId"] as? String + guard let sampleRate = message.content["sampleRate"] as? Double else { + let errorMessage = "No sample rate received in message \(message.identifier)" Current.Log.error(errorMessage) return } - let audioData = blob.content - pendingAudioData = audioData + pendingAudioData = data initAssistServiceIfNeeded(server: server).assist(source: .audio( pipelineId: pipelineId, audioSampleRate: sampleRate @@ -403,3 +434,9 @@ extension WatchCommunicatorService: ServerObserver { _ = HomeAssistantAPI.SyncWatchContext() } } + +private extension InteractiveImmediateMessage { + func toImmediateMessage() -> ImmediateMessage { + ImmediateMessage(identifier: identifier, content: content) + } +} diff --git a/Sources/Extensions/Watch/Assist/Views/ChatBubbleView.swift b/Sources/WatchApp/Assist/Views/ChatBubbleView.swift similarity index 100% rename from Sources/Extensions/Watch/Assist/Views/ChatBubbleView.swift rename to Sources/WatchApp/Assist/Views/ChatBubbleView.swift diff --git a/Sources/Extensions/Watch/Assist/Views/VolumeView.swift b/Sources/WatchApp/Assist/Views/VolumeView.swift similarity index 100% rename from Sources/Extensions/Watch/Assist/Views/VolumeView.swift rename to Sources/WatchApp/Assist/Views/VolumeView.swift diff --git a/Sources/Extensions/Watch/Assist/WatchAssistService.swift b/Sources/WatchApp/Assist/WatchAssistService.swift similarity index 58% rename from Sources/Extensions/Watch/Assist/WatchAssistService.swift rename to Sources/WatchApp/Assist/WatchAssistService.swift index c3e113d59e..d6381b5304 100644 --- a/Sources/Extensions/Watch/Assist/WatchAssistService.swift +++ b/Sources/WatchApp/Assist/WatchAssistService.swift @@ -49,28 +49,31 @@ final class WatchAssistService: ObservableObject { Current.Log.verbose("Signaling Assist audio data") - let metadata: [String: Any] = [ - "sampleRate": sampleRate, - "pipelineId": pipelineId, - "serverId": serverId, - ] + let chunkSize = 32 * 1024 // 32 KB + let totalChunks = Int(ceil(Double(audioData.count) / Double(chunkSize))) - let blob = Blob( - identifier: InteractiveImmediateMessages.assistAudioData.rawValue, - content: audioData, - metadata: metadata - ) + for chunkIndex in 0 ..< totalChunks { + let start = chunkIndex * chunkSize + let end = min(start + chunkSize, audioData.count) + let chunkData = audioData.subdata(in: start ..< end) - Current.Log.verbose("Sending \(blob.identifier)") - - cancellable = Communicator.shared.transfer(blob) { result in - switch result { - case .success: - completion(nil) - case let .failure(error): - Current.Log.error("Failed to send audio data blob: \(error.localizedDescription)") - completion(error) - } + // Ideally data transfers are done using an specific method to transfer data + // but in reality this has demonstrated to not work well specially in watchOS 26 + // this logic uses the normal communication messages in chunks for more reliability + Communicator.shared.send(.init( + identifier: InteractiveImmediateMessages.assistAudioDataChunked.rawValue, + content: [ + "chunkData": chunkData, + "chunkIndex": chunkIndex, + "totalChunks": totalChunks, + "sampleRate": sampleRate, + "pipelineId": pipelineId, + "serverId": serverId, + ], + reply: { message in + Current.Log.verbose("Received reply for assist audio chunk #\(chunkIndex): \(message)") + } + )) } } catch { Current.Log.error("Watch assist failed: \(error.localizedDescription)") diff --git a/Sources/Extensions/Watch/Assist/WatchAssistView+Build.swift b/Sources/WatchApp/Assist/WatchAssistView+Build.swift similarity index 100% rename from Sources/Extensions/Watch/Assist/WatchAssistView+Build.swift rename to Sources/WatchApp/Assist/WatchAssistView+Build.swift diff --git a/Sources/Extensions/Watch/Assist/WatchAssistView.swift b/Sources/WatchApp/Assist/WatchAssistView.swift similarity index 91% rename from Sources/Extensions/Watch/Assist/WatchAssistView.swift rename to Sources/WatchApp/Assist/WatchAssistView.swift index 595e75cffb..1a73a26387 100644 --- a/Sources/Extensions/Watch/Assist/WatchAssistView.swift +++ b/Sources/WatchApp/Assist/WatchAssistView.swift @@ -100,6 +100,14 @@ struct WatchAssistView: View { NavigationLink(destination: VolumeView()) { Image(systemSymbol: .speakerWave2Fill) } + .modify { view in + if #available(watchOS 26.0, *) { + view + .tint(.green) + } else { + view + } + } } @ViewBuilder @@ -113,7 +121,9 @@ struct WatchAssistView: View { .ignoresSafeArea() .frame(maxWidth: .infinity, maxHeight: .infinity) .modify { - if #available(watchOS 10, *) { + if #available(watchOS 26.0, *) { + $0.glassEffect(.clear, in: .circle) + } else if #available(watchOS 10, *) { $0.background(.regularMaterial) } else { $0.background(.black.opacity(0.5)) @@ -173,7 +183,7 @@ struct WatchAssistView: View { Button(action: { viewModel.assist() }, label: { - VStack(spacing: .zero) { + VStack(spacing: DesignSystem.Spaces.one) { if #available(watchOS 10.0, *) { Image(systemSymbol: .waveformCircleFill) .font(.system(size: Constants.micRecordingFontSizeLarge)) @@ -188,12 +198,13 @@ struct WatchAssistView: View { Image(systemSymbol: .waveformCircleFill) .font(.system(size: Constants.micRecordingFontSizeSmall)) } - Text(verbatim: L10n.Watch.Assist.Button.Recording.title) - .font(.system(size: Constants.micRecordingTextFontSize)) - .foregroundStyle(.gray) - Text(verbatim: L10n.Watch.Assist.Button.SendRequest.title) - .font(.footnote.bold()) - .padding() + VStack(spacing: .zero) { + Text(verbatim: L10n.Watch.Assist.Button.Recording.title) + .font(.system(size: Constants.micRecordingTextFontSize)) + .foregroundStyle(.gray) + Text(verbatim: L10n.Watch.Assist.Button.SendRequest.title) + .font(.footnote.bold()) + } } }) .buttonStyle(.plain) diff --git a/Sources/Extensions/Watch/Assist/WatchAssistViewModel.swift b/Sources/WatchApp/Assist/WatchAssistViewModel.swift similarity index 100% rename from Sources/Extensions/Watch/Assist/WatchAssistViewModel.swift rename to Sources/WatchApp/Assist/WatchAssistViewModel.swift diff --git a/Sources/Extensions/Watch/Assist/WatchAudioRecorder.swift b/Sources/WatchApp/Assist/WatchAudioRecorder.swift similarity index 100% rename from Sources/Extensions/Watch/Assist/WatchAudioRecorder.swift rename to Sources/WatchApp/Assist/WatchAudioRecorder.swift diff --git a/Sources/WatchApp/Base.lproj/Interface.storyboard b/Sources/WatchApp/Base.lproj/Interface.storyboard index cecc6551f7..9a7e02d9d4 100644 --- a/Sources/WatchApp/Base.lproj/Interface.storyboard +++ b/Sources/WatchApp/Base.lproj/Interface.storyboard @@ -1,30 +1,23 @@ - + - + - - - - - - - - @@ -43,13 +36,13 @@ - @@ -68,13 +61,13 @@ - @@ -93,18 +86,18 @@ - @@ -125,13 +118,13 @@ - @@ -150,13 +143,13 @@ - @@ -172,7 +165,7 @@ - + diff --git a/Sources/Extensions/Watch/Complication/Assist/AssistDefaultComplication.swift b/Sources/WatchApp/Complication/Assist/AssistDefaultComplication.swift similarity index 100% rename from Sources/Extensions/Watch/Complication/Assist/AssistDefaultComplication.swift rename to Sources/WatchApp/Complication/Assist/AssistDefaultComplication.swift diff --git a/Sources/Extensions/Watch/Complication/ComplicationController.swift b/Sources/WatchApp/Complication/ComplicationController.swift similarity index 100% rename from Sources/Extensions/Watch/Complication/ComplicationController.swift rename to Sources/WatchApp/Complication/ComplicationController.swift diff --git a/Sources/Extensions/Watch/ExtensionDelegate.swift b/Sources/WatchApp/ExtensionDelegate.swift similarity index 98% rename from Sources/Extensions/Watch/ExtensionDelegate.swift rename to Sources/WatchApp/ExtensionDelegate.swift index ae66d32abe..a6512d9928 100644 --- a/Sources/Extensions/Watch/ExtensionDelegate.swift +++ b/Sources/WatchApp/ExtensionDelegate.swift @@ -6,7 +6,7 @@ import UserNotifications import WatchKit import XCGLogger -class ExtensionDelegate: NSObject, WKExtensionDelegate { +class ExtensionDelegate: NSObject, WKApplicationDelegate { // MARK: Fileprivate fileprivate var watchConnectivityBackgroundPromise: Guarantee @@ -20,7 +20,7 @@ class ExtensionDelegate: NSObject, WKExtensionDelegate { super.init() } - // MARK: - WKExtensionDelegate - + // MARK: - WKApplicationDelegate - func applicationDidFinishLaunching() { // Perform any final initialization of your application. @@ -31,7 +31,7 @@ class ExtensionDelegate: NSObject, WKExtensionDelegate { let options: UNAuthorizationOptions = [.alert, .badge, .sound, .criticalAlert, .providesAppNotificationSettings] - WKExtension.shared().registerForRemoteNotifications() + WKApplication.shared().registerForRemoteNotifications() UNUserNotificationCenter.current().requestAuthorization(options: options) { granted, error in Current.Log.verbose("Requested notifications access \(granted), \(String(describing: error))") @@ -296,7 +296,7 @@ extension ExtensionDelegate: UNUserNotificationCenterDelegate { willPresent notification: UNNotification, withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void ) { - completionHandler([.alert, .badge, .sound]) + completionHandler([.banner, .badge, .sound]) } func userNotificationCenter( diff --git a/Sources/Extensions/Watch/Home/MagicItemRow/WatchMagicViewRow.swift b/Sources/WatchApp/Home/MagicItemRow/WatchMagicViewRow.swift similarity index 70% rename from Sources/Extensions/Watch/Home/MagicItemRow/WatchMagicViewRow.swift rename to Sources/WatchApp/Home/MagicItemRow/WatchMagicViewRow.swift index 983d8b8826..0fc1cdd942 100644 --- a/Sources/Extensions/Watch/Home/MagicItemRow/WatchMagicViewRow.swift +++ b/Sources/WatchApp/Home/MagicItemRow/WatchMagicViewRow.swift @@ -1,3 +1,4 @@ +import SFSafeSymbols import Shared import SwiftUI @@ -12,7 +13,7 @@ struct WatchMagicViewRow: View { Button { viewModel.executeItem() } label: { - HStack(spacing: Spaces.one) { + HStack(spacing: DesignSystem.Spaces.one) { iconToDisplay .animation(.bouncy, value: viewModel.state) Text(viewModel.item.name(info: viewModel.itemInfo)) @@ -20,10 +21,12 @@ struct WatchMagicViewRow: View { .foregroundStyle(textColor) .lineLimit(3) .frame(maxWidth: .infinity, alignment: .leading) + .multilineTextAlignment(.leading) .padding(.trailing) } + .frame(maxWidth: .infinity) } - .listRowBackground(backgroundForWatchItem.cornerRadius(14)) + .frame(maxWidth: .infinity) .confirmationDialog( L10n.Watch.Home.Run.Confirmation.title(viewModel.item.name(info: viewModel.itemInfo)), isPresented: $viewModel.showConfirmationDialog, @@ -39,16 +42,21 @@ struct WatchMagicViewRow: View { .tint(.red) } ) - .modify { view in - if let backgroundColor = viewModel.item.customization?.backgroundColor { - view.listRowBackground( - Color(uiColor: .init(hex: backgroundColor)) - .clipShape(RoundedRectangle(cornerRadius: 14)) - ) + .listRowBackground(Color.clear) + .modify({ view in + if #available(watchOS 26.0, *) { + if let backgroundForWatchItem { + view + .buttonStyle(.glassProminent) + .tint(backgroundForWatchItem) + } else { + view.buttonStyle(.glass) + } } else { view + .listRowBackground((backgroundForWatchItem ?? Color.gray.opacity(0.3)).cornerRadius(14)) } - } + }) .onChange(of: viewModel.state) { newValue in // TODO: On watchOS 10 this can be replaced by '.sensoryFeedback' modifier let currentDevice = WKInterfaceDevice.current() @@ -82,19 +90,31 @@ struct WatchMagicViewRow: View { .shadow(color: .white, radius: 10) .padding() case .success: - makeStateImage(systemName: "checkmark.circle.fill") + makeStateImage(systemName: .checkmarkCircleFill) case .failure: - makeStateImage(systemName: "xmark.circle") + makeStateImage(systemName: .xmarkCircle) } } .frame(width: 38, height: 38) - .background(Color(uiColor: .init(hex: viewModel.itemInfo.customization?.iconColor)).opacity(0.3)) - .clipShape(Circle()) - .padding([.vertical, .trailing], Spaces.half) + .modify({ view in + if #available(watchOS 26.0, *) { + view + .glassEffect( + .clear + .tint(Color(uiColor: .init(hex: viewModel.itemInfo.customization?.iconColor)).opacity(0.3)), + in: .circle + ) + } else { + view + .background(Color(uiColor: .init(hex: viewModel.itemInfo.customization?.iconColor)).opacity(0.3)) + .clipShape(Circle()) + } + }) + .padding([.vertical, .trailing], DesignSystem.Spaces.half) } - private func makeStateImage(systemName: String) -> some View { - Image(systemName: systemName) + private func makeStateImage(systemName: SFSymbol) -> some View { + Image(systemSymbol: systemName) .font(.system(size: 24)) .foregroundStyle(.white) .padding() @@ -108,11 +128,11 @@ struct WatchMagicViewRow: View { } } - private var backgroundForWatchItem: Color { + private var backgroundForWatchItem: Color? { if let backgroundColor = viewModel.itemInfo.customization?.backgroundColor { Color(uiColor: .init(hex: backgroundColor)) } else { - .gray.opacity(0.3) + nil } } } diff --git a/Sources/Extensions/Watch/Home/MagicItemRow/WatchMagicViewRowViewModel.swift b/Sources/WatchApp/Home/MagicItemRow/WatchMagicViewRowViewModel.swift similarity index 100% rename from Sources/Extensions/Watch/Home/MagicItemRow/WatchMagicViewRowViewModel.swift rename to Sources/WatchApp/Home/MagicItemRow/WatchMagicViewRowViewModel.swift diff --git a/Sources/WatchApp/Home/WatchHomeView.swift b/Sources/WatchApp/Home/WatchHomeView.swift new file mode 100644 index 0000000000..14d78e657c --- /dev/null +++ b/Sources/WatchApp/Home/WatchHomeView.swift @@ -0,0 +1,272 @@ +import Shared +import SwiftUI + +struct WatchHomeView: View { + @Environment(\.scenePhase) private var scenePhase + @StateObject private var viewModel = WatchHomeViewModel() + @State private var showAssist = false + + var body: some View { + navigation + .onReceive(NotificationCenter.default.publisher(for: AssistDefaultComplication.launchNotification)) { _ in + showAssist = true + } + .fullScreenCover(isPresented: $showAssist, content: { + WatchAssistView.build( + serverId: viewModel.watchConfig.assist.serverId, + pipelineId: viewModel.watchConfig.assist.pipelineId + ) + }) + .onAppear { + Task { + await viewModel.fetchNetworkInfo() + viewModel.initialRoutine() + } + } + .onChange(of: scenePhase) { newValue in + switch newValue { + case .active: + Task { + await viewModel.fetchNetworkInfo() + } + case .background: + break + case .inactive: + break + @unknown default: + break + } + } + } + + @ViewBuilder + private var navigation: some View { + if #available(watchOS 10, *) { + watchOS10Content + } else { + olderWatchOSContent + } + } + + @available(watchOS 10, *) + private var watchOS10Content: some View { + NavigationStack { + content + .persistentSystemOverlays(.hidden) + .toolbar { + reloadToolbarButton + if viewModel.showAssist { + assistToolbarButton + } + if viewModel.isLoading { + toolbarLoadingState + } + } + } + } + + private var olderWatchOSContent: some View { + NavigationView { + content + } + } + + @ViewBuilder + private var content: some View { + List { + inlineLoader + listContent + footer + } + .id(viewModel.refreshListID) + .navigationTitle("") + } + + @ViewBuilder + private var listContent: some View { + if viewModel.watchConfig.items.isEmpty { + Text(verbatim: L10n.Watch.Labels.noConfig) + .font(.footnote) + } else { + mainContent + } + } + + @ViewBuilder + private var inlineReloadButton: some View { + if viewModel.watchConfig.items.isEmpty || viewModel.showError { + reloadButton + } + } + + @ViewBuilder + private var inlineLoader: some View { + // Loader is displayed in list when watchOS 10 is not available + if viewModel.isLoading, #unavailable(watchOS 10.0) { + loadingState + .listRowBackground(Color.clear) + } + } + + @ViewBuilder + private var inlineError: some View { + if viewModel.showError { + Text(viewModel.errorMessage) + .font(.footnote) + .listRowBackground( + Color.red.opacity(0.5) + .clipShape(RoundedRectangle(cornerRadius: DesignSystem.CornerRadius.oneAndHalf)) + ) + } + } + + @ViewBuilder + private var mainContent: some View { + assistButtonForOlderDevices + ForEach(viewModel.watchConfig.items, id: \.serverUniqueId) { item in + WatchMagicViewRow( + item: item, + itemInfo: viewModel.info(for: item) + ) + } + reloadButton + } + + @available(watchOS 10, *) + private var reloadToolbarButton: some ToolbarContent { + ToolbarItem(placement: .topBarLeading) { + navReloadButton + } + } + + @available(watchOS 10, *) + private var assistToolbarButton: some ToolbarContent { + ToolbarItem(placement: .topBarTrailing) { + assistButton + .modify { view in + if #available(watchOS 11, *) { + view.handGestureShortcut(.primaryAction) + } else { + view + } + } + } + } + + private var assistButton: some View { + Button(action: { + showAssist = true + }, label: { + let color: UIColor = { + if #available(watchOS 26.0, *) { + return .white + } else { + return UIColor(Color.haPrimary) + } + }() + Image(uiImage: MaterialDesignIcons.messageProcessingOutlineIcon.image( + ofSize: .init(width: 24, height: 24), + color: color + )) + }) + .modify { view in + if #available(watchOS 26.0, *) { + view + .tint(.haPrimary) + } else { + view + } + } + } + + @available(watchOS 10, *) + private var navReloadButton: some View { + Button { + viewModel.requestConfig() + } label: { + Image(systemSymbol: .arrowCirclepath) + } + } + + @available(watchOS 10, *) + private var toolbarLoadingState: some ToolbarContent { + ToolbarItem(placement: .bottomBar) { + loadingState + .modify { view in + if #available(watchOS 26.0, *) { + view + .glassEffect(in: .circle) + } else { + view + .padding() + .background(.black) + } + } + } + } + + private var loadingState: some View { + ProgressView() + .progressViewStyle(.circular) + } + + private var footer: some View { + VStack(spacing: .zero) { + appVersion + ssidLabel + } + .listRowBackground(Color.clear) + } + + private var appVersion: some View { + Text(verbatim: AppConstants.version) + .listRowBackground(Color.clear) + .foregroundStyle(.secondary) + .frame(maxWidth: .infinity, alignment: .center) + } + + @ViewBuilder + private var ssidLabel: some View { + if !viewModel.currentSSID.isEmpty { + Label { + Text(verbatim: viewModel.currentSSID) + .minimumScaleFactor(0.5) + } icon: { + Image(systemSymbol: .wifi) + } + .font(DesignSystem.Font.caption2) + .foregroundStyle(.secondary.opacity(0.5)) + } + } + + @ViewBuilder + private var reloadButton: some View { + // When watchOS 10 is available, reload is on toolbar + if #unavailable(watchOS 10.0) { + Button { + viewModel.requestConfig() + } label: { + Group { + if #available(watchOS 10.0, *) { + Label(L10n.reloadLabel, systemSymbol: .arrowCirclepath) + } else { + Label(L10n.reloadLabel, systemSymbol: .arrowTriangle2CirclepathCircle) + } + } + .frame(maxWidth: .infinity, alignment: .center) + .font(.footnote) + } + .listRowBackground(Color.clear) + } + } + + @ViewBuilder + private var assistButtonForOlderDevices: some View { + if #unavailable(watchOS 10), + viewModel.watchConfig.assist.showAssist, + !viewModel.watchConfig.assist.serverId.isEmpty, + !viewModel.watchConfig.assist.pipelineId.isEmpty { + assistButton + } + } +} diff --git a/Sources/Extensions/Watch/Home/WatchHomeViewModel.swift b/Sources/WatchApp/Home/WatchHomeViewModel.swift similarity index 91% rename from Sources/Extensions/Watch/Home/WatchHomeViewModel.swift rename to Sources/WatchApp/Home/WatchHomeViewModel.swift index d30222b9c4..c7920504f2 100644 --- a/Sources/Extensions/Watch/Home/WatchHomeViewModel.swift +++ b/Sources/WatchApp/Home/WatchHomeViewModel.swift @@ -16,6 +16,7 @@ final class WatchHomeViewModel: ObservableObject { @Published var showAssist = false @Published var showError = false @Published var errorMessage = "" + @Published var currentSSID: String = "" @Published private(set) var homeType: WatchHomeType = .undefined @Published var watchConfig: WatchConfig = .init() @@ -25,15 +26,18 @@ final class WatchHomeViewModel: ObservableObject { // are different, the list won't refresh. This is a workaround to force a refresh @Published var refreshListID: UUID = .init() - func fetchNetworkInfo(completion: (() -> Void)? = nil) { - NEHotspotNetwork.fetchCurrent { hotspotNetwork in - WatchUserDefaults.shared.set(hotspotNetwork?.ssid, key: .watchSSID) - completion?() - } + @MainActor + func fetchNetworkInfo() async { + let networkInformation = await Current.networkInformation + WatchUserDefaults.shared.set(networkInformation?.ssid, key: .watchSSID) + currentSSID = networkInformation?.ssid ?? "" } @MainActor func initialRoutine() { + // First display whatever is in cache + loadCache() + // Now fetch new data in the background (shows loading indicator only for this fetch) isLoading = true requestConfig() } @@ -41,12 +45,12 @@ final class WatchHomeViewModel: ObservableObject { @MainActor func requestConfig() { homeType = .undefined - isLoading = true guard Communicator.shared.currentReachability != .notReachable else { Current.Log.error("iPhone reachability is not immediate reachable") loadCache() return } + isLoading = true Communicator.shared.send(.init( identifier: InteractiveImmediateMessages.watchConfig.rawValue, reply: { [weak self] message in @@ -55,6 +59,16 @@ final class WatchHomeViewModel: ObservableObject { )) } + func info(for magicItem: MagicItem) -> MagicItem.Info { + magicItemsInfo.first(where: { + $0.id == magicItem.serverUniqueId + }) ?? .init( + id: magicItem.id, + name: magicItem.id, + iconName: "" + ) + } + @MainActor private func handleMessageResponse(_ message: ImmediateMessage) { switch message.identifier { diff --git a/Sources/WatchApp/Info.plist b/Sources/WatchApp/Info.plist index 7a71e47eaf..dfc3864a5c 100644 --- a/Sources/WatchApp/Info.plist +++ b/Sources/WatchApp/Info.plist @@ -20,14 +20,42 @@ $(MARKETING_VERSION) CFBundleVersion $(CURRENT_PROJECT_VERSION) + CLKComplicationPrincipalClass + $(PRODUCT_MODULE_NAME).ComplicationController + CLKComplicationSupportedFamilies + + CLKComplicationFamilyModularSmall + CLKComplicationFamilyModularLarge + CLKComplicationFamilyUtilitarianSmall + CLKComplicationFamilyUtilitarianSmallFlat + CLKComplicationFamilyUtilitarianLarge + CLKComplicationFamilyCircularSmall + CLKComplicationFamilyExtraLarge + CLKComplicationFamilyGraphicCorner + CLKComplicationFamilyGraphicBezel + CLKComplicationFamilyGraphicCircular + CLKComplicationFamilyGraphicRectangular + + NSAppTransportSecurity + + NSAllowsArbitraryLoads + + + UIBackgroundModes + + audio + location + remote-notification + voip + UISupportedInterfaceOrientations UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown + WKApplication + WKCompanionAppBundleIdentifier $(BUNDLE_ID_PREFIX).HomeAssistant$(BUNDLE_ID_SUFFIX) - WKWatchKitApp - diff --git a/Sources/Extensions/Watch/Notifications/DynamicNotificationController.swift b/Sources/WatchApp/Notifications/DynamicNotificationController.swift similarity index 100% rename from Sources/Extensions/Watch/Notifications/DynamicNotificationController.swift rename to Sources/WatchApp/Notifications/DynamicNotificationController.swift diff --git a/Sources/Extensions/Watch/Notifications/NotificationSubController.swift b/Sources/WatchApp/Notifications/NotificationSubController.swift similarity index 100% rename from Sources/Extensions/Watch/Notifications/NotificationSubController.swift rename to Sources/WatchApp/Notifications/NotificationSubController.swift diff --git a/Sources/Extensions/Watch/Notifications/NotificationSubControllerMJPEG.swift b/Sources/WatchApp/Notifications/NotificationSubControllerMJPEG.swift similarity index 100% rename from Sources/Extensions/Watch/Notifications/NotificationSubControllerMJPEG.swift rename to Sources/WatchApp/Notifications/NotificationSubControllerMJPEG.swift diff --git a/Sources/Extensions/Watch/Notifications/NotificationSubControllerMap.swift b/Sources/WatchApp/Notifications/NotificationSubControllerMap.swift similarity index 100% rename from Sources/Extensions/Watch/Notifications/NotificationSubControllerMap.swift rename to Sources/WatchApp/Notifications/NotificationSubControllerMap.swift diff --git a/Sources/Extensions/Watch/Notifications/NotificationSubControllerMedia.swift b/Sources/WatchApp/Notifications/NotificationSubControllerMedia.swift similarity index 100% rename from Sources/Extensions/Watch/Notifications/NotificationSubControllerMedia.swift rename to Sources/WatchApp/Notifications/NotificationSubControllerMedia.swift diff --git a/Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json b/Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json similarity index 100% rename from Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json rename to Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Circular.imageset/Contents.json diff --git a/Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Contents.json b/Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Contents.json similarity index 100% rename from Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Contents.json rename to Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Contents.json diff --git a/Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json b/Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json similarity index 100% rename from Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json rename to Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Extra Large.imageset/Contents.json diff --git a/Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json b/Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json similarity index 100% rename from Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json rename to Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Graphic Bezel.imageset/Contents.json diff --git a/Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json b/Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json similarity index 100% rename from Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json rename to Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Graphic Circular.imageset/Contents.json diff --git a/Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json b/Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json similarity index 100% rename from Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json rename to Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Graphic Corner.imageset/Contents.json diff --git a/Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json b/Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json similarity index 100% rename from Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json rename to Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Graphic Extra Large.imageset/Contents.json diff --git a/Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json b/Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json similarity index 100% rename from Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json rename to Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Graphic Large Rectangular.imageset/Contents.json diff --git a/Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json b/Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json similarity index 100% rename from Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json rename to Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Modular.imageset/Contents.json diff --git a/Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json b/Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json similarity index 100% rename from Sources/Extensions/Watch/Resources/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json rename to Sources/WatchApp/Resources/Assets.xcassets/Complication.complicationset/Utilitarian.imageset/Contents.json diff --git a/Sources/Extensions/Watch/Resources/Assets.xcassets/Contents.json b/Sources/WatchApp/Resources/Assets.xcassets/Contents.json similarity index 100% rename from Sources/Extensions/Watch/Resources/Assets.xcassets/Contents.json rename to Sources/WatchApp/Resources/Assets.xcassets/Contents.json diff --git a/Sources/Extensions/Watch/Resources/Assets.xcassets/RoundLogo.imageset/Contents.json b/Sources/WatchApp/Resources/Assets.xcassets/RoundLogo.imageset/Contents.json similarity index 100% rename from Sources/Extensions/Watch/Resources/Assets.xcassets/RoundLogo.imageset/Contents.json rename to Sources/WatchApp/Resources/Assets.xcassets/RoundLogo.imageset/Contents.json diff --git a/Sources/Extensions/Watch/Resources/Assets.xcassets/RoundLogo.imageset/ha-logo-watch.png b/Sources/WatchApp/Resources/Assets.xcassets/RoundLogo.imageset/ha-logo-watch.png similarity index 100% rename from Sources/Extensions/Watch/Resources/Assets.xcassets/RoundLogo.imageset/ha-logo-watch.png rename to Sources/WatchApp/Resources/Assets.xcassets/RoundLogo.imageset/ha-logo-watch.png diff --git a/Sources/Extensions/Watch/Resources/Assets.xcassets/TemplateLogo.imageset/Contents.json b/Sources/WatchApp/Resources/Assets.xcassets/TemplateLogo.imageset/Contents.json similarity index 100% rename from Sources/Extensions/Watch/Resources/Assets.xcassets/TemplateLogo.imageset/Contents.json rename to Sources/WatchApp/Resources/Assets.xcassets/TemplateLogo.imageset/Contents.json diff --git a/Sources/Extensions/Watch/Resources/Assets.xcassets/TemplateLogo.imageset/ha-logo-watch.png b/Sources/WatchApp/Resources/Assets.xcassets/TemplateLogo.imageset/ha-logo-watch.png similarity index 100% rename from Sources/Extensions/Watch/Resources/Assets.xcassets/TemplateLogo.imageset/ha-logo-watch.png rename to Sources/WatchApp/Resources/Assets.xcassets/TemplateLogo.imageset/ha-logo-watch.png diff --git a/Sources/Extensions/Watch/Resources/Info.plist b/Sources/WatchApp/Resources/Info.plist similarity index 100% rename from Sources/Extensions/Watch/Resources/Info.plist rename to Sources/WatchApp/Resources/Info.plist diff --git a/Sources/Extensions/Watch/Utilities/Date+ComplicationDivination.swift b/Sources/WatchApp/Utilities/Date+ComplicationDivination.swift similarity index 100% rename from Sources/Extensions/Watch/Utilities/Date+ComplicationDivination.swift rename to Sources/WatchApp/Utilities/Date+ComplicationDivination.swift diff --git a/Sources/Extensions/Watch/Utilities/WKInterfaceLabel+Additions.swift b/Sources/WatchApp/Utilities/WKInterfaceLabel+Additions.swift similarity index 100% rename from Sources/Extensions/Watch/Utilities/WKInterfaceLabel+Additions.swift rename to Sources/WatchApp/Utilities/WKInterfaceLabel+Additions.swift diff --git a/Sources/Extensions/Watch/WatchCommunicatorService.swift b/Sources/WatchApp/WatchCommunicatorService.swift similarity index 100% rename from Sources/Extensions/Watch/WatchCommunicatorService.swift rename to Sources/WatchApp/WatchCommunicatorService.swift diff --git a/Sources/WatchApp/WatchHostingController.swift b/Sources/WatchApp/WatchHostingController.swift new file mode 100644 index 0000000000..603ffa7ddb --- /dev/null +++ b/Sources/WatchApp/WatchHostingController.swift @@ -0,0 +1,14 @@ +import Foundation +import Shared +import SwiftUI + +final class WatchHostingController: WKHostingController { + override init() { + super.init() + MaterialDesignIcons.register() + } + + override var body: WatchHomeView { + WatchHomeView() + } +} diff --git a/Sources/WatchApp/WatchMain.swift b/Sources/WatchApp/WatchMain.swift new file mode 100644 index 0000000000..7783e46e23 --- /dev/null +++ b/Sources/WatchApp/WatchMain.swift @@ -0,0 +1,17 @@ +import Shared +import SwiftUI + +@main +struct WatchMain: App { + @WKApplicationDelegateAdaptor private var extensionDelegate: ExtensionDelegate + + init() { + MaterialDesignIcons.register() + } + + var body: some Scene { + WindowGroup { + WatchHomeView() + } + } +}