From 33e464eb0d33065b8e73754d3cfa8b4fcd928ff1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pantale=C3=A3o?= <5808343+bgoncal@users.noreply.github.com> Date: Wed, 29 Apr 2026 16:44:02 +0200 Subject: [PATCH 1/4] Remove legacy actions --- HomeAssistant.xcodeproj/project.pbxproj | 110 ++--- Sources/App/AppDelegate.swift | 1 - .../MagicItem/Add/MagicItemAddView.swift | 28 -- .../MagicItem/Add/MagicItemAddViewModel.swift | 14 - .../Observation/Action+Observation.swift | 51 --- .../Settings/ActionConfiguratorView.swift | 400 ------------------ .../Settings/ActionsSettingsView.swift | 262 ------------ .../Settings/ActionsSettingsViewModel.swift | 188 -------- .../App/Settings/Settings/SettingsItem.swift | 10 - .../App/Settings/Settings/SettingsView.swift | 9 - ...dgetActionsAppIntentTimelineProvider.swift | 134 ------ .../AppIntents/WidgetActionsAppIntent.swift | 52 --- .../Widgets/Actions/WidgetActions.swift | 95 ----- .../Actions/WidgetActionsProvider.swift | 51 --- Sources/Extensions/Widgets/Widgets.swift | 3 - 15 files changed, 35 insertions(+), 1373 deletions(-) delete mode 100644 Sources/App/Settings/Observation/Action+Observation.swift delete mode 100644 Sources/App/Settings/Settings/ActionConfiguratorView.swift delete mode 100644 Sources/App/Settings/Settings/ActionsSettingsView.swift delete mode 100644 Sources/App/Settings/Settings/ActionsSettingsViewModel.swift delete mode 100644 Sources/Extensions/AppIntents/Widget/Actions/WidgetActionsAppIntentTimelineProvider.swift delete mode 100644 Sources/Extensions/AppIntents/WidgetActionsAppIntent.swift delete mode 100644 Sources/Extensions/Widgets/Actions/WidgetActions.swift delete mode 100644 Sources/Extensions/Widgets/Actions/WidgetActionsProvider.swift diff --git a/HomeAssistant.xcodeproj/project.pbxproj b/HomeAssistant.xcodeproj/project.pbxproj index 9de8bdc51..07c1a5067 100644 --- a/HomeAssistant.xcodeproj/project.pbxproj +++ b/HomeAssistant.xcodeproj/project.pbxproj @@ -51,7 +51,6 @@ 110AA55C25B36630005061A0 /* ServerAlerter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110AA55B25B36630005061A0 /* ServerAlerter.swift */; }; 110AA55D25B36630005061A0 /* ServerAlerter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110AA55B25B36630005061A0 /* ServerAlerter.swift */; }; 110AA57B25B38C02005061A0 /* ServerAlerter.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110AA57A25B38C02005061A0 /* ServerAlerter.test.swift */; }; - 110E694424E77125004AA96D /* WidgetActionsProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110E694324E77125004AA96D /* WidgetActionsProvider.swift */; }; 110EC9FD251708D5009C9A1B /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03D891720E0A85200D4F28D /* Shared.framework */; }; 110EC9FE251708D5009C9A1B /* Shared.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = D03D891720E0A85200D4F28D /* Shared.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 110ED55425A5604F00489AF7 /* MacBridgeScreenImpl.swift in Sources */ = {isa = PBXBuildFile; fileRef = 110ED55325A5604F00489AF7 /* MacBridgeScreenImpl.swift */; }; @@ -181,7 +180,6 @@ 1171507224DFCDEE0065E874 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 1171507124DFCDEE0065E874 /* Assets.xcassets */; }; 1171507624DFCDEE0065E874 /* HomeAssistant-Extensions-Widgets.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = 1171506924DFCDE60065E874 /* HomeAssistant-Extensions-Widgets.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; 1171507B24DFCE0D0065E874 /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03D891720E0A85200D4F28D /* Shared.framework */; }; - 1171508124DFCEC50065E874 /* WidgetActions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1171508024DFCEC50065E874 /* WidgetActions.swift */; }; 117318AB25199E1A0013E010 /* AppKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 117318AA25199E1A0013E010 /* AppKit.framework */; }; 117318AD25199E220013E010 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 117318AC25199E220013E010 /* Foundation.framework */; }; 11764A6C26817FC3007D47F3 /* UserDefaultsValueSync.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11764A6B26817FC3007D47F3 /* UserDefaultsValueSync.test.swift */; }; @@ -252,7 +250,6 @@ 11A48D7C24CA7D7F0021BDD9 /* NotificationAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DAC736215F06B100727D2A /* NotificationAction.swift */; }; 11A48D7D24CA7E4E0021BDD9 /* NotificationCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DAC734215F069300727D2A /* NotificationCategory.swift */; }; 11A48D7E24CA7E4E0021BDD9 /* NotificationCategory.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6DAC734215F069300727D2A /* NotificationCategory.swift */; }; - 11A48D7F24CA7E820021BDD9 /* Action+Observation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11EE9B5624C68F5700404AF8 /* Action+Observation.swift */; }; 11A48D8124CA8ADB0021BDD9 /* NotificationCategory+Observation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11A48D8024CA8ADB0021BDD9 /* NotificationCategory+Observation.swift */; }; 11A71C6B24A463FC00D9565F /* ZoneManagerState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11A71C6A24A463FC00D9565F /* ZoneManagerState.swift */; }; 11A71C6D24A4641600D9565F /* ZoneManagerEvent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 11A71C6C24A4641600D9565F /* ZoneManagerEvent.swift */; }; @@ -909,11 +906,8 @@ 42955C3C2F20E2E800E398E8 /* ConnectivityCheckView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 42955C382F20E2E800E398E8 /* ConnectivityCheckView.swift */; }; 4296C36D2B90DB640051B63C /* IntentActionAppEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4296C36B2B90DB630051B63C /* IntentActionAppEntity.swift */; }; 4296C36E2B90DB640051B63C /* PerformAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4296C36C2B90DB630051B63C /* PerformAction.swift */; }; - 4296C3762B91F0F50051B63C /* WidgetActionsAppIntentTimelineProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4296C3742B91F0860051B63C /* WidgetActionsAppIntentTimelineProvider.swift */; }; 4296C3772B91F26A0051B63C /* IntentActionAppEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4296C36B2B90DB630051B63C /* IntentActionAppEntity.swift */; }; 4296C3782B91F6260051B63C /* PerformAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4296C36C2B90DB630051B63C /* PerformAction.swift */; }; - 4296C37A2B9205450051B63C /* WidgetActionsAppIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4296C3792B9205450051B63C /* WidgetActionsAppIntent.swift */; }; - 4296C37B2B92054C0051B63C /* WidgetActionsAppIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4296C3792B9205450051B63C /* WidgetActionsAppIntent.swift */; }; 429764F62E93B21E004C26EE /* CircularGlassOrLegacyBackground.swift in Sources */ = {isa = PBXBuildFile; fileRef = 429764F52E93B21E004C26EE /* CircularGlassOrLegacyBackground.swift */; }; 4297ADA72C89C74A00790812 /* GRDB+Initialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4297ADA62C89C74A00790812 /* GRDB+Initialization.swift */; }; 4297ADA82C89C74A00790812 /* GRDB+Initialization.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4297ADA62C89C74A00790812 /* GRDB+Initialization.swift */; }; @@ -1237,7 +1231,7 @@ 651755E378F6F79AB401F05C /* AssistPipelineAddList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07701F2786F6D45E945CC1AA /* AssistPipelineAddList.swift */; }; 65286F3B745551AD4090EE6B /* Pods-iOS-SharedTesting-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4053903E4C54A6803204286E /* Pods-iOS-SharedTesting-metadata.plist */; }; 6596FA74E1A501276EA62D86 /* Pods_watchOS_Shared_watchOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD370D44DFFB906B05C3EB3A /* Pods_watchOS_Shared_watchOS.framework */; }; - 692BCBBA4EEEABCC76DBBECA /* GRDB+Initialization.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C50FA39BF16AD0BD782D0D7 /* GRDB+Initialization.test.swift */; }; + 692BCBBA4EEEABCC76DBBECA /* Database/GRDB+Initialization.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C50FA39BF16AD0BD782D0D7 /* Database/GRDB+Initialization.test.swift */; }; 6FCEBAA2C8E9C5403055E73D /* IntentFanEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E5E2F9F8F008EEA30C533FD /* IntentFanEntity.swift */; }; 70BD8A8EA1ABC5DC1F0A0D6E /* Pods_iOS_Shared_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C663B0750E0318469E7008C3 /* Pods_iOS_Shared_iOS.framework */; }; 71E0BF803A854C3B9F0CB726 /* HandlerLiveActivityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58D524991C142DBB38A1968 /* HandlerLiveActivityTests.swift */; }; @@ -1251,7 +1245,7 @@ 999549244371450BC98C700E /* Pods_iOS_Extensions_PushProvider.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 608CFDA223EBCDF01B946093 /* Pods_iOS_Extensions_PushProvider.framework */; }; 9D57ECBD5431BC00BDC16F1E /* NotificationActionEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F913E441276235B7A2D7B29 /* NotificationActionEditorView.swift */; }; A1619F1ED93FB8B0E7E53C38 /* KioskLifecycleBrightness.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373AE72CB925F044BAE18B62 /* KioskLifecycleBrightness.test.swift */; }; - A2F3A140CDD1EF1AEA6DFAB9 /* DatabaseTableProtocol.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC31518EE9DC9E065AC508D9 /* DatabaseTableProtocol.test.swift */; }; + A2F3A140CDD1EF1AEA6DFAB9 /* Database/DatabaseTableProtocol.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC31518EE9DC9E065AC508D9 /* Database/DatabaseTableProtocol.test.swift */; }; A596C4D1E125E6863C7D2034 /* ComplicationEditViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 512A72C5F1BCC979E74F7629 /* ComplicationEditViewModel.swift */; }; A5A3C1932BE1F4A40EA78754 /* Pods-iOS-Extensions-Matter-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = 392B0C44197C98E2653932A5 /* Pods-iOS-Extensions-Matter-metadata.plist */; }; A60E917B401A6D456F1DB630 /* ComplicationFamilySelectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1861EB0361816DC9260D1F5E /* ComplicationFamilySelectView.swift */; }; @@ -1263,8 +1257,6 @@ A95FDD162F6B8A3E008EF72F /* HALockScreenView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95FDD122F6B8A3E008EF72F /* HALockScreenView.swift */; }; A95FDD192F6B8A5B008EF72F /* LiveActivitySettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95FDD172F6B8A5B008EF72F /* LiveActivitySettingsView.swift */; }; AB3E076F146799C008ACB0EA /* Pods_iOS_Extensions_NotificationContent.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B7D8DAEFAD435091FDDD61E7 /* Pods_iOS_Extensions_NotificationContent.framework */; }; - AC710001000000000000AA01 /* ActionsSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC720001000000000000AA01 /* ActionsSettingsView.swift */; }; - AC710002000000000000AA01 /* ActionsSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AC720002000000000000AA01 /* ActionsSettingsViewModel.swift */; }; B60248001FBD343000998205 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = B60247FE1FBD343000998205 /* InfoPlist.strings */; }; B605C891226E9DAC00EF46DD /* Permissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B605C890226E9DAC00EF46DD /* Permissions.swift */; }; B60615BB1D1F117700249C11 /* MorganFreemanSounds.csv in Resources */ = {isa = PBXBuildFile; fileRef = B60614B51D1F117700249C11 /* MorganFreemanSounds.csv */; }; @@ -1483,7 +1475,6 @@ B6A258492232539900ADD202 /* WebhookUpdateLocation.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6A258472232539900ADD202 /* WebhookUpdateLocation.swift */; }; B6AAD7A41D827DD40090B220 /* NotificationService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6AAD7A31D827DD40090B220 /* NotificationService.swift */; }; B6AAD7A81D827DD40090B220 /* HomeAssistant-Extensions-NotificationService.appex in Embed App Extensions */ = {isa = PBXBuildFile; fileRef = B6AAD7A11D827DD40090B220 /* HomeAssistant-Extensions-NotificationService.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; - B6B2E6A5216ACE4400D39A26 /* ActionConfiguratorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B2E6A4216ACE4400D39A26 /* ActionConfiguratorView.swift */; }; B6B74CB6228397D100D58A68 /* WatchHelpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = B66D6B1F2227A2EA009D8B90 /* WatchHelpers.swift */; }; B6B74CB82283983300D58A68 /* WatchComplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B6B14E215B6866003DE2DD /* WatchComplication.swift */; }; B6B74CB92283983300D58A68 /* WatchComplication.swift in Sources */ = {isa = PBXBuildFile; fileRef = B6B6B14E215B6866003DE2DD /* WatchComplication.swift */; }; @@ -1510,7 +1501,7 @@ B6E42613215C4333007FEB7E /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03D891720E0A85200D4F28D /* Shared.framework */; }; BB77559927344584B2C0E987 /* OnboardingAuthError.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1A7DD090A1D41ADB9374E7A /* OnboardingAuthError.test.swift */; }; BD1044995DE13A04C0FA039A /* Pods_iOS_Extensions_Widgets.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D9C81015FD7A8FA8716E4F2 /* Pods_iOS_Extensions_Widgets.framework */; }; - BECCC152A4E3F69A8EF5A6F3 /* TableSchemaTests.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EE9A0E08E6FEBDDE425D0D4 /* TableSchemaTests.test.swift */; }; + BECCC152A4E3F69A8EF5A6F3 /* Database/TableSchemaTests.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EE9A0E08E6FEBDDE425D0D4 /* Database/TableSchemaTests.test.swift */; }; C10D762EFE08D347D0538339 /* Pods-iOS-Shared-iOS-Tests-Shared-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = B2F5238669D8A7416FBD2B55 /* Pods-iOS-Shared-iOS-Tests-Shared-metadata.plist */; }; C35621B95F7E4548BC8F6D75 /* FolderEditView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BECEB2525564358A124F818 /* FolderEditView.swift */; }; C3EB3740FA097F36D51F525E /* BarometerSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1396822195C7FF562AB891F2 /* BarometerSensor.swift */; }; @@ -1562,7 +1553,7 @@ D87EC7A89E0515C4CAB93220 /* BarometerSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1396822195C7FF562AB891F2 /* BarometerSensor.swift */; }; D8B4F2A61E9C73058AF2D49E /* KioskSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7A3E91F5B8D42A6E0F13B74 /* KioskSettingsViewModel.swift */; }; D9A6697AF4D05BB8DE822A54 /* Pods_iOS_Extensions_Share.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33CA7FF55788E7084DA5E4B3 /* Pods_iOS_Extensions_Share.framework */; }; - DA6F4C18D66EDBA5DCEAE833 /* DatabaseMigration.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892F0EF22A0B9F20AAEE4CCA /* DatabaseMigration.test.swift */; }; + DA6F4C18D66EDBA5DCEAE833 /* Database/DatabaseMigration.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892F0EF22A0B9F20AAEE4CCA /* Database/DatabaseMigration.test.swift */; }; DB54626ADCE0C32094C8C0B9 /* LoadingButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BFD0D30836C69840AB63A8A /* LoadingButton.swift */; }; DEFBE1A5E9A005B0A5392D27 /* KioskLocalization.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F4593A60DBF019E6C91AAA7 /* KioskLocalization.test.swift */; }; E3A02409794174F002C8BB4F /* IconSearchPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BC23DE131CA8813C2DBD657 /* IconSearchPicker.swift */; }; @@ -1891,7 +1882,6 @@ 1109F82324A25A41002590F2 /* SensorContainer.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SensorContainer.test.swift; sourceTree = ""; }; 110AA55B25B36630005061A0 /* ServerAlerter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerAlerter.swift; sourceTree = ""; }; 110AA57A25B38C02005061A0 /* ServerAlerter.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ServerAlerter.test.swift; sourceTree = ""; }; - 110E694324E77125004AA96D /* WidgetActionsProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetActionsProvider.swift; sourceTree = ""; }; 110E694524E771AB004AA96D /* Color+Hex.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Color+Hex.swift"; sourceTree = ""; }; 110ED55325A5604F00489AF7 /* MacBridgeScreenImpl.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MacBridgeScreenImpl.swift; sourceTree = ""; }; 110ED56225A563D600489AF7 /* DisplaySensor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisplaySensor.swift; sourceTree = ""; }; @@ -2025,7 +2015,6 @@ 1171506F24DFCDE60065E874 /* Widgets.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Widgets.swift; sourceTree = ""; }; 1171507124DFCDEE0065E874 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 1171507324DFCDEE0065E874 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 1171508024DFCEC50065E874 /* WidgetActions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetActions.swift; sourceTree = ""; }; 117318AA25199E1A0013E010 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk/System/Library/Frameworks/AppKit.framework; sourceTree = DEVELOPER_DIR; }; 117318AC25199E220013E010 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/MacOSX.platform/Developer/SDKs/MacOSX11.0.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; }; 11764A6B26817FC3007D47F3 /* UserDefaultsValueSync.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsValueSync.test.swift; sourceTree = ""; }; @@ -2181,7 +2170,6 @@ 11EE9B4B24C5181A00404AF8 /* ModelManager.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModelManager.test.swift; sourceTree = ""; }; 11EE9B4D24C6089800404AF8 /* RealmPersistable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealmPersistable.swift; sourceTree = ""; }; 11EE9B5324C62EB300404AF8 /* RealmScene.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RealmScene.swift; sourceTree = ""; }; - 11EE9B5624C68F5700404AF8 /* Action+Observation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Action+Observation.swift"; sourceTree = ""; }; 11EF62D924C3687D00BABB64 /* ZoneManagerRegionFilter.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZoneManagerRegionFilter.test.swift; sourceTree = ""; }; 11EFB44B29D89FD100CE4B05 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Intents.strings; sourceTree = ""; }; 11EFB44C29D89FD100CE4B05 /* hu */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = hu; path = hu.lproj/Frontend.strings; sourceTree = ""; }; @@ -2613,8 +2601,6 @@ 42955C382F20E2E800E398E8 /* ConnectivityCheckView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectivityCheckView.swift; sourceTree = ""; }; 4296C36B2B90DB630051B63C /* IntentActionAppEntity.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IntentActionAppEntity.swift; sourceTree = ""; }; 4296C36C2B90DB630051B63C /* PerformAction.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PerformAction.swift; sourceTree = ""; }; - 4296C3742B91F0860051B63C /* WidgetActionsAppIntentTimelineProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetActionsAppIntentTimelineProvider.swift; sourceTree = ""; }; - 4296C3792B9205450051B63C /* WidgetActionsAppIntent.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = WidgetActionsAppIntent.swift; path = Sources/Extensions/AppIntents/WidgetActionsAppIntent.swift; sourceTree = SOURCE_ROOT; }; 429764F52E93B21E004C26EE /* CircularGlassOrLegacyBackground.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CircularGlassOrLegacyBackground.swift; sourceTree = ""; }; 4297ADA42C89C43F00790812 /* AppEntitiesModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppEntitiesModel.swift; sourceTree = ""; }; 4297ADA62C89C74A00790812 /* GRDB+Initialization.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "GRDB+Initialization.swift"; sourceTree = ""; }; @@ -3054,7 +3040,7 @@ 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 = ""; }; 592EED7A6C2444872F11C17B /* Pods-iOS-Extensions-NotificationService-metadata.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "Pods-iOS-Extensions-NotificationService-metadata.plist"; path = "Pods/Pods-iOS-Extensions-NotificationService-metadata.plist"; sourceTree = ""; }; 5BFD0D30836C69840AB63A8A /* LoadingButton.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LoadingButton.swift; sourceTree = ""; }; - 5C50FA39BF16AD0BD782D0D7 /* GRDB+Initialization.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Database/GRDB+Initialization.test.swift"; sourceTree = ""; }; + 5C50FA39BF16AD0BD782D0D7 /* Database/GRDB+Initialization.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Database/GRDB+Initialization.test.swift"; sourceTree = ""; }; 5D4737412F241342009A70EA /* FolderDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderDetailView.swift; sourceTree = ""; }; 5E95733B72864AB3B9607B57 /* MockLiveActivityRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockLiveActivityRegistry.swift; sourceTree = ""; }; 5FF9C3A30E10A8E214623EBB /* ComplicationListView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ComplicationListView.swift; sourceTree = ""; }; @@ -3078,7 +3064,7 @@ 825E1E44BA9ABF1BF53733D3 /* KioskConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KioskConstants.swift; sourceTree = ""; }; 862436CFE6E3F4B31500EFB2 /* ComplicationListViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ComplicationListViewModel.swift; sourceTree = ""; }; 86BFD63671D2D0A012DFE169 /* Pods-iOS-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-App/Pods-iOS-App.debug.xcconfig"; sourceTree = ""; }; - 892F0EF22A0B9F20AAEE4CCA /* DatabaseMigration.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database/DatabaseMigration.test.swift; sourceTree = ""; }; + 892F0EF22A0B9F20AAEE4CCA /* Database/DatabaseMigration.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database/DatabaseMigration.test.swift; sourceTree = ""; }; 8A34A5417D650BBBE9D2D7C0 /* ControlFanValueProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlFanValueProvider.swift; sourceTree = ""; }; 8D6888525DCF492642BA7EA3 /* FanIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FanIntent.swift; sourceTree = ""; }; 9249824D575933DFA1530BB2 /* Pods-watchOS-WatchExtension-Watch-metadata.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "Pods-watchOS-WatchExtension-Watch-metadata.plist"; path = "Pods/Pods-watchOS-WatchExtension-Watch-metadata.plist"; sourceTree = ""; }; @@ -3091,7 +3077,7 @@ 9C4E5E27229D992A0044C8EC /* HomeAssistant.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = HomeAssistant.xcconfig; sourceTree = ""; }; 9D84964A844E6CD21F16D3AB /* Pods-watchOS-WatchExtension-Watch.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-watchOS-WatchExtension-Watch.debug.xcconfig"; path = "Pods/Target Support Files/Pods-watchOS-WatchExtension-Watch/Pods-watchOS-WatchExtension-Watch.debug.xcconfig"; sourceTree = ""; }; 9DA2D62699FC44A99AB37480 /* WatchFolderRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchFolderRow.swift; sourceTree = ""; }; - 9EE9A0E08E6FEBDDE425D0D4 /* TableSchemaTests.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database/TableSchemaTests.test.swift; sourceTree = ""; }; + 9EE9A0E08E6FEBDDE425D0D4 /* Database/TableSchemaTests.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database/TableSchemaTests.test.swift; sourceTree = ""; }; 9F913E441276235B7A2D7B29 /* NotificationActionEditorView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NotificationActionEditorView.swift; sourceTree = ""; }; 9F9398CFD66E4C66DC39E1D3 /* Pods-iOS-Extensions-PushProvider.beta.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-Extensions-PushProvider.beta.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-Extensions-PushProvider/Pods-iOS-Extensions-PushProvider.beta.xcconfig"; sourceTree = ""; }; A1A7DD090A1D41ADB9374E7A /* OnboardingAuthError.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingAuthError.test.swift; sourceTree = ""; }; @@ -3104,8 +3090,6 @@ A95FDD172F6B8A5B008EF72F /* LiveActivitySettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LiveActivitySettingsView.swift; sourceTree = ""; }; AA48C686F844D08C426A8D74 /* Pods_Tests_App.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Tests_App.framework; sourceTree = BUILT_PRODUCTS_DIR; }; AC24B1CAB85767B8171BB850 /* 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 = ""; }; - AC720001000000000000AA01 /* ActionsSettingsView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionsSettingsView.swift; sourceTree = ""; }; - AC720002000000000000AA01 /* ActionsSettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionsSettingsViewModel.swift; sourceTree = ""; }; 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 = ""; }; B26248E8DEAC8C13210A6587 /* Pods-iOS-Extensions-Widgets.beta.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-Extensions-Widgets.beta.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-Extensions-Widgets/Pods-iOS-Extensions-Widgets.beta.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 = ""; }; @@ -3370,7 +3354,6 @@ B6AAD7A31D827DD40090B220 /* NotificationService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationService.swift; sourceTree = ""; }; B6AAD7A51D827DD40090B220 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; B6B2E6A1216AC21400D39A26 /* Action.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Action.swift; sourceTree = ""; }; - B6B2E6A4216ACE4400D39A26 /* ActionConfiguratorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ActionConfiguratorView.swift; sourceTree = ""; }; B6B6B14B215B1E86003DE2DD /* CLKComplication+Strings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CLKComplication+Strings.swift"; sourceTree = ""; }; B6B6B14E215B6866003DE2DD /* WatchComplication.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchComplication.swift; sourceTree = ""; }; B6C0911E2151F90300A326DC /* LocationHistory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LocationHistory.swift; sourceTree = ""; }; @@ -3416,7 +3399,7 @@ B6FD0574228411B200AC45BA /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; B7D8DAEFAD435091FDDD61E7 /* Pods_iOS_Extensions_NotificationContent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iOS_Extensions_NotificationContent.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B833A17275EC47FA65A3235A /* YamlPreviewSection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = YamlPreviewSection.swift; sourceTree = ""; }; - BC31518EE9DC9E065AC508D9 /* DatabaseTableProtocol.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database/DatabaseTableProtocol.test.swift; sourceTree = ""; }; + BC31518EE9DC9E065AC508D9 /* Database/DatabaseTableProtocol.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database/DatabaseTableProtocol.test.swift; sourceTree = ""; }; BC9B77AAC44845DC9EE48759 /* Pods_iOS_Extensions_Intents.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iOS_Extensions_Intents.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BDC6ACBDCC2C47510C37E4C8 /* NotificationCategoryListView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NotificationCategoryListView.swift; sourceTree = ""; }; BEF9A7008EFA4A6FC9E02B5E /* 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 = ""; }; @@ -3690,15 +3673,6 @@ path = TestNotifications; sourceTree = ""; }; - 110E693E24E770BD004AA96D /* Actions */ = { - isa = PBXGroup; - children = ( - 1171508024DFCEC50065E874 /* WidgetActions.swift */, - 110E694324E77125004AA96D /* WidgetActionsProvider.swift */, - ); - path = Actions; - sourceTree = ""; - }; 1115018C2528411200DCFA94 /* Sources */ = { isa = PBXGroup; children = ( @@ -3925,7 +3899,6 @@ 3E02C0F82CAD9EC700102131 /* Sensor */, 42F958962BB4680100497981 /* Assist */, 115560DF27010D6700A8F818 /* Common */, - 110E693E24E770BD004AA96D /* Actions */, 115560EA27012ED000A8F818 /* OpenPage */, 1171508324DFCF960065E874 /* Resources */, 4289DDAC2C85D595003591C2 /* Scene */, @@ -4065,7 +4038,6 @@ 11AD2E2B2528FDEB00FBC437 /* Observation */ = { isa = PBXGroup; children = ( - 11EE9B5624C68F5700404AF8 /* Action+Observation.swift */, 11A48D8024CA8ADB0021BDD9 /* NotificationCategory+Observation.swift */, ); path = Observation; @@ -5423,7 +5395,6 @@ 42C0F7C52D4791E800BD5C76 /* StatePrecision.swift */, 3E02C0FA2CAD9EEB00102131 /* Sensor */, 420F53F02C4EA314003C8415 /* ReloadWidgetsAppIntent.swift */, - 4296C3732B91F0730051B63C /* Actions */, 403AE90A2C2E28A200D48147 /* Gauge */, 4080D5C02C319AF400099C88 /* Details */, 42D3E4B22C5D2BA400444BE6 /* Script */, @@ -5431,15 +5402,6 @@ path = Widget; sourceTree = ""; }; - 4296C3732B91F0730051B63C /* Actions */ = { - isa = PBXGroup; - children = ( - 4296C3792B9205450051B63C /* WidgetActionsAppIntent.swift */, - 4296C3742B91F0860051B63C /* WidgetActionsAppIntentTimelineProvider.swift */, - ); - path = Actions; - sourceTree = ""; - }; 429821122CD0DD71005ECD39 /* Bluetooth */ = { isa = PBXGroup; children = ( @@ -6244,9 +6206,6 @@ 42DF7DDD2EC53D50003F3C4A /* SettingsItem.swift */, 42DF7DDF2EC53D85003F3C4A /* ServersListView.swift */, 42DF7DE12EC53DBC003F3C4A /* HomeAssistantAccountRowView.swift */, - B6B2E6A4216ACE4400D39A26 /* ActionConfiguratorView.swift */, - AC720001000000000000AA01 /* ActionsSettingsView.swift */, - AC720002000000000000AA01 /* ActionsSettingsViewModel.swift */, ); path = Settings; sourceTree = ""; @@ -6929,7 +6888,6 @@ 421155222D354F3F00A71630 /* AppIcon.swift */, 42DF7DDC2EC53D42003F3C4A /* Settings */, B641BC1D1E2097EF002CCBC1 /* AboutView.swift */, - B641BC221E209CA9002CCBC1 /* HomeAssistantLogoView.xib */, 42B19BD02D4A358B00B3262B /* DebugView.swift */, 420C1BB32CF7DBF300AF22E7 /* ClientEventsLogView */, 420DBEXP2F10000000000005 /* DatabaseExplorer */, @@ -6988,8 +6946,6 @@ 11BD7B3C25B53D37001826F0 /* AppMacBridgeStatusItemConfiguration.swift */, B641BC241E20A17B002CCBC1 /* OpenInChromeController.swift */, B6E857A11CB1CCCC00F96925 /* Utils.swift */, - B68EDD08215F45EB00DD6B28 /* NotificationIdentifierEurekaRow.swift */, - B675ECC2221BB0E600C65D31 /* SearchPushRow.swift */, B6DA3C7222691A5000DE811C /* AKConverter.swift */, B605C890226E9DAC00EF46DD /* Permissions.swift */, 1100D51E2496F63400B1073C /* ThemeColors.swift */, @@ -7244,10 +7200,10 @@ 11CB98CC249E637300B05222 /* Version+HA.test.swift */, 11883CC424C12C8A0036A6C6 /* CLLocation+Extensions.test.swift */, 11883CC624C131EE0036A6C6 /* RealmZone.test.swift */, - 892F0EF22A0B9F20AAEE4CCA /* DatabaseMigration.test.swift */, - BC31518EE9DC9E065AC508D9 /* DatabaseTableProtocol.test.swift */, - 5C50FA39BF16AD0BD782D0D7 /* GRDB+Initialization.test.swift */, - 9EE9A0E08E6FEBDDE425D0D4 /* TableSchemaTests.test.swift */, + 892F0EF22A0B9F20AAEE4CCA /* Database/DatabaseMigration.test.swift */, + BC31518EE9DC9E065AC508D9 /* Database/DatabaseTableProtocol.test.swift */, + 5C50FA39BF16AD0BD782D0D7 /* Database/GRDB+Initialization.test.swift */, + 9EE9A0E08E6FEBDDE425D0D4 /* Database/TableSchemaTests.test.swift */, 11EE9B4B24C5181A00404AF8 /* ModelManager.test.swift */, 11BC9E5424FDB88200B9FBF7 /* ActiveStateManager.test.swift */, 1104FCCE253275CF00B8BE34 /* WatchBackgroundRefreshScheduler.test.swift */, @@ -7457,7 +7413,6 @@ 6BC23DE131CA8813C2DBD657 /* IconSearchPicker.swift */, 5BFD0D30836C69840AB63A8A /* LoadingButton.swift */, ); - name = Complications; path = Complications; sourceTree = ""; }; @@ -7477,7 +7432,6 @@ 99EC7EF1136575D0E7A17091 /* NotificationIdentifierField.swift */, 208A5362BE60377368ACB1D6 /* RealmResultsObserver.swift */, ); - name = Components; path = Components; sourceTree = ""; }; @@ -8135,7 +8089,7 @@ packageReferences = ( 420E64BB2D676B2400A31E86 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */, 42B89EA62E05CC54000224A2 /* XCRemoteSwiftPackageReference "WebRTC" */, - 42E00D0F2E1E7487006D140D /* XCLocalSwiftPackageReference "SharedPush" */, + 42E00D0F2E1E7487006D140D /* XCLocalSwiftPackageReference "Sources/SharedPush" */, 4237E6372E5333370023B673 /* XCRemoteSwiftPackageReference "ZIPFoundation" */, 42B18FD52F38CA2300A1537A /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, ); @@ -8663,10 +8617,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Tests-App/Pods-Tests-App-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Tests-App/Pods-Tests-App-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tests-App/Pods-Tests-App-frameworks.sh\"\n"; @@ -8804,10 +8762,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-iOS-App/Pods-iOS-App-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-iOS-App/Pods-iOS-App-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iOS-App/Pods-iOS-App-frameworks.sh\"\n"; @@ -8843,10 +8805,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-iOS-Shared-iOS-Tests-Shared/Pods-iOS-Shared-iOS-Tests-Shared-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-iOS-Shared-iOS-Tests-Shared/Pods-iOS-Shared-iOS-Tests-Shared-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iOS-Shared-iOS-Tests-Shared/Pods-iOS-Shared-iOS-Tests-Shared-frameworks.sh\"\n"; @@ -8946,10 +8912,14 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-watchOS-WatchExtension-Watch/Pods-watchOS-WatchExtension-Watch-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); + inputPaths = ( + ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-watchOS-WatchExtension-Watch/Pods-watchOS-WatchExtension-Watch-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); + outputPaths = ( + ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-watchOS-WatchExtension-Watch/Pods-watchOS-WatchExtension-Watch-frameworks.sh\"\n"; @@ -9055,11 +9025,9 @@ 420E2AE32C4746BB004921D8 /* WidgetBasicViewModel.swift in Sources */, 42A935A22C7FEBA100FCF504 /* ControlScript.swift in Sources */, 427647222C8F36DB0027B21F /* LightIntent.swift in Sources */, - 4296C3762B91F0F50051B63C /* WidgetActionsAppIntentTimelineProvider.swift in Sources */, 42F158482CA15FA7009C7201 /* SwitchIntent.swift in Sources */, 42C1012A2CD3DB8A0012BA78 /* CoverIntent.swift in Sources */, 426CBB6C2C9C550D003CA3AC /* IntentSwitchEntity.swift in Sources */, - 110E694424E77125004AA96D /* WidgetActionsProvider.swift in Sources */, A95FDD142F6B8A3E008EF72F /* HADynamicIslandView.swift in Sources */, A95FDD152F6B8A3E008EF72F /* HALiveActivityConfiguration.swift in Sources */, A95FDD162F6B8A3E008EF72F /* HALockScreenView.swift in Sources */, @@ -9133,7 +9101,6 @@ 420396482EF16A4700C9DF74 /* ControlOpenSwitch.swift in Sources */, 420396492EF16A4700C9DF74 /* ControlOpenSwitchValueProvider.swift in Sources */, 3E02C0E82CA7FCF400102131 /* WidgetSensors.swift in Sources */, - 1171508124DFCEC50065E874 /* WidgetActions.swift in Sources */, 4289DDB32C85D6B3003591C2 /* IntentSceneEntity.swift in Sources */, 3E4087EE2CE62B5A0085DF29 /* WidgetBasicViewProtocol.swift in Sources */, 42D3E4AE2C5D2AFA00444BE6 /* WidgetScripts.swift in Sources */, @@ -9152,7 +9119,6 @@ 3E02C0E32CA7FCBF00102131 /* IntentSensorsAppEntity.swift in Sources */, 4080D5BE2C319AA000099C88 /* WidgetDetailsView.swift in Sources */, 4080D5BF2C319AA000099C88 /* WidgetDetails.swift in Sources */, - 4296C37B2B92054C0051B63C /* WidgetActionsAppIntent.swift in Sources */, 424627342C98D8E900EF7B43 /* WidgetBasicViewTintedWrapper.swift in Sources */, 403AE9092C2E220200D48147 /* WidgetGauge.swift in Sources */, 42EF0ACE2D4CDC0C0088C91E /* ResetAllCustomWidgetConfirmationAppIntent.swift in Sources */, @@ -9266,7 +9232,6 @@ 4240DF472E1D148F00FB0DE6 /* DeviceNameView.swift in Sources */, 4210CD032F155C4500B71FB9 /* AssistConfiguration.swift in Sources */, 420E2AE62C474710004921D8 /* WidgetBasicButtonView.swift in Sources */, - 11A48D7F24CA7E820021BDD9 /* Action+Observation.swift in Sources */, 11195F6B267EFB1F003DF674 /* NotificationManagerLocalPushInterface.swift in Sources */, 1112AE9B25F71775007A541A /* LocationHistoryListView.swift in Sources */, 426EE49B2CA4194E00A5EF4F /* OnboardingWelcomeView.swift in Sources */, @@ -9385,9 +9350,6 @@ 42EF0ACD2D4CDC0C0088C91E /* ResetAllCustomWidgetConfirmationAppIntent.swift in Sources */, 423B5E0A2D6778370000CB95 /* WidgetBackground.swift in Sources */, 423B5E092D67781A0000CB95 /* WidgetBasicContainerView.swift in Sources */, - B6B2E6A5216ACE4400D39A26 /* ActionConfiguratorView.swift in Sources */, - AC710001000000000000AA01 /* ActionsSettingsView.swift in Sources */, - AC710002000000000000AA01 /* ActionsSettingsViewModel.swift in Sources */, 42EFFAEC2C8882DD002F10FC /* CarPlayConfigurationView.swift in Sources */, 425EB4FD2F5F0ACB0067A678 /* TTSVoicePickerView.swift in Sources */, 42FA833D2F4722D00050095A /* WebViewController+EmptyState.swift in Sources */, @@ -9514,7 +9476,6 @@ 117EBC32261D398B00F5334A /* ZoneManagerAccuracyFuzzer.swift in Sources */, 42A47A902C4548E100C9B43D /* ImprovDiscoverView.swift in Sources */, 113FB1132515A065000AC680 /* ScaleFactorMutator.swift in Sources */, - 4296C37A2B9205450051B63C /* WidgetActionsAppIntent.swift in Sources */, 428ED98B2E9E4FBF0019113B /* CheckmarkDrawOnView.swift in Sources */, 1185DFB3271FF53800ED7D9A /* OnboardingAuthStepSensors.swift in Sources */, 425573D12B5576E600145217 /* CarPlayDomainsListTemplate+Build.swift in Sources */, @@ -9536,7 +9497,6 @@ 42A47A852C45218D00C9B43D /* WebViewExternalMessageHandler.swift in Sources */, 42B19BD12D4A358B00B3262B /* DebugView.swift in Sources */, 4261EAA22F34F8C8002A7C85 /* WebViewController+ProtocolConformance.swift in Sources */, - 1164DA3225FBF5D600515E8A /* UITextView+CodeRow.swift in Sources */, 4245DC012EBA3DD3005E0E04 /* EntityPickerViewModel.swift in Sources */, 42FCCFE12B9B1B610057783F /* BarcodeScannerDataModel.swift in Sources */, 42D3E4B72C5D2C2700444BE6 /* WidgetScriptsAppIntent.swift in Sources */, @@ -10379,10 +10339,10 @@ 11AF4D2C249D965C006C74C0 /* BatterySensor.test.swift in Sources */, 11F2F2B8258728B200F61F7C /* NotificationAttachmentParserURL.test.swift in Sources */, 11883CC724C131EE0036A6C6 /* RealmZone.test.swift in Sources */, - DA6F4C18D66EDBA5DCEAE833 /* DatabaseMigration.test.swift in Sources */, - A2F3A140CDD1EF1AEA6DFAB9 /* DatabaseTableProtocol.test.swift in Sources */, - 692BCBBA4EEEABCC76DBBECA /* GRDB+Initialization.test.swift in Sources */, - BECCC152A4E3F69A8EF5A6F3 /* TableSchemaTests.test.swift in Sources */, + DA6F4C18D66EDBA5DCEAE833 /* Database/DatabaseMigration.test.swift in Sources */, + A2F3A140CDD1EF1AEA6DFAB9 /* Database/DatabaseTableProtocol.test.swift in Sources */, + 692BCBBA4EEEABCC76DBBECA /* Database/GRDB+Initialization.test.swift in Sources */, + BECCC152A4E3F69A8EF5A6F3 /* Database/TableSchemaTests.test.swift in Sources */, 11267D0925BBA9FE00F28E5C /* Updater.test.swift in Sources */, 11A3F08C24ECE88C0018D84F /* WebhookUpdateLocation.test.swift in Sources */, 42FDCA272F0C7EB900C92958 /* EntityRegistry.test.swift in Sources */, @@ -12263,7 +12223,7 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - 42E00D0F2E1E7487006D140D /* XCLocalSwiftPackageReference "SharedPush" */ = { + 42E00D0F2E1E7487006D140D /* XCLocalSwiftPackageReference "Sources/SharedPush" */ = { isa = XCLocalSwiftPackageReference; relativePath = Sources/SharedPush; }; @@ -12327,7 +12287,7 @@ }; 4273F7DF2E258827000629F7 /* SharedPush */ = { isa = XCSwiftPackageProductDependency; - package = 42E00D0F2E1E7487006D140D /* XCLocalSwiftPackageReference "SharedPush" */; + package = 42E00D0F2E1E7487006D140D /* XCLocalSwiftPackageReference "Sources/SharedPush" */; productName = SharedPush; }; 427692E22B98B82500F24321 /* SharedPush */ = { diff --git a/Sources/App/AppDelegate.swift b/Sources/App/AppDelegate.swift index de91440a1..8924ea225 100644 --- a/Sources/App/AppDelegate.swift +++ b/Sources/App/AppDelegate.swift @@ -418,7 +418,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { private func setupModels() { // Force Realm migration to happen now _ = Realm.live() - Action.setupObserver() NotificationCategory.setupObserver() } diff --git a/Sources/App/Settings/MagicItem/Add/MagicItemAddView.swift b/Sources/App/Settings/MagicItem/Add/MagicItemAddView.swift index 55445ed43..292bfaeec 100644 --- a/Sources/App/Settings/MagicItem/Add/MagicItemAddView.swift +++ b/Sources/App/Settings/MagicItem/Add/MagicItemAddView.swift @@ -13,7 +13,6 @@ struct MagicItemAddView: View { case entities case scripts case scenes - case legacyiOSActions case assistPipelines } @@ -41,7 +40,6 @@ struct MagicItemAddView: View { options.append(.scripts) options.append(.scenes) } - options.append(.legacyiOSActions) } if context == .carPlay, #available(iOS 26.0, *) { options.append(.assistPipelines) @@ -54,12 +52,6 @@ struct MagicItemAddView: View { NavigationView { Group { switch viewModel.selectedItemType { - case .actions: - List { - pickerView - actionsList - } - .searchable(text: $viewModel.searchText) case .entities: VStack { pickerView @@ -91,7 +83,6 @@ struct MagicItemAddView: View { } .onAppear { autoSelectItemType() - viewModel.loadContent() if viewModel.selectedServerId == nil { viewModel.selectedServerId = Current.servers.all.first?.identifier.rawValue @@ -127,9 +118,6 @@ struct MagicItemAddView: View { case .entities: Text(verbatim: L10n.MagicItem.ItemType.Entity.List.title) .tag(MagicItemAddType.entities) - case .legacyiOSActions: - Text(verbatim: L10n.MagicItem.ItemType.Action.List.title) - .tag(MagicItemAddType.actions) case .scripts: Text(verbatim: L10n.MagicItem.ItemType.Script.List.title) .tag(MagicItemAddType.scripts) @@ -158,22 +146,6 @@ struct MagicItemAddView: View { } } - @ViewBuilder - private var actionsList: some View { - actionsDeprecationDisclaimer - ForEach(viewModel.actions, id: \.ID) { action in - if visibleForSearch(title: action.Text, entityId: action.ID) { - Button(action: { - itemToAdd(.init(id: action.ID, serverId: action.serverIdentifier, type: .action)) - dismiss() - }, label: { - EntityRowView(optionalTitle: action.Text, accessoryImageSystemSymbol: .plusCircleFill) - }) - .tint(Color(uiColor: .label)) - } - } - } - private var actionsDeprecationDisclaimer: some View { Section { Button { diff --git a/Sources/App/Settings/MagicItem/Add/MagicItemAddViewModel.swift b/Sources/App/Settings/MagicItem/Add/MagicItemAddViewModel.swift index 2ddd14595..0f74cb8f5 100644 --- a/Sources/App/Settings/MagicItem/Add/MagicItemAddViewModel.swift +++ b/Sources/App/Settings/MagicItem/Add/MagicItemAddViewModel.swift @@ -7,7 +7,6 @@ import Shared enum MagicItemAddType { case scripts - case actions case scenes case entities case assistPipelines @@ -15,19 +14,6 @@ enum MagicItemAddType { final class MagicItemAddViewModel: ObservableObject { @Published var selectedItemType = MagicItemAddType.scripts - @Published var actions: [Action] = [] @Published var searchText: String = "" @Published var selectedServerId: String? - - @MainActor - func loadContent() { - loadActions() - } - - @MainActor - private func loadActions() { - actions = Current.realm().objects(Action.self) - .filter({ $0.Scene == nil }) - .sorted(by: { $0.Position < $1.Position }) - } } diff --git a/Sources/App/Settings/Observation/Action+Observation.swift b/Sources/App/Settings/Observation/Action+Observation.swift deleted file mode 100644 index 892685808..000000000 --- a/Sources/App/Settings/Observation/Action+Observation.swift +++ /dev/null @@ -1,51 +0,0 @@ -import Foundation -import PromiseKit -import RealmSwift -import Shared -#if !targetEnvironment(macCatalyst) -import NotificationCenter -#endif -import Intents -import WidgetKit - -extension Action { - static func setupObserver() { - let actions = Current.realm() - .objects(Action.self) - .sorted(byKeyPath: #keyPath(Action.Position)) - - Current.modelManager.observe(for: AnyRealmCollection(actions)) { collection in - let invalidateMenu = Promise { seal in - UIMenuSystem.main.setNeedsRebuild() - seal.fulfill(()) - } - - let updateShortcuts = Promise { seal in - if !Current.isCatalyst { - UIApplication.shared.shortcutItems = collection.map(\.uiShortcut) - } - seal.fulfill(()) - } - - let updateWidgetKitWidgets = Promise { seal in - WidgetCenter.shared.reloadTimelines(ofKind: WidgetsKind.actions.rawValue) - - seal.fulfill(()) - } - - let updateSuggestions = Promise { seal in - // if we ever want to start donating more than actions, this needs to be pulled out to a helper - let intents = collection.map { PerformActionIntent(action: $0) } - INVoiceShortcutCenter.shared.setShortcutSuggestions(Array(intents.map { .intent($0) })) - seal.fulfill(()) - } - - return when(resolved: [ - invalidateMenu, - updateShortcuts, - updateWidgetKitWidgets, - updateSuggestions, - ]).asVoid() - } - } -} diff --git a/Sources/App/Settings/Settings/ActionConfiguratorView.swift b/Sources/App/Settings/Settings/ActionConfiguratorView.swift deleted file mode 100644 index 407bf9cba..000000000 --- a/Sources/App/Settings/Settings/ActionConfiguratorView.swift +++ /dev/null @@ -1,400 +0,0 @@ -import PromiseKit -import RealmSwift -import Shared -import SwiftUI - -/// View model that holds the mutable fields of an `Action` being edited. -/// -/// Backing `Action` is a Realm `Object`, so we mirror its editable fields onto -/// `@Published` properties to make SwiftUI redraws reliable and keep Realm -/// writes out of the view body. -final class ActionConfiguratorViewModel: ObservableObject { - @Published var name: String - @Published var text: String - @Published var iconName: String - @Published var iconColor: String - @Published var textColor: String - @Published var backgroundColor: String - @Published var useCustomColors: Bool - @Published var serverIdentifier: String - - private let sourceAction: Action - let isNewAction: Bool - - var isServerControlled: Bool { sourceAction.isServerControlled } - var triggerType: Action.TriggerType { sourceAction.triggerType } - var showInWatch: Bool { sourceAction.showInWatch } - - init(action: Action?) { - if let action { - let copy = Action(value: action) - self.sourceAction = copy - self.isNewAction = false - } else { - let fresh = Action() - if let firstServer = Current.servers.all.first { - fresh.serverIdentifier = firstServer.identifier.rawValue - } - self.sourceAction = fresh - self.isNewAction = true - } - self.name = sourceAction.Name - self.text = sourceAction.Text - self.iconName = sourceAction.IconName - self.iconColor = sourceAction.IconColor - self.textColor = sourceAction.TextColor - self.backgroundColor = sourceAction.BackgroundColor - self.useCustomColors = sourceAction.useCustomColors - - // Fall back to the first available server if the stored identifier is empty - // or points to a server that no longer exists. Common for actions imported from - // older single-server installs. - let allServerIds = Set(Current.servers.all.map(\.identifier.rawValue)) - if sourceAction.serverIdentifier.isEmpty || !allServerIds.contains(sourceAction.serverIdentifier) { - self.serverIdentifier = Current.servers.all.first?.identifier.rawValue ?? sourceAction.serverIdentifier - } else { - self.serverIdentifier = sourceAction.serverIdentifier - } - } - - func canConfigure(_ keyPath: PartialKeyPath) -> Bool { - sourceAction.canConfigure(keyPath) - } - - /// Returns an unmanaged `Action` with the view model values applied. Safe to - /// hand to the `onSave` callback for Realm persistence. - func buildAction() -> Action { - let result = Action(value: sourceAction) - result.Name = name - result.Text = text - result.IconName = iconName - result.IconColor = iconColor - result.TextColor = textColor - result.BackgroundColor = backgroundColor - result.useCustomColors = useCustomColors - result.serverIdentifier = serverIdentifier - return result - } -} - -/// SwiftUI editor for a legacy `Action`. Replaces the Eureka-based `ActionConfigurator`. -/// -/// The caller is responsible for persisting the resulting `Action` to Realm when -/// `onSave` is invoked. -struct ActionConfiguratorView: View { - @StateObject private var viewModel: ActionConfiguratorViewModel - - @Environment(\.dismiss) private var dismiss - - private let onSave: (Action, _ openAutomationEditor: Bool) -> Void - - init( - action: Action?, - onSave: @escaping (Action, _ openAutomationEditor: Bool) -> Void - ) { - self._viewModel = StateObject(wrappedValue: ActionConfiguratorViewModel(action: action)) - self.onSave = onSave - } - - var body: some View { - Form { - previewSection - nameAndServerSection - textSection - visualsSection - customColorsSection - executeSection - } - .navigationTitle(title) - .navigationBarTitleDisplayMode(.inline) - .toolbar { - // `if` directly inside `.toolbar` requires iOS 16+ ToolbarContentBuilder. - // Move the conditional inside the item so it works on iOS 15 too. - ToolbarItem(placement: .primaryAction) { - if hasEditableFields { - Button(L10n.saveLabel) { - save(openAutomationEditor: false) - } - .disabled(!isValid) - } - } - } - } - - private var title: String { - if viewModel.name.isEmpty, viewModel.isNewAction { - return L10n.ActionsConfigurator.title - } - return viewModel.name - } - - private var isValid: Bool { - !viewModel.name.trimmingCharacters(in: .whitespaces).isEmpty - && !viewModel.text.trimmingCharacters(in: .whitespaces).isEmpty - } - - private var hasEditableFields: Bool { - viewModel.canConfigure(\Action.Name) - || viewModel.canConfigure(\Action.Text) - || viewModel.canConfigure(\Action.IconName) - || viewModel.canConfigure(\Action.IconColor) - || viewModel.canConfigure(\Action.TextColor) - || viewModel.canConfigure(\Action.BackgroundColor) - || viewModel.canConfigure(\Action.useCustomColors) - } - - // MARK: - Sections - - @ViewBuilder - private var previewSection: some View { - if viewModel.showInWatch { - Section { - WidgetPreviewView(viewModel: viewModel) - .listRowInsets(.init(top: 0, leading: 0, bottom: 0, trailing: 0)) - .listRowBackground(Color.clear) - } - } - } - - private var nameAndServerSection: some View { - Section { - LabeledField(title: L10n.ActionsConfigurator.Rows.Name.title) { - TextField(L10n.ActionsConfigurator.Rows.Name.title, text: $viewModel.name) - .disabled(!viewModel.canConfigure(\Action.Name)) - .multilineTextAlignment(.trailing) - } - - // When the action is server-controlled, Text isn't editable, but still display it here - // to match the old layout. - if !viewModel.canConfigure(\Action.Text), viewModel.isServerControlled { - LabeledField(title: L10n.ActionsConfigurator.Rows.Text.title) { - TextField(L10n.ActionsConfigurator.Rows.Text.title, text: $viewModel.text) - .disabled(true) - .multilineTextAlignment(.trailing) - } - } - - ActionServerPicker( - selectedServerId: $viewModel.serverIdentifier, - isDisabled: !viewModel.canConfigure(\Action.serverIdentifier) - ) - } - } - - @ViewBuilder - private var textSection: some View { - if viewModel.canConfigure(\Action.Text) { - Section { - LabeledField(title: L10n.ActionsConfigurator.Rows.Text.title) { - TextField(L10n.ActionsConfigurator.Rows.Text.title, text: $viewModel.text) - .multilineTextAlignment(.trailing) - } - } - } - } - - @ViewBuilder - private var visualsSection: some View { - let canConfigureIcon = viewModel.canConfigure(\Action.IconName) - let canConfigureIconColor = viewModel.canConfigure(\Action.IconColor) - - if !canConfigureIcon, !canConfigureIconColor { - Section { - switch viewModel.triggerType { - case .event: - Text(L10n.ActionsConfigurator.VisualSection.serverDefined) - .foregroundStyle(.secondary) - case .scene: - Text(L10n.ActionsConfigurator.VisualSection.sceneDefined) - .foregroundStyle(.secondary) - } - } - } else { - Section { - if canConfigureIcon { - iconPickerRow - } - if canConfigureIconColor { - ColorPicker( - L10n.ActionsConfigurator.Rows.IconColor.title, - selection: Binding( - get: { Color(hex: viewModel.iconColor) }, - set: { newColor in - viewModel.iconColor = newColor.hex() ?? viewModel.iconColor - } - ), - supportsOpacity: false - ) - } - } footer: { - if viewModel.triggerType == .scene { - Text(L10n.ActionsConfigurator.VisualSection.sceneHintFooter( - ListFormatter.localizedString(byJoining: ["text_color", "background_color", "icon_color"]) - )) - } - } - } - } - - @ViewBuilder - private var iconPickerRow: some View { - HStack { - Text(L10n.ActionsConfigurator.Rows.Icon.title) - Spacer() - IconPicker( - selectedIcon: Binding( - get: { MaterialDesignIcons(named: viewModel.iconName) }, - set: { newIcon in - if let newIcon { - viewModel.iconName = newIcon.name - } - } - ), - selectedColor: Binding( - get: { Color(hex: viewModel.iconColor) }, - set: { _ in /* no-op */ } - ) - ) - } - } - - @ViewBuilder - private var customColorsSection: some View { - let canConfigureTextColor = viewModel.canConfigure(\Action.TextColor) - let canConfigureBackgroundColor = viewModel.canConfigure(\Action.BackgroundColor) - let canConfigureUseCustom = viewModel.canConfigure(\Action.useCustomColors) - - if canConfigureUseCustom || canConfigureTextColor || canConfigureBackgroundColor { - Section { - Toggle(L10n.SettingsDetails.Actions.UseCustomColors.title, isOn: $viewModel.useCustomColors) - .disabled(!canConfigureUseCustom) - - if viewModel.useCustomColors { - if canConfigureTextColor { - ColorPicker( - L10n.ActionsConfigurator.Rows.TextColor.title, - selection: Binding( - get: { Color(hex: viewModel.textColor) }, - set: { newColor in - viewModel.textColor = newColor.hex() ?? viewModel.textColor - } - ), - supportsOpacity: false - ) - } - if canConfigureBackgroundColor { - ColorPicker( - L10n.ActionsConfigurator.Rows.BackgroundColor.title, - selection: Binding( - get: { Color(hex: viewModel.backgroundColor) }, - set: { newColor in - viewModel.backgroundColor = newColor.hex() ?? viewModel.backgroundColor - } - ), - supportsOpacity: false - ) - } - } - } - } - } - - private var executeSection: some View { - Section { - Button { - save(openAutomationEditor: true) - } label: { - Label( - L10n.ActionsConfigurator.Action.createAutomation, - systemSymbol: .arrowUpForwardSquare - ) - } - .disabled(!isValid) - } header: { - Text(L10n.ActionsConfigurator.Action.title) - } footer: { - Text(L10n.ActionsConfigurator.Action.footer) - } - } - - // MARK: - Save - - private func save(openAutomationEditor: Bool) { - guard isValid else { return } - onSave(viewModel.buildAction(), openAutomationEditor) - dismiss() - } -} - -// MARK: - Helpers - -private struct LabeledField: View { - let title: String - @ViewBuilder var content: () -> Content - - var body: some View { - HStack { - Text(title) - Spacer() - content() - } - } -} - -/// SwiftUI replacement for the Eureka `ServerSelectRow` that writes the chosen -/// server identifier into a binding. -struct ActionServerPicker: View { - @Binding var selectedServerId: String - let isDisabled: Bool - - @StateObject private var observer = ServersObserver() - - var body: some View { - Picker(L10n.Settings.ServerSelect.title, selection: $selectedServerId) { - ForEach(observer.servers, id: \.identifier) { server in - Text(server.info.name) - .tag(server.identifier.rawValue) - } - } - .pickerStyle(.menu) - .disabled(isDisabled) - } -} - -// MARK: - Widget Preview - -struct WidgetPreviewView: View { - @ObservedObject var viewModel: ActionConfiguratorViewModel - - var body: some View { - VStack { - WidgetBasicButtonView( - model: .init( - id: UUID().uuidString, - title: viewModel.text, - subtitle: nil, - interactionType: .widgetURL(URL(string: "homeassistant://perform_action")!), - icon: MaterialDesignIcons(named: viewModel.iconName), - textColor: Color(hex: viewModel.textColor), - iconColor: Color(hex: viewModel.iconColor), - backgroundColor: Color(hex: viewModel.backgroundColor), - useCustomColors: viewModel.useCustomColors - ), - sizeStyle: .compact, - tinted: false - ) - .padding() - .frame(width: 340, height: 100) - } - .frame(maxWidth: .infinity) - .background(Color(uiColor: .tertiarySystemGroupedBackground)) - } -} - -// MARK: - Previews - -#Preview { - NavigationView { - ActionConfiguratorView(action: nil, onSave: { _, _ in }) - } -} diff --git a/Sources/App/Settings/Settings/ActionsSettingsView.swift b/Sources/App/Settings/Settings/ActionsSettingsView.swift deleted file mode 100644 index 2f41274b6..000000000 --- a/Sources/App/Settings/Settings/ActionsSettingsView.swift +++ /dev/null @@ -1,262 +0,0 @@ -import PromiseKit -import RealmSwift -import Shared -import SwiftUI - -/// SwiftUI replacement for the legacy Eureka "Actions" settings screen. -/// -/// Displays: -/// - A disclaimer about legacy actions. -/// - The list of locally-created actions (reorderable / deletable). -/// - Scene actions (toggle + customize navigation). -/// - Server-controlled actions (read-only). -/// - A button to refresh server actions. -struct ActionsSettingsView: View { - @StateObject private var viewModel = ActionsSettingsViewModel() - - @State private var editingAction: Action? - - var body: some View { - List { - disclaimerSection - localActionsSection - serverActionsSection - serverUpdateSection - } - .listStyle(.insetGrouped) - .navigationTitle(L10n.SettingsDetails.LegacyActions.title) - .sheet(item: $editingAction) { action in - ActionEditorSheet(action: action, isNew: false) { updated, openAutomationEditor in - handleSheetSave(updated: updated, openAutomationEditor: openAutomationEditor) - } - } - } - - private var hasAnyEditableActions: Bool { - !viewModel.localActions.isEmpty - } - - // MARK: - Sections - - private var disclaimerSection: some View { - Section { - Text(L10n.LegacyActions.disclaimer) - .font(.footnote) - .foregroundStyle(.secondary) - } - } - - @ViewBuilder - private var localActionsSection: some View { - Section { - if !viewModel.localActions.isEmpty { - ForEach(viewModel.localActions) { snapshot in - Button { - if let loaded = viewModel.loadAction(id: snapshot.actionID) { - editingAction = loaded - } - } label: { - ActionRowView(snapshot: snapshot) - } - .buttonStyle(.plain) - } - .onDelete { indexSet in - viewModel.deleteLocalActions(at: indexSet) - } - .onMove { source, destination in - viewModel.moveLocalActions(from: source, to: destination) - } - } - } - } - - @ViewBuilder - private var serverActionsSection: some View { - Section { - if viewModel.serverActions.isEmpty { - Text(L10n.SettingsDetails.Actions.ActionsSynced.empty) - .foregroundStyle(.secondary) - } else { - ForEach(viewModel.serverActions) { snapshot in - Button { - if let loaded = viewModel.loadAction(id: snapshot.actionID) { - editingAction = loaded - } - } label: { - ActionRowView(snapshot: snapshot) - } - .buttonStyle(.plain) - } - } - } header: { - Text(L10n.SettingsDetails.Actions.ActionsSynced.header) - } footer: { - if viewModel.serverActions.isEmpty { - Text(L10n.SettingsDetails.Actions.ActionsSynced.footerNoActions) - } else { - Text(L10n.SettingsDetails.Actions.ActionsSynced.footer) - } - } - } - - private var serverUpdateSection: some View { - Section { - Button { - viewModel.refreshServerActions() - } label: { - HStack { - Text(L10n.SettingsDetails.Actions.ServerControlled.Update.title) - Spacer() - if viewModel.isRefreshing { - ProgressView() - } - } - } - .disabled(viewModel.isRefreshing) - } - } - - /// Mirrors the legacy `ActionConfigurator` "Create Automation" path: server-controlled - /// actions should never be persisted from this sheet (they're owned by the server), - /// even though the same callback funnels both Save and Create-Automation actions. - private func handleSheetSave(updated: Action, openAutomationEditor: Bool) { - if openAutomationEditor, updated.isServerControlled { - // Don't write back; just open the automation editor. - } else { - viewModel.save(action: updated) - } - if openAutomationEditor { - openAutomationEditorIfAvailable(for: updated) - } - } - - private func openAutomationEditorIfAvailable(for action: Action) { - Current.sceneManager.webViewWindowControllerPromise - .then(\.webViewControllerPromise) - .done { controller in - controller.openActionAutomationEditor(actionId: action.ID) - }.cauterize() - } -} - -// MARK: - Row views - -private struct ActionRowView: View { - let snapshot: ActionRowSnapshot - - var body: some View { - HStack(spacing: DesignSystem.Spaces.two) { - Image( - uiImage: MaterialDesignIcons(named: snapshot.iconName) - .image(ofSize: MaterialDesignIcons.settingsIconSize, color: .label) - ) - .renderingMode(.template) - VStack(alignment: .leading, spacing: 2) { - Text(snapshot.name) - .foregroundStyle(.primary) - Text(snapshot.text.isEmpty ? L10n.ActionsConfigurator.Rows.Text.title : snapshot.text) - .font(.footnote) - .foregroundStyle(.secondary) - } - Spacer() - Image(systemSymbol: .chevronRight) - .font(.caption) - .foregroundStyle(.tertiary) - } - .contentShape(Rectangle()) - } -} - -private struct SceneActionRowView: View { - let scene: ActionsSceneSnapshot - let onToggle: (Bool) -> Void - let onCustomize: () -> Void - - @State private var isEnabled: Bool - - init(scene: ActionsSceneSnapshot, onToggle: @escaping (Bool) -> Void, onCustomize: @escaping () -> Void) { - self.scene = scene - self.onToggle = onToggle - self.onCustomize = onCustomize - self._isEnabled = State(initialValue: scene.actionEnabled) - } - - var body: some View { - VStack(alignment: .leading, spacing: DesignSystem.Spaces.one) { - Toggle(isOn: Binding( - get: { isEnabled }, - set: { newValue in - isEnabled = newValue - onToggle(newValue) - } - )) { - HStack(spacing: DesignSystem.Spaces.two) { - if let iconName = scene.icon { - let icon = MaterialDesignIcons(serversideValueNamed: iconName) - Image(uiImage: icon.image( - ofSize: MaterialDesignIcons.settingsIconSize, - color: .label - )) - .renderingMode(.template) - } - Text(scene.name ?? scene.identifier) - } - } - if isEnabled { - Button(L10n.SettingsDetails.Actions.Scenes.customizeAction) { - onCustomize() - } - .font(.footnote) - } - } - // Keep local @State in sync with the upstream Realm-backed snapshot, otherwise - // an external change to `actionEnabled` (sync, another screen, etc.) would not - // update the toggle while the row is on screen. - .onChange(of: scene.actionEnabled) { newValue in - if newValue != isEnabled { - isEnabled = newValue - } - } - } -} - -// MARK: - Sheet wrapper - -private struct ActionEditorSheet: View { - @Environment(\.dismiss) private var dismiss - let action: Action - let isNew: Bool - let onSave: (Action, _ openAutomationEditor: Bool) -> Void - - var body: some View { - NavigationView { - ActionConfiguratorView(action: isNew ? nil : action) { updated, openAutomationEditor in - onSave(updated, openAutomationEditor) - } - .toolbar { - CloseButton { - dismiss() - } - } - } - .navigationViewStyle(.stack) - } -} - -// MARK: - Action Identifiable - -extension Action: @retroactive Identifiable { - // The compiler synthesises `typealias ID = String` from the `Identifiable` - // conformance, which lives on `Action` at module scope and shadows the - // stored `ID` property in *any* extension. The only way to disambiguate is - // `self.ID`. SwiftFormat's `--self init-only` rule strips that, so disable - // `redundantSelf` for the one line that needs the qualification. - // swiftformat:disable:next redundantSelf - public var id: String { self.ID } -} - -#Preview { - NavigationView { - ActionsSettingsView() - } -} diff --git a/Sources/App/Settings/Settings/ActionsSettingsViewModel.swift b/Sources/App/Settings/Settings/ActionsSettingsViewModel.swift deleted file mode 100644 index 3d11496df..000000000 --- a/Sources/App/Settings/Settings/ActionsSettingsViewModel.swift +++ /dev/null @@ -1,188 +0,0 @@ -import Foundation -import PromiseKit -import RealmSwift -import Shared - -/// Value-type snapshot of a scene for safe SwiftUI rendering. -struct ActionsSceneSnapshot: Identifiable, Equatable { - var id: String { identifier } - let identifier: String - let name: String? - let icon: String? - let actionEnabled: Bool -} - -/// Value-type snapshot of an `Action` row for safe SwiftUI rendering. -struct ActionRowSnapshot: Identifiable, Equatable { - var id: String { actionID } - let actionID: String - let name: String - let text: String - let iconName: String -} - -/// View model for `ActionsSettingsView`. -/// -/// Wraps Realm observation for `Action` and `RLMScene` results and exposes them -/// as `@Published` snapshot arrays so the SwiftUI view does not touch Realm -/// directly from its body. -final class ActionsSettingsViewModel: ObservableObject { - @Published private(set) var localActions: [ActionRowSnapshot] = [] - @Published private(set) var serverActions: [ActionRowSnapshot] = [] - @Published private(set) var scenes: [ActionsSceneSnapshot] = [] - @Published private(set) var isRefreshing: Bool = false - - private let realm: Realm - private var actionsToken: NotificationToken? - private var scenesToken: NotificationToken? - - init() { - self.realm = Current.realm() - setupObservers() - } - - deinit { - actionsToken?.invalidate() - scenesToken?.invalidate() - } - - // MARK: - Observation - - private func setupObservers() { - let actions = realm.objects(Action.self) - .sorted(byKeyPath: "Position") - .filter("Scene == nil") - - actionsToken = actions.observe { [weak self] _ in - self?.refresh(actions: actions) - } - refresh(actions: actions) - - let scenes = realm.objects(RLMScene.self) - .sorted(byKeyPath: RLMScene.positionKeyPath) - scenesToken = scenes.observe { [weak self] _ in - self?.refresh(scenes: scenes) - } - refresh(scenes: scenes) - } - - private func refresh(actions: Results) { - localActions = actions.filter("isServerControlled == false").map(Self.snapshot(from:)) - serverActions = actions.filter("isServerControlled == true").map(Self.snapshot(from:)) - } - - private static func snapshot(from action: Action) -> ActionRowSnapshot { - ActionRowSnapshot( - actionID: action.ID, - name: action.Name, - text: action.Text, - iconName: action.IconName - ) - } - - /// Loads an unmanaged copy of the managed `Action` with the given identifier, or - /// `nil` if it no longer exists (deleted concurrently). - func loadAction(id: String) -> Action? { - guard let stored = realm.object(ofType: Action.self, forPrimaryKey: id) else { return nil } - return Action(value: stored) - } - - private func refresh(scenes: Results) { - self.scenes = scenes.map { - ActionsSceneSnapshot( - identifier: $0.identifier, - name: $0.name, - icon: $0.icon, - actionEnabled: $0.actionEnabled - ) - } - } - - // MARK: - Mutations - - func save(action: Action) { - // For brand-new local actions (no managed copy yet) assign a position at the end of - // the current local list. Without this, the default `Position = 0` makes the new - // action sort to the top of the manual section once Realm publishes the change. - let isNewLocal = action.Scene == nil - && !action.isServerControlled - && realm.object(ofType: Action.self, forPrimaryKey: action.ID) == nil - if isNewLocal { - action.Position = Action.PositionOffset.manual.rawValue + localActions.count - } - realm.reentrantWrite { [realm] in - realm.add(action, update: .all) - }.done { [weak self] in - self?.updatePositions() - }.cauterize() - } - - func deleteLocalActions(at offsets: IndexSet) { - let ids = offsets.compactMap { index -> String? in - guard index < localActions.count else { return nil } - return localActions[index].actionID - } - guard !ids.isEmpty else { return } - realm.reentrantWrite { [realm] in - realm.delete(realm.objects(Action.self).filter("ID IN %@", ids)) - }.cauterize() - } - - func moveLocalActions(from source: IndexSet, to destination: Int) { - var reordered = localActions - reordered.move(fromOffsets: source, toOffset: destination) - localActions = reordered - - let ids = reordered.map(\.actionID) - realm.reentrantWrite { [realm] in - let stored = realm.objects(Action.self).filter("ID IN %@", ids) - for action in stored { - guard let newIndex = ids.firstIndex(of: action.ID) else { continue } - action.Position = Action.PositionOffset.manual.rawValue + newIndex - } - }.cauterize() - } - - func setSceneEnabled(_ sceneId: String, enabled: Bool) { - realm.reentrantWrite { [realm] in - guard let scene = realm.object(ofType: RLMScene.self, forPrimaryKey: sceneId) else { return } - scene.actionEnabled = enabled - }.cauterize() - } - - func firstAction(forSceneId sceneId: String) -> Action? { - guard let scene = realm.object(ofType: RLMScene.self, forPrimaryKey: sceneId) else { - return nil - } - return scene.actions.first.map { Action(value: $0) } - } - - func refreshServerActions() { - isRefreshing = true - let result = Current.modelManager.fetch() - result.pipe { [weak self] result in - DispatchQueue.main.async { - self?.isRefreshing = false - } - switch result { - case .fulfilled: - break - case let .rejected(error): - Current.Log.error("Failed to manually update server Actions: \(error.localizedDescription)") - } - } - } - - // MARK: - Helpers - - private func updatePositions() { - let ids = localActions.map(\.actionID) - realm.reentrantWrite { [realm] in - let stored = realm.objects(Action.self).filter("ID IN %@", ids) - for action in stored { - guard let newIndex = ids.firstIndex(of: action.ID) else { continue } - action.Position = Action.PositionOffset.manual.rawValue + newIndex - } - }.cauterize() - } -} diff --git a/Sources/App/Settings/Settings/SettingsItem.swift b/Sources/App/Settings/Settings/SettingsItem.swift index 0a42a97a9..1ba919b08 100644 --- a/Sources/App/Settings/Settings/SettingsItem.swift +++ b/Sources/App/Settings/Settings/SettingsItem.swift @@ -15,7 +15,6 @@ enum SettingsItem: String, Hashable, CaseIterable { case watch case carPlay case complications - case actions case help case privacy case debugging @@ -36,7 +35,6 @@ enum SettingsItem: String, Hashable, CaseIterable { case .watch: return L10n.Settings.DetailsSection.WatchRowConfiguration.title case .carPlay: return "CarPlay" case .complications: return L10n.Settings.DetailsSection.WatchRowComplications.title - case .actions: return L10n.SettingsDetails.LegacyActions.title case .help: return L10n.helpLabel case .privacy: return L10n.SettingsDetails.Privacy.title case .debugging: return L10n.Settings.Debugging.title @@ -73,8 +71,6 @@ enum SettingsItem: String, Hashable, CaseIterable { MaterialDesignIconsImage(icon: .carBackIcon, size: 24) case .complications: MaterialDesignIconsImage(icon: .chartDonutIcon, size: 24) - case .actions: - MaterialDesignIconsImage(icon: .gamepadVariantOutlineIcon, size: 24) case .help: MaterialDesignIconsImage(icon: .helpCircleOutlineIcon, size: 24) case .privacy: @@ -132,8 +128,6 @@ enum SettingsItem: String, Hashable, CaseIterable { CarPlayConfigurationView(needsNavigationController: false) case .complications: SettingsComplicationsView() - case .actions: - ActionsSettingsView() case .help: EmptyView() case .privacy: @@ -179,10 +173,6 @@ enum SettingsItem: String, Hashable, CaseIterable { [.carPlay] } - static var legacyItems: [SettingsItem] { - [.actions] - } - static var helpItems: [SettingsItem] { [.help, .privacy, .debugging] } diff --git a/Sources/App/Settings/Settings/SettingsView.swift b/Sources/App/Settings/Settings/SettingsView.swift index 3dc3fab58..48243feb0 100644 --- a/Sources/App/Settings/Settings/SettingsView.swift +++ b/Sources/App/Settings/Settings/SettingsView.swift @@ -152,15 +152,6 @@ struct SettingsView: View { } } - // Legacy section - Section { - ForEach(SettingsItem.legacyItems, id: \.self) { item in - NavigationLink(destination: item.destinationView) { - settingsItemLabel(item) - } - } - } - // Help section Section { ForEach(SettingsItem.helpItems, id: \.self) { item in diff --git a/Sources/Extensions/AppIntents/Widget/Actions/WidgetActionsAppIntentTimelineProvider.swift b/Sources/Extensions/AppIntents/Widget/Actions/WidgetActionsAppIntentTimelineProvider.swift deleted file mode 100644 index 0e436d5b6..000000000 --- a/Sources/Extensions/AppIntents/Widget/Actions/WidgetActionsAppIntentTimelineProvider.swift +++ /dev/null @@ -1,134 +0,0 @@ -import AppIntents -import RealmSwift -import Shared -import WidgetKit - -@available(iOS 17, *) -struct WidgetActionsAppIntentTimelineProvider: AppIntentTimelineProvider { - typealias Entry = WidgetActionsEntry - typealias Intent = WidgetActionsAppIntent - - func snapshot(for configuration: WidgetActionsAppIntent, in context: Context) async -> WidgetActionsEntry { - await withCheckedContinuation({ continuation in - Self.entry(for: configuration, in: context) { entries in - continuation.resume(returning: entries) - } - }) - } - - func timeline(for configuration: Intent, in context: Context) async -> Timeline { - let entries = await withCheckedContinuation({ continuation in - Self.entry(for: configuration, in: context) { entries in - continuation.resume(returning: entries) - } - }) - return .init( - entries: [entries], - policy: .after( - Current.date() - .addingTimeInterval(WidgetActionsDataSource.expiration.converted(to: .seconds).value) - ) - ) - } - - func placeholder(in context: Context) -> WidgetActionsEntry { - let count = WidgetFamilySizes.size(for: context.family) - let actions = stride(from: 0, to: count, by: 1).map { _ in - with(Action()) { - $0.Text = "Redacted Text" - $0.IconName = MaterialDesignIcons.bedEmptyIcon.name - } - } - - return WidgetActionsEntry(actions: actions) - } - - private static func entry(for configuration: Intent, in context: Context, completion: @escaping (Entry) -> Void) { - if !(configuration.actions?.isEmpty ?? true) { - var actions: [Action?] = [] - var intentActionCheckCount = 0 - configuration.actions?.forEach({ intentAction in - intentAction.asAction { action in - actions.append(action) - intentActionCheckCount += 1 - if intentActionCheckCount == (configuration.actions?.count ?? 0) { - completion(.init(actions: actions.compactMap({ $0 }))) - } - } - }) - } else { - defaultActions(in: context) { actions in - completion(.init(actions: actions)) - } - } - } - - private static func defaultActions(in context: Context, completion: @escaping ([Action]) -> Void) { - WidgetActionsDataSource.actions { allActions in - let maxCount = WidgetFamilySizes.size(for: context.family) - switch allActions.count { - case 0: - completion([]) - case ...maxCount: - completion(Array(allActions)) - default: - completion(Array(allActions[0 ..< maxCount])) - } - } - } -} - -@available(iOS 17, *) -extension IntentActionAppEntity { - func asAction(completion: @escaping (Action?) -> Void) { - guard id.isEmpty == false else { - completion(nil) - return - } - func getAction() -> Action? { - Current.realm(objectTypes: [Action.self, RLMScene.self]).object( - ofType: Action.self, - forPrimaryKey: id - ) - } - - /* - Workaround for iOS 18, - 'Realm accessed from incorrect thread.' if not called from main thread - while in iOS 17 it reports the same error if called in the main thread - */ - if #available(iOS 18, *) { - DispatchQueue.main.async { - completion(getAction()) - } - } else { - completion(getAction()) - } - } -} - -enum WidgetActionsDataSource { - static var expiration: Measurement { - .init(value: 24, unit: .hours) - } - - static func getActions() -> Results { - Current.realm(objectTypes: [Action.self, RLMScene.self]).objects(Action.self) - .sorted(byKeyPath: #keyPath(Action.Position)) - } - - static func actions(completion: @escaping (Results) -> Void) { - /* - Workaround for iOS 18, - 'Realm accessed from incorrect thread.' if not called from main thread - while in iOS 17 it reports the same error if called in the main thread - */ - if #available(iOS 18, *) { - DispatchQueue.main.async { - completion(getActions()) - } - } else { - completion(getActions()) - } - } -} diff --git a/Sources/Extensions/AppIntents/WidgetActionsAppIntent.swift b/Sources/Extensions/AppIntents/WidgetActionsAppIntent.swift deleted file mode 100644 index 15a1f4120..000000000 --- a/Sources/Extensions/AppIntents/WidgetActionsAppIntent.swift +++ /dev/null @@ -1,52 +0,0 @@ -import AppIntents -import Foundation -import Shared - -@available(iOS 17.0, macOS 14.0, watchOS 10.0, *) -struct WidgetActionsAppIntent: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedAppIntent { - static let intentClassName = "WidgetActionsIntent" - - static let title: LocalizedStringResource = .init("widgets.actions.title", defaultValue: "Actions") - static let description = IntentDescription( - .init("widgets.actions.description", defaultValue: "Perform Home Assistant actions.") - ) - - // ATTENTION: Unfortunately these sizes below can't be retrieved dynamically from widget family sizes. - // Check ``WidgetFamilySizes.swift`` as source of truth - @Parameter( - title: .init("widgets.actions.parameters.action", defaultValue: "Action"), - size: [ - .systemSmall: 3, - .systemMedium: 6, - .systemLarge: 12, - .systemExtraLarge: 20, - .accessoryInline: 1, - .accessoryCorner: 1, - .accessoryCircular: 1, - .accessoryRectangular: 2, - ] - ) - var actions: [IntentActionAppEntity]? - - static var parameterSummary: some ParameterSummary { - Summary() - } - - func perform() async throws -> some IntentResult { - await Current.connectivity.syncNetworkInformation() - guard let actions else { return .result() } - for action in actions { - let intent = PerformAction() - intent.action = action - let _ = try await intent.perform() - } - return .result() - } -} - -@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) -private extension IntentDialog { - static var actionsParameterConfiguration: Self { - .init(stringLiteral: L10n.AppIntents.WidgetAction.actionsParameterConfiguration) - } -} diff --git a/Sources/Extensions/Widgets/Actions/WidgetActions.swift b/Sources/Extensions/Widgets/Actions/WidgetActions.swift deleted file mode 100644 index 86ab9705e..000000000 --- a/Sources/Extensions/Widgets/Actions/WidgetActions.swift +++ /dev/null @@ -1,95 +0,0 @@ -import AppIntents -import Intents -import Shared -import SwiftUI -import WidgetKit - -@available(iOS 17, *) -struct WidgetActions: Widget { - var body: some WidgetConfiguration { - AppIntentConfiguration( - kind: WidgetsKind.actions.rawValue, - provider: WidgetActionsAppIntentTimelineProvider() - ) { timelineEntry in - WidgetBasicContainerView( - emptyViewGenerator: { - AnyView(WidgetEmptyView(message: L10n.Widgets.Actions.notConfigured)) - }, - contents: timelineEntry.actions.map { action in - WidgetBasicViewModel( - id: action.ID, - title: action.Text, - subtitle: nil, - interactionType: .appIntent(.action(id: action.ID, name: action.Name)), - icon: MaterialDesignIcons(serversideValueNamed: action.IconName), - textColor: .init(hex: action.TextColor), - iconColor: .init(hex: action.IconColor), - backgroundColor: .init(hex: action.BackgroundColor), - useCustomColors: action.useCustomColors - ) - }, - type: .button - ) - } - .contentMarginsDisabledIfAvailable() - .configurationDisplayName(L10n.Widgets.Actions.title) - .description(L10n.Widgets.Actions.description) - .supportedFamilies(WidgetActionSupportedFamilies.families) - } -} - -struct LegacyWidgetActions: Widget { - var body: some WidgetConfiguration { - IntentConfiguration( - kind: WidgetsKind.actions.rawValue, - intent: WidgetActionsIntent.self, - provider: WidgetActionsProvider(), - content: { - WidgetBasicContainerView( - emptyViewGenerator: { - AnyView(WidgetEmptyView(message: L10n.Widgets.Actions.notConfigured)) - }, - contents: $0.actions.map { action in - WidgetBasicViewModel( - id: action.ID, - title: action.Text, - subtitle: nil, - interactionType: .widgetURL(action.widgetLinkURL), - icon: MaterialDesignIcons(serversideValueNamed: action.IconName), - textColor: .init(hex: action.TextColor), - iconColor: .init(hex: action.IconColor), - backgroundColor: .init(hex: action.BackgroundColor), - useCustomColors: action.useCustomColors - ) - }, - type: .button - ) - } - ) - .contentMarginsDisabledIfAvailable() - .configurationDisplayName(L10n.Widgets.Actions.title) - .description(L10n.Widgets.Actions.description) - .supportedFamilies(WidgetActionSupportedFamilies.legacyFamilies) - .onBackgroundURLSessionEvents(matching: nil) { identifier, completion in - Current.webhooks.handleBackground(for: identifier, completionHandler: completion) - } - } -} - -enum WidgetActionSupportedFamilies { - @available(iOS 16.0, *) - static let families: [WidgetFamily] = [ - .systemSmall, - .systemMedium, - .systemLarge, - .systemExtraLarge, - .accessoryCircular, - ] - - static let legacyFamilies: [WidgetFamily] = [ - .systemSmall, - .systemMedium, - .systemLarge, - .systemExtraLarge, - ] -} diff --git a/Sources/Extensions/Widgets/Actions/WidgetActionsProvider.swift b/Sources/Extensions/Widgets/Actions/WidgetActionsProvider.swift deleted file mode 100644 index 7a0fdea46..000000000 --- a/Sources/Extensions/Widgets/Actions/WidgetActionsProvider.swift +++ /dev/null @@ -1,51 +0,0 @@ -import Shared -import WidgetKit - -struct WidgetActionsEntry: TimelineEntry { - var date = Date() - var actions: [Action] = [] -} - -struct WidgetActionsProvider: IntentTimelineProvider { - typealias Intent = WidgetActionsIntent - typealias Entry = WidgetActionsEntry - - func placeholder(in context: Context) -> WidgetActionsEntry { - let count = WidgetFamilySizes.size(for: context.family) - let actions = stride(from: 0, to: count, by: 1).map { _ in - with(Action()) { - $0.Text = "Redacted Text" - $0.IconName = MaterialDesignIcons.bedEmptyIcon.name - } - } - - return .init(actions: actions) - } - - private static func defaultActions(in context: Context) -> [Action] { - let allActions = WidgetActionsDataSource.getActions() - let maxCount = WidgetFamilySizes.size(for: context.family) - - switch allActions.count { - case 0: return [] - case ...maxCount: return Array(allActions) - default: return Array(allActions[0 ..< maxCount]) - } - } - - private static func entry(for configuration: Intent, in context: Context) -> Entry { - if let existing = configuration.actions?.compactMap({ $0.asAction() }), !existing.isEmpty { - return .init(actions: existing) - } else { - return .init(actions: Self.defaultActions(in: context)) - } - } - - func getSnapshot(for configuration: Intent, in context: Context, completion: @escaping (Entry) -> Void) { - completion(Self.entry(for: configuration, in: context)) - } - - func getTimeline(for configuration: Intent, in context: Context, completion: @escaping (Timeline) -> Void) { - completion(.init(entries: [Self.entry(for: configuration, in: context)], policy: .never)) - } -} diff --git a/Sources/Extensions/Widgets/Widgets.swift b/Sources/Extensions/Widgets/Widgets.swift index 10253bd9d..7277073e6 100644 --- a/Sources/Extensions/Widgets/Widgets.swift +++ b/Sources/Extensions/Widgets/Widgets.swift @@ -27,7 +27,6 @@ struct WidgetsBundleLegacy: WidgetBundle { } #endif WidgetAssist() - LegacyWidgetActions() WidgetOpenPage() } } @@ -51,7 +50,6 @@ struct WidgetsBundle17: WidgetBundle { WidgetTodoList() WidgetGauge() WidgetDetails() - WidgetActions() WidgetOpenPage() WidgetSensors() } @@ -100,7 +98,6 @@ struct WidgetsBundle18: WidgetBundle { WidgetGauge() WidgetDetails() WidgetSensors() - WidgetActions() WidgetOpenPage() } } From 204b90e58f0aa55efc88c27f41de270a0727c5d5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pantale=C3=A3o?= <5808343+bgoncal@users.noreply.github.com> Date: Wed, 29 Apr 2026 16:44:35 +0200 Subject: [PATCH 2/4] Update project.pbxproj --- HomeAssistant.xcodeproj/project.pbxproj | 54 +++++++++---------------- 1 file changed, 19 insertions(+), 35 deletions(-) diff --git a/HomeAssistant.xcodeproj/project.pbxproj b/HomeAssistant.xcodeproj/project.pbxproj index 07c1a5067..79a94d130 100644 --- a/HomeAssistant.xcodeproj/project.pbxproj +++ b/HomeAssistant.xcodeproj/project.pbxproj @@ -1231,7 +1231,7 @@ 651755E378F6F79AB401F05C /* AssistPipelineAddList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 07701F2786F6D45E945CC1AA /* AssistPipelineAddList.swift */; }; 65286F3B745551AD4090EE6B /* Pods-iOS-SharedTesting-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = 4053903E4C54A6803204286E /* Pods-iOS-SharedTesting-metadata.plist */; }; 6596FA74E1A501276EA62D86 /* Pods_watchOS_Shared_watchOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FD370D44DFFB906B05C3EB3A /* Pods_watchOS_Shared_watchOS.framework */; }; - 692BCBBA4EEEABCC76DBBECA /* Database/GRDB+Initialization.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C50FA39BF16AD0BD782D0D7 /* Database/GRDB+Initialization.test.swift */; }; + 692BCBBA4EEEABCC76DBBECA /* GRDB+Initialization.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5C50FA39BF16AD0BD782D0D7 /* GRDB+Initialization.test.swift */; }; 6FCEBAA2C8E9C5403055E73D /* IntentFanEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3E5E2F9F8F008EEA30C533FD /* IntentFanEntity.swift */; }; 70BD8A8EA1ABC5DC1F0A0D6E /* Pods_iOS_Shared_iOS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C663B0750E0318469E7008C3 /* Pods_iOS_Shared_iOS.framework */; }; 71E0BF803A854C3B9F0CB726 /* HandlerLiveActivityTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B58D524991C142DBB38A1968 /* HandlerLiveActivityTests.swift */; }; @@ -1245,7 +1245,7 @@ 999549244371450BC98C700E /* Pods_iOS_Extensions_PushProvider.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 608CFDA223EBCDF01B946093 /* Pods_iOS_Extensions_PushProvider.framework */; }; 9D57ECBD5431BC00BDC16F1E /* NotificationActionEditorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F913E441276235B7A2D7B29 /* NotificationActionEditorView.swift */; }; A1619F1ED93FB8B0E7E53C38 /* KioskLifecycleBrightness.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 373AE72CB925F044BAE18B62 /* KioskLifecycleBrightness.test.swift */; }; - A2F3A140CDD1EF1AEA6DFAB9 /* Database/DatabaseTableProtocol.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC31518EE9DC9E065AC508D9 /* Database/DatabaseTableProtocol.test.swift */; }; + A2F3A140CDD1EF1AEA6DFAB9 /* DatabaseTableProtocol.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = BC31518EE9DC9E065AC508D9 /* DatabaseTableProtocol.test.swift */; }; A596C4D1E125E6863C7D2034 /* ComplicationEditViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 512A72C5F1BCC979E74F7629 /* ComplicationEditViewModel.swift */; }; A5A3C1932BE1F4A40EA78754 /* Pods-iOS-Extensions-Matter-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = 392B0C44197C98E2653932A5 /* Pods-iOS-Extensions-Matter-metadata.plist */; }; A60E917B401A6D456F1DB630 /* ComplicationFamilySelectView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1861EB0361816DC9260D1F5E /* ComplicationFamilySelectView.swift */; }; @@ -1501,7 +1501,7 @@ B6E42613215C4333007FEB7E /* Shared.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D03D891720E0A85200D4F28D /* Shared.framework */; }; BB77559927344584B2C0E987 /* OnboardingAuthError.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = A1A7DD090A1D41ADB9374E7A /* OnboardingAuthError.test.swift */; }; BD1044995DE13A04C0FA039A /* Pods_iOS_Extensions_Widgets.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3D9C81015FD7A8FA8716E4F2 /* Pods_iOS_Extensions_Widgets.framework */; }; - BECCC152A4E3F69A8EF5A6F3 /* Database/TableSchemaTests.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EE9A0E08E6FEBDDE425D0D4 /* Database/TableSchemaTests.test.swift */; }; + BECCC152A4E3F69A8EF5A6F3 /* TableSchemaTests.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9EE9A0E08E6FEBDDE425D0D4 /* TableSchemaTests.test.swift */; }; C10D762EFE08D347D0538339 /* Pods-iOS-Shared-iOS-Tests-Shared-metadata.plist in Resources */ = {isa = PBXBuildFile; fileRef = B2F5238669D8A7416FBD2B55 /* Pods-iOS-Shared-iOS-Tests-Shared-metadata.plist */; }; C35621B95F7E4548BC8F6D75 /* FolderEditView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BECEB2525564358A124F818 /* FolderEditView.swift */; }; C3EB3740FA097F36D51F525E /* BarometerSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1396822195C7FF562AB891F2 /* BarometerSensor.swift */; }; @@ -1553,7 +1553,7 @@ D87EC7A89E0515C4CAB93220 /* BarometerSensor.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1396822195C7FF562AB891F2 /* BarometerSensor.swift */; }; D8B4F2A61E9C73058AF2D49E /* KioskSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = C7A3E91F5B8D42A6E0F13B74 /* KioskSettingsViewModel.swift */; }; D9A6697AF4D05BB8DE822A54 /* Pods_iOS_Extensions_Share.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 33CA7FF55788E7084DA5E4B3 /* Pods_iOS_Extensions_Share.framework */; }; - DA6F4C18D66EDBA5DCEAE833 /* Database/DatabaseMigration.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892F0EF22A0B9F20AAEE4CCA /* Database/DatabaseMigration.test.swift */; }; + DA6F4C18D66EDBA5DCEAE833 /* DatabaseMigration.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 892F0EF22A0B9F20AAEE4CCA /* DatabaseMigration.test.swift */; }; DB54626ADCE0C32094C8C0B9 /* LoadingButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5BFD0D30836C69840AB63A8A /* LoadingButton.swift */; }; DEFBE1A5E9A005B0A5392D27 /* KioskLocalization.test.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4F4593A60DBF019E6C91AAA7 /* KioskLocalization.test.swift */; }; E3A02409794174F002C8BB4F /* IconSearchPicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6BC23DE131CA8813C2DBD657 /* IconSearchPicker.swift */; }; @@ -3040,7 +3040,7 @@ 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 = ""; }; 592EED7A6C2444872F11C17B /* Pods-iOS-Extensions-NotificationService-metadata.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "Pods-iOS-Extensions-NotificationService-metadata.plist"; path = "Pods/Pods-iOS-Extensions-NotificationService-metadata.plist"; sourceTree = ""; }; 5BFD0D30836C69840AB63A8A /* LoadingButton.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = LoadingButton.swift; sourceTree = ""; }; - 5C50FA39BF16AD0BD782D0D7 /* Database/GRDB+Initialization.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Database/GRDB+Initialization.test.swift"; sourceTree = ""; }; + 5C50FA39BF16AD0BD782D0D7 /* GRDB+Initialization.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Database/GRDB+Initialization.test.swift"; sourceTree = ""; }; 5D4737412F241342009A70EA /* FolderDetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderDetailView.swift; sourceTree = ""; }; 5E95733B72864AB3B9607B57 /* MockLiveActivityRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MockLiveActivityRegistry.swift; sourceTree = ""; }; 5FF9C3A30E10A8E214623EBB /* ComplicationListView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ComplicationListView.swift; sourceTree = ""; }; @@ -3064,7 +3064,7 @@ 825E1E44BA9ABF1BF53733D3 /* KioskConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KioskConstants.swift; sourceTree = ""; }; 862436CFE6E3F4B31500EFB2 /* ComplicationListViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = ComplicationListViewModel.swift; sourceTree = ""; }; 86BFD63671D2D0A012DFE169 /* Pods-iOS-App.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-App.debug.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-App/Pods-iOS-App.debug.xcconfig"; sourceTree = ""; }; - 892F0EF22A0B9F20AAEE4CCA /* Database/DatabaseMigration.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database/DatabaseMigration.test.swift; sourceTree = ""; }; + 892F0EF22A0B9F20AAEE4CCA /* DatabaseMigration.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database/DatabaseMigration.test.swift; sourceTree = ""; }; 8A34A5417D650BBBE9D2D7C0 /* ControlFanValueProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ControlFanValueProvider.swift; sourceTree = ""; }; 8D6888525DCF492642BA7EA3 /* FanIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FanIntent.swift; sourceTree = ""; }; 9249824D575933DFA1530BB2 /* Pods-watchOS-WatchExtension-Watch-metadata.plist */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.plist.xml; name = "Pods-watchOS-WatchExtension-Watch-metadata.plist"; path = "Pods/Pods-watchOS-WatchExtension-Watch-metadata.plist"; sourceTree = ""; }; @@ -3077,7 +3077,7 @@ 9C4E5E27229D992A0044C8EC /* HomeAssistant.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = HomeAssistant.xcconfig; sourceTree = ""; }; 9D84964A844E6CD21F16D3AB /* Pods-watchOS-WatchExtension-Watch.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-watchOS-WatchExtension-Watch.debug.xcconfig"; path = "Pods/Target Support Files/Pods-watchOS-WatchExtension-Watch/Pods-watchOS-WatchExtension-Watch.debug.xcconfig"; sourceTree = ""; }; 9DA2D62699FC44A99AB37480 /* WatchFolderRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WatchFolderRow.swift; sourceTree = ""; }; - 9EE9A0E08E6FEBDDE425D0D4 /* Database/TableSchemaTests.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database/TableSchemaTests.test.swift; sourceTree = ""; }; + 9EE9A0E08E6FEBDDE425D0D4 /* TableSchemaTests.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database/TableSchemaTests.test.swift; sourceTree = ""; }; 9F913E441276235B7A2D7B29 /* NotificationActionEditorView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NotificationActionEditorView.swift; sourceTree = ""; }; 9F9398CFD66E4C66DC39E1D3 /* Pods-iOS-Extensions-PushProvider.beta.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-iOS-Extensions-PushProvider.beta.xcconfig"; path = "Pods/Target Support Files/Pods-iOS-Extensions-PushProvider/Pods-iOS-Extensions-PushProvider.beta.xcconfig"; sourceTree = ""; }; A1A7DD090A1D41ADB9374E7A /* OnboardingAuthError.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OnboardingAuthError.test.swift; sourceTree = ""; }; @@ -3399,7 +3399,7 @@ B6FD0574228411B200AC45BA /* ru */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ru; path = ru.lproj/Localizable.strings; sourceTree = ""; }; B7D8DAEFAD435091FDDD61E7 /* Pods_iOS_Extensions_NotificationContent.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iOS_Extensions_NotificationContent.framework; sourceTree = BUILT_PRODUCTS_DIR; }; B833A17275EC47FA65A3235A /* YamlPreviewSection.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = YamlPreviewSection.swift; sourceTree = ""; }; - BC31518EE9DC9E065AC508D9 /* Database/DatabaseTableProtocol.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database/DatabaseTableProtocol.test.swift; sourceTree = ""; }; + BC31518EE9DC9E065AC508D9 /* DatabaseTableProtocol.test.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Database/DatabaseTableProtocol.test.swift; sourceTree = ""; }; BC9B77AAC44845DC9EE48759 /* Pods_iOS_Extensions_Intents.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_iOS_Extensions_Intents.framework; sourceTree = BUILT_PRODUCTS_DIR; }; BDC6ACBDCC2C47510C37E4C8 /* NotificationCategoryListView.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = NotificationCategoryListView.swift; sourceTree = ""; }; BEF9A7008EFA4A6FC9E02B5E /* 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 = ""; }; @@ -7200,10 +7200,10 @@ 11CB98CC249E637300B05222 /* Version+HA.test.swift */, 11883CC424C12C8A0036A6C6 /* CLLocation+Extensions.test.swift */, 11883CC624C131EE0036A6C6 /* RealmZone.test.swift */, - 892F0EF22A0B9F20AAEE4CCA /* Database/DatabaseMigration.test.swift */, - BC31518EE9DC9E065AC508D9 /* Database/DatabaseTableProtocol.test.swift */, - 5C50FA39BF16AD0BD782D0D7 /* Database/GRDB+Initialization.test.swift */, - 9EE9A0E08E6FEBDDE425D0D4 /* Database/TableSchemaTests.test.swift */, + 892F0EF22A0B9F20AAEE4CCA /* DatabaseMigration.test.swift */, + BC31518EE9DC9E065AC508D9 /* DatabaseTableProtocol.test.swift */, + 5C50FA39BF16AD0BD782D0D7 /* GRDB+Initialization.test.swift */, + 9EE9A0E08E6FEBDDE425D0D4 /* TableSchemaTests.test.swift */, 11EE9B4B24C5181A00404AF8 /* ModelManager.test.swift */, 11BC9E5424FDB88200B9FBF7 /* ActiveStateManager.test.swift */, 1104FCCE253275CF00B8BE34 /* WatchBackgroundRefreshScheduler.test.swift */, @@ -8089,7 +8089,7 @@ packageReferences = ( 420E64BB2D676B2400A31E86 /* XCRemoteSwiftPackageReference "swift-snapshot-testing" */, 42B89EA62E05CC54000224A2 /* XCRemoteSwiftPackageReference "WebRTC" */, - 42E00D0F2E1E7487006D140D /* XCLocalSwiftPackageReference "Sources/SharedPush" */, + 42E00D0F2E1E7487006D140D /* XCLocalSwiftPackageReference "SharedPush" */, 4237E6372E5333370023B673 /* XCRemoteSwiftPackageReference "ZIPFoundation" */, 42B18FD52F38CA2300A1537A /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */, ); @@ -8617,14 +8617,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Tests-App/Pods-Tests-App-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-Tests-App/Pods-Tests-App-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Tests-App/Pods-Tests-App-frameworks.sh\"\n"; @@ -8762,14 +8758,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-iOS-App/Pods-iOS-App-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-iOS-App/Pods-iOS-App-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iOS-App/Pods-iOS-App-frameworks.sh\"\n"; @@ -8805,14 +8797,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-iOS-Shared-iOS-Tests-Shared/Pods-iOS-Shared-iOS-Tests-Shared-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-iOS-Shared-iOS-Tests-Shared/Pods-iOS-Shared-iOS-Tests-Shared-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-iOS-Shared-iOS-Tests-Shared/Pods-iOS-Shared-iOS-Tests-Shared-frameworks.sh\"\n"; @@ -8912,14 +8900,10 @@ inputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-watchOS-WatchExtension-Watch/Pods-watchOS-WatchExtension-Watch-frameworks-${CONFIGURATION}-input-files.xcfilelist", ); - inputPaths = ( - ); name = "[CP] Embed Pods Frameworks"; outputFileListPaths = ( "${PODS_ROOT}/Target Support Files/Pods-watchOS-WatchExtension-Watch/Pods-watchOS-WatchExtension-Watch-frameworks-${CONFIGURATION}-output-files.xcfilelist", ); - outputPaths = ( - ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-watchOS-WatchExtension-Watch/Pods-watchOS-WatchExtension-Watch-frameworks.sh\"\n"; @@ -10339,10 +10323,10 @@ 11AF4D2C249D965C006C74C0 /* BatterySensor.test.swift in Sources */, 11F2F2B8258728B200F61F7C /* NotificationAttachmentParserURL.test.swift in Sources */, 11883CC724C131EE0036A6C6 /* RealmZone.test.swift in Sources */, - DA6F4C18D66EDBA5DCEAE833 /* Database/DatabaseMigration.test.swift in Sources */, - A2F3A140CDD1EF1AEA6DFAB9 /* Database/DatabaseTableProtocol.test.swift in Sources */, - 692BCBBA4EEEABCC76DBBECA /* Database/GRDB+Initialization.test.swift in Sources */, - BECCC152A4E3F69A8EF5A6F3 /* Database/TableSchemaTests.test.swift in Sources */, + DA6F4C18D66EDBA5DCEAE833 /* DatabaseMigration.test.swift in Sources */, + A2F3A140CDD1EF1AEA6DFAB9 /* DatabaseTableProtocol.test.swift in Sources */, + 692BCBBA4EEEABCC76DBBECA /* GRDB+Initialization.test.swift in Sources */, + BECCC152A4E3F69A8EF5A6F3 /* TableSchemaTests.test.swift in Sources */, 11267D0925BBA9FE00F28E5C /* Updater.test.swift in Sources */, 11A3F08C24ECE88C0018D84F /* WebhookUpdateLocation.test.swift in Sources */, 42FDCA272F0C7EB900C92958 /* EntityRegistry.test.swift in Sources */, @@ -12223,7 +12207,7 @@ /* End XCConfigurationList section */ /* Begin XCLocalSwiftPackageReference section */ - 42E00D0F2E1E7487006D140D /* XCLocalSwiftPackageReference "Sources/SharedPush" */ = { + 42E00D0F2E1E7487006D140D /* XCLocalSwiftPackageReference "SharedPush" */ = { isa = XCLocalSwiftPackageReference; relativePath = Sources/SharedPush; }; @@ -12287,7 +12271,7 @@ }; 4273F7DF2E258827000629F7 /* SharedPush */ = { isa = XCSwiftPackageProductDependency; - package = 42E00D0F2E1E7487006D140D /* XCLocalSwiftPackageReference "Sources/SharedPush" */; + package = 42E00D0F2E1E7487006D140D /* XCLocalSwiftPackageReference "SharedPush" */; productName = SharedPush; }; 427692E22B98B82500F24321 /* SharedPush */ = { From 9b705aec89a6e8e5b13462b831d8cabb2716129c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 13 May 2026 13:57:13 +0000 Subject: [PATCH 3/4] Remove dead legacy action helpers Agent-Logs-Url: https://github.com/home-assistant/iOS/sessions/03a09738-81a2-4cd5-a531-24a646f45727 Co-authored-by: bgoncal <5808343+bgoncal@users.noreply.github.com> --- .../MagicItem/Add/MagicItemAddView.swift | 19 ------------------- .../MagicItem/Add/MagicItemAddViewModel.swift | 5 ----- 2 files changed, 24 deletions(-) diff --git a/Sources/App/Settings/MagicItem/Add/MagicItemAddView.swift b/Sources/App/Settings/MagicItem/Add/MagicItemAddView.swift index 292bfaeec..5d0c93b0d 100644 --- a/Sources/App/Settings/MagicItem/Add/MagicItemAddView.swift +++ b/Sources/App/Settings/MagicItem/Add/MagicItemAddView.swift @@ -146,19 +146,6 @@ struct MagicItemAddView: View { } } - private var actionsDeprecationDisclaimer: some View { - Section { - Button { - viewModel.selectedItemType = .scripts - } label: { - Text(verbatim: L10n.MagicItem.ItemType.Action.List.Warning.title) - } - .buttonStyle(.bordered) - .tint(.red) - .listRowBackground(Color.clear) - } - } - @ViewBuilder private func entitiesPerServerList(domainFilter: Domain? = nil) -> some View { EntityPicker( @@ -191,12 +178,6 @@ struct MagicItemAddView: View { } ) } - - private func visibleForSearch(title: String, entityId: String) -> Bool { - viewModel.searchText.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || - title.lowercased().contains(viewModel.searchText.lowercased()) || - entityId.lowercased().contains(viewModel.searchText.lowercased()) - } } #Preview { diff --git a/Sources/App/Settings/MagicItem/Add/MagicItemAddViewModel.swift b/Sources/App/Settings/MagicItem/Add/MagicItemAddViewModel.swift index 0f74cb8f5..62cbf80f8 100644 --- a/Sources/App/Settings/MagicItem/Add/MagicItemAddViewModel.swift +++ b/Sources/App/Settings/MagicItem/Add/MagicItemAddViewModel.swift @@ -1,9 +1,5 @@ import Combine import Foundation -import GRDB -import HAKit -import PromiseKit -import Shared enum MagicItemAddType { case scripts @@ -14,6 +10,5 @@ enum MagicItemAddType { final class MagicItemAddViewModel: ObservableObject { @Published var selectedItemType = MagicItemAddType.scripts - @Published var searchText: String = "" @Published var selectedServerId: String? } From 1a05665d3b1f86d385c6ae829b03732379906458 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 13 May 2026 14:01:35 +0000 Subject: [PATCH 4/4] Remove Actions menu and related methods Agent-Logs-Url: https://github.com/home-assistant/iOS/sessions/1c8bc677-3fe7-4c09-8333-6902fbc86ee5 Co-authored-by: bgoncal <5808343+bgoncal@users.noreply.github.com> --- Sources/App/AppDelegate.swift | 6 -- .../App/Scenes/SettingsSceneDelegate.swift | 6 -- Sources/App/Utilities/MenuManager.swift | 98 ------------------- 3 files changed, 110 deletions(-) diff --git a/Sources/App/AppDelegate.swift b/Sources/App/AppDelegate.swift index 8924ea225..5a12b749a 100644 --- a/Sources/App/AppDelegate.swift +++ b/Sources/App/AppDelegate.swift @@ -166,12 +166,6 @@ class AppDelegate: UIResponder, UIApplicationDelegate { sceneManager.activateAnyScene(for: .settings) } - @objc func openActionsPreferences() { - precondition(Current.sceneManager.supportsMultipleScenes) - let delegate: Guarantee = sceneManager.scene(for: .init(activity: .settings)) - delegate.done { $0.pushActions(animated: true) } - } - @objc func openHelp() { openURLInBrowser( URL(string: "https://companion.home-assistant.io")!, diff --git a/Sources/App/Scenes/SettingsSceneDelegate.swift b/Sources/App/Scenes/SettingsSceneDelegate.swift index 075af1e49..cbfebc63f 100644 --- a/Sources/App/Scenes/SettingsSceneDelegate.swift +++ b/Sources/App/Scenes/SettingsSceneDelegate.swift @@ -29,10 +29,4 @@ import UIKit } #endif } - - func pushActions(animated: Bool) { - // SwiftUI SettingsView handles navigation internally - // This method is kept for compatibility but no longer does anything - Current.Log.info("pushActions called on SwiftUI SettingsView - navigation handled internally") - } } diff --git a/Sources/App/Utilities/MenuManager.swift b/Sources/App/Utilities/MenuManager.swift index 2b9f14e2c..299ce8b56 100644 --- a/Sources/App/Utilities/MenuManager.swift +++ b/Sources/App/Utilities/MenuManager.swift @@ -6,8 +6,6 @@ import Shared import UIKit private extension UIMenu.Identifier { - static var haActions: Self { .init(rawValue: "ha.actions") } - static var haActionsConfigure: Self { .init(rawValue: "ha.actions.configure") } static var haHelp: Self { .init(rawValue: "ha.help") } static var haWebViewActions: Self { .init(rawValue: "ha.webViewActions") } static var haFile: Self { .init(rawValue: "ha.file") } @@ -123,13 +121,11 @@ enum StatusItemTitleRenderer { class MenuManager { let builder: UIMenuBuilder - let actionsWithImages: [(Action, UIImage)] // remember: this class is short-lived. it only exists for the duration of creating the menu. init(builder: UIMenuBuilder) { self.builder = builder - self.actionsWithImages = Self.actionsWithImages() update() } @@ -200,12 +196,6 @@ class MenuManager { builder.replaceChildren(ofMenu: .help) { _ in helpMenus() } - if builder.menu(for: .haActions) == nil { - builder.insertSibling(actionsMenu(), beforeMenu: .window) - } else { - builder.replace(menu: .haActions, with: actionsMenu()) - } - if builder.menu(for: .haWebViewActions) == nil { builder.insertSibling(webViewActionsMenu(), beforeMenu: .fullscreen) } else { @@ -326,92 +316,6 @@ class MenuManager { ] } - private static func actionsWithImages() -> [(Action, UIImage)] { - // Action+Observation calls reload, so when they change this all gets run again - Current.realm() - .objects(Action.self) - .sorted(byKeyPath: #keyPath(Action.Position)) - .map { action -> (Action, UIImage) in - let iconRect = CGRect(x: 0, y: 0, width: 28, height: 28) - - let image = UIKit.UIGraphicsImageRenderer(size: iconRect.size).image { _ in - let imageRect = iconRect.insetBy(dx: 3, dy: 3) - - UIColor(hex: action.BackgroundColor).set() - UIBezierPath(roundedRect: iconRect, cornerRadius: 6.0).fill() - - MaterialDesignIcons(named: action.IconName) - .image(ofSize: imageRect.size, color: UIColor(hex: action.IconColor)) - .draw(in: imageRect) - } - - return (action, image) - } - } - - private func actionsMenu() -> UIMenu { - let children = actionsWithImages.map { action, image in - UICommand( - title: action.Text, - image: image, - action: #selector(AppDelegate.openMenuUrl(_:)), - propertyList: Self.propertyList(for: action.widgetLinkURL) - ) - } + [ - UIMenu(title: "", image: nil, identifier: .haActionsConfigure, options: [.displayInline], children: [ - UICommand( - title: L10n.Menu.Actions.configure, - image: nil, - action: #selector(AppDelegate.openActionsPreferences), - propertyList: nil - ), - ]), - ] - - return UIMenu( - title: L10n.Menu.Actions.title, - image: nil, - identifier: .haActions, - children: Array(children) - ) - } - - private func actionsMenu() -> AppMacBridgeStatusItemMenuItem { - var items = [AppMacBridgeStatusItemMenuItem]() - items.append(contentsOf: actionsWithImages.compactMap { action, image in - let url = action.widgetLinkURL - - return .init( - name: action.Name, - image: image - ) { callbackInfo in - callbackInfo.activate() - - let delegate: Guarantee = Current.sceneManager.scene( - for: .init(activity: .webView) - ) - delegate.done { - $0.urlHandler?.handle(url: url) - } - } - }) - if !items.isEmpty { - items.append(.separator()) - } - items.append(.init(name: L10n.Menu.Actions.configure) { callbackInfo in - callbackInfo.activate() - - UIApplication.shared.sendAction( - #selector(AppDelegate.openActionsPreferences), - to: UIApplication.shared.delegate, - from: nil, - for: nil - ) - }) - - return AppMacBridgeStatusItemMenuItem(name: L10n.Menu.Actions.title, subitems: items) - } - private func webViewActionsMenu() -> UIMenu { var commands: [UIMenuElement] = [ UIKeyCommand( @@ -493,8 +397,6 @@ class MenuManager { var menuItems = [AppMacBridgeStatusItemMenuItem]() menuItems.append(toggleMenu()) menuItems.append(.separator()) - menuItems.append(actionsMenu()) - menuItems.append(.separator()) menuItems.append(contentsOf: aboutMenu()) menuItems.append(preferencesMenu()) menuItems.append(quitMenu())