From 0650051948fee4f618e03798887b44acda854c4f Mon Sep 17 00:00:00 2001 From: Tim Bert <5411131+timbms@users.noreply.github.com> Date: Thu, 16 Nov 2023 19:06:58 +0100 Subject: [PATCH 01/13] Add Widget Extension and make it runnable Reformating --- OpenHABWidget/AppIntent.swift | 22 ++ .../AccentColor.colorset/Contents.json | 11 + .../AppIcon.appiconset/Contents.json | 63 +++++ OpenHABWidget/Assets.xcassets/Contents.json | 6 + .../WidgetBackground.colorset/Contents.json | 11 + OpenHABWidget/Info.plist | 11 + OpenHABWidget/OpenHABWidget.entitlements | 8 + OpenHABWidget/OpenHABWidget.swift | 86 +++++++ OpenHABWidget/OpenHABWidgetBundle.swift | 20 ++ openHAB.xcodeproj/project.pbxproj | 229 +++++++++++++++++- .../SetColorValueIntentHandler.swift | 12 +- .../SetContactStateValueIntentHandler.swift | 10 +- .../SetDimmerRollerValueIntentHandler.swift | 10 +- .../SetNumberValueIntentHandler.swift | 8 +- .../SetStringValueIntentHandler.swift | 8 +- .../SetSwitchStateIntentHandler.swift | 10 +- openHABUITests/OpenHABUITests.swift | 2 +- 17 files changed, 492 insertions(+), 35 deletions(-) create mode 100644 OpenHABWidget/AppIntent.swift create mode 100644 OpenHABWidget/Assets.xcassets/AccentColor.colorset/Contents.json create mode 100644 OpenHABWidget/Assets.xcassets/AppIcon.appiconset/Contents.json create mode 100644 OpenHABWidget/Assets.xcassets/Contents.json create mode 100644 OpenHABWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json create mode 100644 OpenHABWidget/Info.plist create mode 100644 OpenHABWidget/OpenHABWidget.entitlements create mode 100644 OpenHABWidget/OpenHABWidget.swift create mode 100644 OpenHABWidget/OpenHABWidgetBundle.swift diff --git a/OpenHABWidget/AppIntent.swift b/OpenHABWidget/AppIntent.swift new file mode 100644 index 000000000..28925701b --- /dev/null +++ b/OpenHABWidget/AppIntent.swift @@ -0,0 +1,22 @@ +// Copyright (c) 2010-2023 Contributors to the openHAB project +// +// See the NOTICE file(s) distributed with this work for additional +// information. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0 +// +// SPDX-License-Identifier: EPL-2.0 + +import AppIntents +import WidgetKit + +struct ConfigurationAppIntent: WidgetConfigurationIntent { + static var title: LocalizedStringResource = "Configuration" + static var description = IntentDescription("This is an example widget.") + + // An example configurable parameter. + @Parameter(title: "Favorite Emoji", default: "😃") + var favoriteEmoji: String +} diff --git a/OpenHABWidget/Assets.xcassets/AccentColor.colorset/Contents.json b/OpenHABWidget/Assets.xcassets/AccentColor.colorset/Contents.json new file mode 100644 index 000000000..eb8789700 --- /dev/null +++ b/OpenHABWidget/Assets.xcassets/AccentColor.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/OpenHABWidget/Assets.xcassets/AppIcon.appiconset/Contents.json b/OpenHABWidget/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 000000000..532cd729c --- /dev/null +++ b/OpenHABWidget/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,63 @@ +{ + "images" : [ + { + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "16x16" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "32x32" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "128x128" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "256x256" + }, + { + "idiom" : "mac", + "scale" : "1x", + "size" : "512x512" + }, + { + "idiom" : "mac", + "scale" : "2x", + "size" : "512x512" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/OpenHABWidget/Assets.xcassets/Contents.json b/OpenHABWidget/Assets.xcassets/Contents.json new file mode 100644 index 000000000..73c00596a --- /dev/null +++ b/OpenHABWidget/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/OpenHABWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json b/OpenHABWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json new file mode 100644 index 000000000..eb8789700 --- /dev/null +++ b/OpenHABWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json @@ -0,0 +1,11 @@ +{ + "colors" : [ + { + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/OpenHABWidget/Info.plist b/OpenHABWidget/Info.plist new file mode 100644 index 000000000..0f118fb75 --- /dev/null +++ b/OpenHABWidget/Info.plist @@ -0,0 +1,11 @@ + + + + + NSExtension + + NSExtensionPointIdentifier + com.apple.widgetkit-extension + + + diff --git a/OpenHABWidget/OpenHABWidget.entitlements b/OpenHABWidget/OpenHABWidget.entitlements new file mode 100644 index 000000000..852fa1a47 --- /dev/null +++ b/OpenHABWidget/OpenHABWidget.entitlements @@ -0,0 +1,8 @@ + + + + + com.apple.security.app-sandbox + + + diff --git a/OpenHABWidget/OpenHABWidget.swift b/OpenHABWidget/OpenHABWidget.swift new file mode 100644 index 000000000..931b4992c --- /dev/null +++ b/OpenHABWidget/OpenHABWidget.swift @@ -0,0 +1,86 @@ +// Copyright (c) 2010-2023 Contributors to the openHAB project +// +// See the NOTICE file(s) distributed with this work for additional +// information. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0 +// +// SPDX-License-Identifier: EPL-2.0 + +import SwiftUI +import WidgetKit + +struct Provider: AppIntentTimelineProvider { + func placeholder(in context: Context) -> SimpleEntry { + SimpleEntry(date: Date(), configuration: ConfigurationAppIntent()) + } + + func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry { + SimpleEntry(date: Date(), configuration: configuration) + } + + func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline { + var entries: [SimpleEntry] = [] + + // Generate a timeline consisting of five entries an hour apart, starting from the current date. + let currentDate = Date() + for hourOffset in 0 ..< 5 { + let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! + let entry = SimpleEntry(date: entryDate, configuration: configuration) + entries.append(entry) + } + + return Timeline(entries: entries, policy: .atEnd) + } +} + +struct SimpleEntry: TimelineEntry { + let date: Date + let configuration: ConfigurationAppIntent +} + +struct OpenHABWidgetEntryView: View { + var entry: Provider.Entry + + var body: some View { + Text("Time:") + Text(entry.date, style: .time) + + Text("Favorite Emoji:") + Text(entry.configuration.favoriteEmoji) + } +} + +struct OpenHABWidget: Widget { + let kind: String = "OpenHABWidget" + + var body: some WidgetConfiguration { + AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in + OpenHABWidgetEntryView(entry: entry) + .containerBackground(.fill.tertiary, for: .widget) + } + } +} + +private extension ConfigurationAppIntent { + static var smiley: ConfigurationAppIntent { + let intent = ConfigurationAppIntent() + intent.favoriteEmoji = "😀" + return intent + } + + static var starEyes: ConfigurationAppIntent { + let intent = ConfigurationAppIntent() + intent.favoriteEmoji = "🤩" + return intent + } +} + +#Preview(as: .systemSmall) { + OpenHABWidget() +} timeline: { + SimpleEntry(date: .now, configuration: .smiley) + SimpleEntry(date: .now, configuration: .starEyes) +} diff --git a/OpenHABWidget/OpenHABWidgetBundle.swift b/OpenHABWidget/OpenHABWidgetBundle.swift new file mode 100644 index 000000000..32bedcfb7 --- /dev/null +++ b/OpenHABWidget/OpenHABWidgetBundle.swift @@ -0,0 +1,20 @@ +// Copyright (c) 2010-2023 Contributors to the openHAB project +// +// See the NOTICE file(s) distributed with this work for additional +// information. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0 +// +// SPDX-License-Identifier: EPL-2.0 + +import SwiftUI +import WidgetKit + +@main +struct OpenHABWidgetBundle: WidgetBundle { + var body: some Widget { + OpenHABWidget() + } +} diff --git a/openHAB.xcodeproj/project.pbxproj b/openHAB.xcodeproj/project.pbxproj index 02eae31fc..2b6b445d7 100644 --- a/openHAB.xcodeproj/project.pbxproj +++ b/openHAB.xcodeproj/project.pbxproj @@ -94,6 +94,13 @@ DA4D4DB5233F9ACB00B37E37 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = DA4D4DB4233F9ACB00B37E37 /* README.md */; }; DA65871F236F83CE007E2E7F /* UserDefaultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA65871E236F83CD007E2E7F /* UserDefaultsExtension.swift */; }; DA6587222370C9D8007E2E7F /* PreferencesHostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA6587212370C9D8007E2E7F /* PreferencesHostingController.swift */; }; + DA65AF0E2B064F940060EF7C /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA65AF0D2B064F940060EF7C /* WidgetKit.framework */; }; + DA65AF102B064F940060EF7C /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA65AF0F2B064F940060EF7C /* SwiftUI.framework */; }; + DA65AF132B064F940060EF7C /* OpenHABWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA65AF122B064F940060EF7C /* OpenHABWidgetBundle.swift */; }; + DA65AF152B064F940060EF7C /* OpenHABWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA65AF142B064F940060EF7C /* OpenHABWidget.swift */; }; + DA65AF172B064F940060EF7C /* AppIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA65AF162B064F940060EF7C /* AppIntent.swift */; }; + DA65AF192B064F970060EF7C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA65AF182B064F970060EF7C /* Assets.xcassets */; }; + DA65AF1E2B064F970060EF7C /* OpenHABWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = DA65AF0C2B064F940060EF7C /* OpenHABWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; DA7224D223828D3400712D20 /* PreviewConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA7224D123828D3300712D20 /* PreviewConstants.swift */; }; DA72E1B8236DEA0900B8EF3A /* AppMessageService.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA72E1B5236DEA0900B8EF3A /* AppMessageService.swift */; }; DA7649DE23FC81A20085CE46 /* Unwrap.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA7649DD23FC81A20085CE46 /* Unwrap.swift */; }; @@ -194,6 +201,13 @@ remoteGlobalIDString = DFB2622618830A3600D3244D; remoteInfo = openHAB; }; + DA65AF1C2B064F970060EF7C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = DFB2621F18830A3600D3244D /* Project object */; + proxyType = 1; + remoteGlobalIDString = DA65AF0B2B064F940060EF7C; + remoteInfo = OpenHABWidgetExtension; + }; /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ @@ -210,14 +224,15 @@ }; 4D6470DE2561F935007B03FC /* Embed Foundation Extensions */ = { isa = PBXCopyFilesBuildPhase; - buildActionMask = 12; + buildActionMask = 8; dstPath = ""; dstSubfolderSpec = 13; files = ( + DA65AF1E2B064F970060EF7C /* OpenHABWidgetExtension.appex in Embed Foundation Extensions */, 4D6470DA2561F935007B03FC /* openHABIntents.appex in Embed Foundation Extensions */, ); name = "Embed Foundation Extensions"; - runOnlyForDeploymentPostprocessing = 0; + runOnlyForDeploymentPostprocessing = 1; }; 93F38C4C23803499001B1451 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; @@ -369,6 +384,15 @@ DA4D4E0E2340A00200B37E37 /* Changes.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Changes.md; sourceTree = ""; }; DA65871E236F83CD007E2E7F /* UserDefaultsExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDefaultsExtension.swift; sourceTree = ""; }; DA6587212370C9D8007E2E7F /* PreferencesHostingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreferencesHostingController.swift; sourceTree = ""; }; + DA65AF0C2B064F940060EF7C /* OpenHABWidgetExtension.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = OpenHABWidgetExtension.appex; sourceTree = BUILT_PRODUCTS_DIR; }; + DA65AF0D2B064F940060EF7C /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = /System/Library/Frameworks/WidgetKit.framework; sourceTree = ""; }; + DA65AF0F2B064F940060EF7C /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = /System/Library/Frameworks/SwiftUI.framework; sourceTree = ""; }; + DA65AF122B064F940060EF7C /* OpenHABWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenHABWidgetBundle.swift; sourceTree = ""; }; + DA65AF142B064F940060EF7C /* OpenHABWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenHABWidget.swift; sourceTree = ""; }; + DA65AF162B064F940060EF7C /* AppIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntent.swift; sourceTree = ""; }; + DA65AF182B064F970060EF7C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + DA65AF1A2B064F970060EF7C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + DA65AF1B2B064F970060EF7C /* OpenHABWidget.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OpenHABWidget.entitlements; sourceTree = ""; }; DA7224D123828D3300712D20 /* PreviewConstants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewConstants.swift; sourceTree = ""; }; DA72E1B0236DE9F200B8EF3A /* AppState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppState.swift; path = "openHABWatch Extension/app/AppState.swift"; sourceTree = ""; }; DA72E1B5236DEA0900B8EF3A /* AppMessageService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AppMessageService.swift; path = "openHABWatch Extension/external/AppMessageService.swift"; sourceTree = ""; }; @@ -489,6 +513,15 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DA65AF092B064F940060EF7C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + DA65AF102B064F940060EF7C /* SwiftUI.framework in Frameworks */, + DA65AF0E2B064F940060EF7C /* WidgetKit.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DFB2622418830A3600D3244D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -734,6 +767,19 @@ path = Views; sourceTree = ""; }; + DA65AF112B064F940060EF7C /* OpenHABWidget */ = { + isa = PBXGroup; + children = ( + DA65AF122B064F940060EF7C /* OpenHABWidgetBundle.swift */, + DA65AF142B064F940060EF7C /* OpenHABWidget.swift */, + DA65AF162B064F940060EF7C /* AppIntent.swift */, + DA65AF182B064F970060EF7C /* Assets.xcassets */, + DA65AF1A2B064F970060EF7C /* Info.plist */, + DA65AF1B2B064F970060EF7C /* OpenHABWidget.entitlements */, + ); + path = OpenHABWidget; + sourceTree = ""; + }; DAE238252806E5C800196467 /* Recovered References */ = { isa = PBXGroup; children = ( @@ -874,6 +920,7 @@ DA0775162346705D0086C685 /* openHABWatch */, DA0775252346705F0086C685 /* openHABWatch Extension */, 4D6470D42561F935007B03FC /* openHABIntents */, + DA65AF112B064F940060EF7C /* OpenHABWidget */, DFB2622818830A3600D3244D /* Products */, DFB2622918830A3600D3244D /* Frameworks */, DA1C2E4A230DC28F00FACFB0 /* fastlane */, @@ -889,6 +936,7 @@ 933D7F0422E7015000621A03 /* openHABUITests.xctest */, DA0775152346705D0086C685 /* openHABWatch.app */, 4D6470D32561F935007B03FC /* openHABIntents.appex */, + DA65AF0C2B064F940060EF7C /* OpenHABWidgetExtension.appex */, ); name = Products; sourceTree = ""; @@ -902,6 +950,8 @@ DFE10413197415F900D94943 /* Security.framework */, DFB2622E18830A3600D3244D /* UIKit.framework */, DFB2624C18830A3600D3244D /* XCTest.framework */, + DA65AF0D2B064F940060EF7C /* WidgetKit.framework */, + DA65AF0F2B064F940060EF7C /* SwiftUI.framework */, ); name = Frameworks; sourceTree = ""; @@ -1054,6 +1104,23 @@ productReference = DA2DC22F21F2736C00830730 /* openHABTestsSwift.xctest */; productType = "com.apple.product-type.bundle.unit-test"; }; + DA65AF0B2B064F940060EF7C /* OpenHABWidgetExtension */ = { + isa = PBXNativeTarget; + buildConfigurationList = DA65AF212B064F980060EF7C /* Build configuration list for PBXNativeTarget "OpenHABWidgetExtension" */; + buildPhases = ( + DA65AF082B064F940060EF7C /* Sources */, + DA65AF092B064F940060EF7C /* Frameworks */, + DA65AF0A2B064F940060EF7C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = OpenHABWidgetExtension; + productName = OpenHABWidgetExtension; + productReference = DA65AF0C2B064F940060EF7C /* OpenHABWidgetExtension.appex */; + productType = "com.apple.product-type.app-extension"; + }; DFB2622618830A3600D3244D /* openHAB */ = { isa = PBXNativeTarget; buildConfigurationList = DFB2625C18830A3600D3244D /* Build configuration list for PBXNativeTarget "openHAB" */; @@ -1072,6 +1139,7 @@ dependencies = ( DA07753A2346705F0086C685 /* PBXTargetDependency */, 4D6470D92561F935007B03FC /* PBXTargetDependency */, + DA65AF1D2B064F970060EF7C /* PBXTargetDependency */, ); name = openHAB; packageProductDependencies = ( @@ -1100,7 +1168,7 @@ attributes = { BuildIndependentTargetsInParallel = YES; CLASSPREFIX = OpenHAB; - LastSwiftUpdateCheck = 1210; + LastSwiftUpdateCheck = 1500; LastUpgradeCheck = 1500; ORGANIZATIONNAME = "openHAB e.V."; TargetAttributes = { @@ -1120,6 +1188,9 @@ ProvisioningStyle = Automatic; TestTargetID = DFB2622618830A3600D3244D; }; + DA65AF0B2B064F940060EF7C = { + CreatedOnToolsVersion = 15.0.1; + }; DFB2622618830A3600D3244D = { LastSwiftMigration = ""; SystemCapabilities = { @@ -1181,6 +1252,7 @@ 933D7F0322E7015000621A03 /* openHABUITests */, DA0775142346705D0086C685 /* openHABWatch */, 4D6470D22561F935007B03FC /* openHABIntents */, + DA65AF0B2B064F940060EF7C /* OpenHABWidgetExtension */, ); }; /* End PBXProject section */ @@ -1224,6 +1296,14 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DA65AF0A2B064F940060EF7C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DA65AF192B064F970060EF7C /* Assets.xcassets in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DFB2622518830A3600D3244D /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; @@ -1373,6 +1453,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + DA65AF082B064F940060EF7C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + DA65AF132B064F940060EF7C /* OpenHABWidgetBundle.swift in Sources */, + DA65AF152B064F940060EF7C /* OpenHABWidget.swift in Sources */, + DA65AF172B064F940060EF7C /* AppIntent.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; DFB2622318830A3600D3244D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1449,6 +1539,11 @@ target = DFB2622618830A3600D3244D /* openHAB */; targetProxy = DA2DC23421F2736C00830730 /* PBXContainerItemProxy */; }; + DA65AF1D2B064F970060EF7C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = DA65AF0B2B064F940060EF7C /* OpenHABWidgetExtension */; + targetProxy = DA65AF1C2B064F970060EF7C /* PBXContainerItemProxy */; + }; /* End PBXTargetDependency section */ /* Begin PBXVariantGroup section */ @@ -1852,6 +1947,119 @@ }; name = Release; }; + DA65AF1F2B064F980060EF7C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = OpenHABWidget/OpenHABWidget.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = ""; + DEBUG_INFORMATION_FORMAT = dwarf; + DEVELOPMENT_TEAM = PBAPXHRAM9; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = OpenHABWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = OpenHABWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 openHAB e.V. All rights reserved."; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@executable_path/../../../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 14.0; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = es.spaphone.openhab.OpenHABWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = auto; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + DA65AF202B064F980060EF7C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; + ASSETCATALOG_COMPILER_WIDGET_BACKGROUND_COLOR_NAME = WidgetBackground; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CODE_SIGN_ENTITLEMENTS = OpenHABWidget/OpenHABWidget.entitlements; + CODE_SIGN_IDENTITY = "Apple Development"; + CODE_SIGN_STYLE = Automatic; + CURRENT_PROJECT_VERSION = ""; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + DEVELOPMENT_TEAM = PBAPXHRAM9; + ENABLE_HARDENED_RUNTIME = YES; + ENABLE_USER_SCRIPT_SANDBOXING = YES; + GCC_C_LANGUAGE_STANDARD = gnu17; + GCC_NO_COMMON_BLOCKS = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GENERATE_INFOPLIST_FILE = YES; + INFOPLIST_FILE = OpenHABWidget/Info.plist; + INFOPLIST_KEY_CFBundleDisplayName = OpenHABWidget; + INFOPLIST_KEY_NSHumanReadableCopyright = "Copyright © 2023 openHAB e.V. All rights reserved."; + IPHONEOS_DEPLOYMENT_TARGET = 17.0; + LD_RUNPATH_SEARCH_PATHS = ( + "$(inherited)", + "@executable_path/Frameworks", + "@executable_path/../../Frameworks", + ); + "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( + "$(inherited)", + "@executable_path/../Frameworks", + "@executable_path/../../../../Frameworks", + ); + LOCALIZATION_PREFERS_STRING_CATALOGS = YES; + MACOSX_DEPLOYMENT_TARGET = 14.0; + MARKETING_VERSION = 1.0; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + PRODUCT_BUNDLE_IDENTIFIER = es.spaphone.openhab.OpenHABWidget; + PRODUCT_NAME = "$(TARGET_NAME)"; + PROVISIONING_PROFILE_SPECIFIER = ""; + SDKROOT = auto; + SKIP_INSTALL = YES; + SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx"; + SWIFT_EMIT_LOC_STRINGS = YES; + SWIFT_VERSION = 5.0; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Release; + }; DFB2625A18830A3600D3244D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1908,7 +2116,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 12.0; ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; - SWIFT_VERSION = ""; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; }; @@ -1965,7 +2173,7 @@ ONLY_ACTIVE_ARCH = NO; SDKROOT = iphoneos; SWIFT_COMPILATION_MODE = wholemodule; - SWIFT_VERSION = ""; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; VERSIONING_SYSTEM = "apple-generic"; @@ -1988,6 +2196,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "openHAB/openHAB-Prefix.pch"; INFOPLIST_FILE = "openHAB/openHAB-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2032,6 +2241,7 @@ GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = "openHAB/openHAB-Prefix.pch"; INFOPLIST_FILE = "openHAB/openHAB-Info.plist"; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -2098,6 +2308,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + DA65AF212B064F980060EF7C /* Build configuration list for PBXNativeTarget "OpenHABWidgetExtension" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + DA65AF1F2B064F980060EF7C /* Debug */, + DA65AF202B064F980060EF7C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; DFB2622218830A3600D3244D /* Build configuration list for PBXProject "openHAB" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/openHABIntents/SetColorValueIntentHandler.swift b/openHABIntents/SetColorValueIntentHandler.swift index 3c9ec77bb..ea21f5bd2 100644 --- a/openHABIntents/SetColorValueIntentHandler.swift +++ b/openHABIntents/SetColorValueIntentHandler.swift @@ -39,18 +39,18 @@ class SetColorValueIntentHandler: NSObject, OpenHABSetColorValueIntentHandling { os_log("SetColorValueIntent for %{PUBLIC}@", log: .default, type: .info, intent.item ?? "") guard let itemName = intent.item else { - completion(OpenHABSetColorValueIntentResponse.failureInvalidItem(NSLocalizedString("empty", comment: "empty item name"))) + completion(.failureInvalidItem(NSLocalizedString("empty", comment: "empty item name"))) return } guard var value = intent.value else { - completion(OpenHABSetColorValueIntentResponse.failureInvalidValue(NSLocalizedString("empty", comment: "empty value"), item: intent.item!)) + completion(.failureInvalidValue(NSLocalizedString("empty", comment: "empty value"), item: intent.item!)) return } let hsb = value.split(separator: ",") if hsb.count != 3 { - completion(OpenHABSetColorValueIntentResponse.failureInvalidValue(value, item: intent.item!)) + completion(.failureInvalidValue(value, item: intent.item!)) return } let hue = Int(hsb[0]) ?? 0 @@ -58,19 +58,19 @@ class SetColorValueIntentHandler: NSObject, OpenHABSetColorValueIntentHandling { let val = Int(hsb[2]) ?? 0 if hue < 0 || hue > 360 || sat < 0 || sat > 100 || val < 0 || val > 100 { - completion(OpenHABSetColorValueIntentResponse.failureInvalidValue(value, item: intent.item!)) + completion(.failureInvalidValue(value, item: intent.item!)) return } value = "\(hue),\(sat),\(val)" OpenHABItemCache.instance.getItem(name: itemName) { item in guard let item else { - completion(OpenHABSetColorValueIntentResponse.failureInvalidItem(itemName)) + completion(.failureInvalidItem(itemName)) return } OpenHABItemCache.instance.sendCommand(item, commandToSend: value) - completion(OpenHABSetColorValueIntentResponse.success(value: value, item: itemName)) + completion(.success(value: value, item: itemName)) } } } diff --git a/openHABIntents/SetContactStateValueIntentHandler.swift b/openHABIntents/SetContactStateValueIntentHandler.swift index 18d581ebf..bd2ac65f7 100644 --- a/openHABIntents/SetContactStateValueIntentHandler.swift +++ b/openHABIntents/SetContactStateValueIntentHandler.swift @@ -51,29 +51,29 @@ class SetContactStateValueIntentHandler: NSObject, OpenHABSetContactStateValueIn os_log("SetContactStateValueIntent for %{PUBLIC}@", log: .default, type: .info, intent.item ?? "") guard let itemName = intent.item else { - completion(OpenHABSetContactStateValueIntentResponse.failureInvalidItem(NSLocalizedString("empty", comment: "empty item name"))) + completion(.failureInvalidItem(NSLocalizedString("empty", comment: "empty item name"))) return } guard let state = intent.state else { - completion(OpenHABSetContactStateValueIntentResponse.failureInvalidAction(state: NSLocalizedString("empty", comment: "empty value"), item: itemName)) + completion(.failureInvalidAction(state: NSLocalizedString("empty", comment: "empty value"), item: itemName)) return } // Map user language to real action guard let realState = SetContactStateValueIntentHandler.ACTION_MAP[state] else { - completion(OpenHABSetContactStateValueIntentResponse.failureInvalidAction(state: state, item: itemName)) + completion(.failureInvalidAction(state: state, item: itemName)) return } OpenHABItemCache.instance.getItem(name: itemName) { item in guard let item else { - completion(OpenHABSetContactStateValueIntentResponse.failureInvalidItem(itemName)) + completion(.failureInvalidItem(itemName)) return } OpenHABItemCache.instance.sendState(item, stateToSend: realState) - completion(OpenHABSetContactStateValueIntentResponse.success(item: itemName, state: state)) + completion(.success(item: itemName, state: state)) } } } diff --git a/openHABIntents/SetDimmerRollerValueIntentHandler.swift b/openHABIntents/SetDimmerRollerValueIntentHandler.swift index 936c5b25e..e335a018c 100644 --- a/openHABIntents/SetDimmerRollerValueIntentHandler.swift +++ b/openHABIntents/SetDimmerRollerValueIntentHandler.swift @@ -39,30 +39,30 @@ class SetDimmerRollerValueIntentHandler: NSObject, OpenHABSetDimmerRollerValueIn os_log("SetDimmerRollerValueIntent for %{PUBLIC}@", log: .default, type: .info, intent.item ?? "") guard let itemName = intent.item else { - completion(OpenHABSetDimmerRollerValueIntentResponse.failureInvalidItem(NSLocalizedString("empty", comment: "empty item name"))) + completion(.failureInvalidItem(NSLocalizedString("empty", comment: "empty item name"))) return } guard let value = intent.value else { - completion(OpenHABSetDimmerRollerValueIntentResponse.failureEmptyValue(item: itemName)) + completion(.failureEmptyValue(item: itemName)) return } let number = Int(truncating: value) if number < 0 || number > 100 { - completion(OpenHABSetDimmerRollerValueIntentResponse.failureInvalidValue(value, item: itemName)) + completion(.failureInvalidValue(value, item: itemName)) return } OpenHABItemCache.instance.getItem(name: itemName) { item in guard let item else { - completion(OpenHABSetDimmerRollerValueIntentResponse.failureInvalidItem(itemName)) + completion(.failureInvalidItem(itemName)) return } OpenHABItemCache.instance.sendCommand(item, commandToSend: "\(number)") - completion(OpenHABSetDimmerRollerValueIntentResponse.success(value: NSNumber(value: number), item: itemName)) + completion(.success(value: NSNumber(value: number), item: itemName)) } } } diff --git a/openHABIntents/SetNumberValueIntentHandler.swift b/openHABIntents/SetNumberValueIntentHandler.swift index 44606ca80..37513a0d5 100644 --- a/openHABIntents/SetNumberValueIntentHandler.swift +++ b/openHABIntents/SetNumberValueIntentHandler.swift @@ -39,23 +39,23 @@ class SetNumberValueIntentHandler: NSObject, OpenHABSetNumberValueIntentHandling os_log("SetNumberValueIntent for %{PUBLIC}@", log: .default, type: .info, intent.item ?? "") guard let itemName = intent.item else { - completion(OpenHABSetNumberValueIntentResponse.failureInvalidItem(NSLocalizedString("empty", comment: "empty item name"))) + completion(.failureInvalidItem(NSLocalizedString("empty", comment: "empty item name"))) return } guard let value = intent.value else { - completion(OpenHABSetNumberValueIntentResponse.failureEmptyValue(item: itemName)) + completion(.failureEmptyValue(item: itemName)) return } OpenHABItemCache.instance.getItem(name: itemName) { item in guard let item else { - completion(OpenHABSetNumberValueIntentResponse.failureInvalidItem(itemName)) + completion(.failureInvalidItem(itemName)) return } OpenHABItemCache.instance.sendCommand(item, commandToSend: value.stringValue) - completion(OpenHABSetNumberValueIntentResponse.success(value: value, item: itemName)) + completion(.success(value: value, item: itemName)) } } } diff --git a/openHABIntents/SetStringValueIntentHandler.swift b/openHABIntents/SetStringValueIntentHandler.swift index 95e4044e0..4f00cc349 100644 --- a/openHABIntents/SetStringValueIntentHandler.swift +++ b/openHABIntents/SetStringValueIntentHandler.swift @@ -39,23 +39,23 @@ class SetStringValueIntentHandler: NSObject, OpenHABSetStringValueIntentHandling os_log("SetStringValueIntent for %{PUBLIC}@", log: .default, type: .info, intent.item ?? "") guard let itemName = intent.item else { - completion(OpenHABSetStringValueIntentResponse.failureInvalidItem(NSLocalizedString("empty", comment: "empty item name"))) + completion(.failureInvalidItem(NSLocalizedString("empty", comment: "empty item name"))) return } guard let value = intent.value else { - completion(OpenHABSetStringValueIntentResponse.failureEmptyValue(item: itemName)) + completion(.failureEmptyValue(item: itemName)) return } OpenHABItemCache.instance.getItem(name: itemName) { item in guard let item else { - completion(OpenHABSetStringValueIntentResponse.failureInvalidItem(itemName)) + completion(.failureInvalidItem(itemName)) return } OpenHABItemCache.instance.sendCommand(item, commandToSend: value) - completion(OpenHABSetStringValueIntentResponse.success(value: value, item: itemName)) + completion(.success(value: value, item: itemName)) } } } diff --git a/openHABIntents/SetSwitchStateIntentHandler.swift b/openHABIntents/SetSwitchStateIntentHandler.swift index e23f4c914..be0f1301f 100644 --- a/openHABIntents/SetSwitchStateIntentHandler.swift +++ b/openHABIntents/SetSwitchStateIntentHandler.swift @@ -51,29 +51,29 @@ class SetSwitchStateIntentHandler: NSObject, OpenHABSetSwitchStateIntentHandling os_log("SetSwitchStateIntent for %{PUBLIC}@", log: .default, type: .info, intent.item ?? "") guard let itemName = intent.item else { - completion(OpenHABSetSwitchStateIntentResponse.failureInvalidItem(NSLocalizedString("empty", comment: "empty item name"))) + completion(.failureInvalidItem(NSLocalizedString("empty", comment: "empty item name"))) return } guard let action = intent.action else { - completion(OpenHABSetSwitchStateIntentResponse.failureInvalidAction(NSLocalizedString("empty", comment: "empty action"), item: itemName)) + completion(.failureInvalidAction(NSLocalizedString("empty", comment: "empty action"), item: itemName)) return } // Map user language to real action guard let realAction = SetSwitchStateIntentHandler.ACTION_MAP[action] else { - completion(OpenHABSetSwitchStateIntentResponse.failureInvalidAction(action, item: itemName)) + completion(.failureInvalidAction(action, item: itemName)) return } OpenHABItemCache.instance.getItem(name: itemName) { item in guard let item else { - completion(OpenHABSetSwitchStateIntentResponse.failureInvalidItem(itemName)) + completion(.failureInvalidItem(itemName)) return } OpenHABItemCache.instance.sendCommand(item, commandToSend: realAction) - completion(OpenHABSetSwitchStateIntentResponse.success(action: action, item: itemName)) + completion(.success(action: action, item: itemName)) } } } diff --git a/openHABUITests/OpenHABUITests.swift b/openHABUITests/OpenHABUITests.swift index be90ef4f5..b2f8531ec 100644 --- a/openHABUITests/OpenHABUITests.swift +++ b/openHABUITests/OpenHABUITests.swift @@ -63,7 +63,7 @@ class OpenHABUITests: XCTestCase { menuStaticText?.tap() sleep(1) - + // openHAB logo in left menu webViewsQuery.links.allElementsBoundByIndex[1].tap() sleep(2) From b6e67329955e42fbbf49d7be4ed3b5617ccf0bf6 Mon Sep 17 00:00:00 2001 From: Tim Bert <5411131+timbms@users.noreply.github.com> Date: Fri, 17 Nov 2023 14:06:06 +0100 Subject: [PATCH 02/13] Integrate widgets into openhab-ios So far without cotent. Builds and installs. Dirty overwrite of Current Project Version and Marketing Version - will require rework to synchronise it with app Signed-off-by: Tim Bert <5411131+timbms@users.noreply.github.com> --- OpenHABWidget/OpenHABWidget.entitlements | 2 ++ OpenHABWidget/OpenHABWidget.swift | 1 + openHAB.xcodeproj/project.pbxproj | 25 +++++-------- .../Base.lproj/Intents.intentdefinition | 36 ++++++++++++++++--- openHABIntents/IntentHandler.swift | 1 - 5 files changed, 44 insertions(+), 21 deletions(-) diff --git a/OpenHABWidget/OpenHABWidget.entitlements b/OpenHABWidget/OpenHABWidget.entitlements index 852fa1a47..ee95ab7e5 100644 --- a/OpenHABWidget/OpenHABWidget.entitlements +++ b/OpenHABWidget/OpenHABWidget.entitlements @@ -4,5 +4,7 @@ com.apple.security.app-sandbox + com.apple.security.network.client + diff --git a/OpenHABWidget/OpenHABWidget.swift b/OpenHABWidget/OpenHABWidget.swift index 931b4992c..6183f765c 100644 --- a/OpenHABWidget/OpenHABWidget.swift +++ b/OpenHABWidget/OpenHABWidget.swift @@ -61,6 +61,7 @@ struct OpenHABWidget: Widget { OpenHABWidgetEntryView(entry: entry) .containerBackground(.fill.tertiary, for: .widget) } + .supportedFamilies([.systemSmall]) } } diff --git a/openHAB.xcodeproj/project.pbxproj b/openHAB.xcodeproj/project.pbxproj index 2b6b445d7..91ffea95e 100644 --- a/openHAB.xcodeproj/project.pbxproj +++ b/openHAB.xcodeproj/project.pbxproj @@ -91,6 +91,7 @@ DA2E0AA423DC96E9009B0A99 /* EncircledIconWithAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2E0AA323DC96E9009B0A99 /* EncircledIconWithAction.swift */; }; DA2E0B0E23DCC153009B0A99 /* MapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2E0B0D23DCC152009B0A99 /* MapView.swift */; }; DA2E0B1023DCC439009B0A99 /* MapViewRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2E0B0F23DCC439009B0A99 /* MapViewRow.swift */; }; + DA4743C92B07682C00A2BD10 /* Intents.intentdefinition in Resources */ = {isa = PBXBuildFile; fileRef = 935D340A257B7DC00020A404 /* Intents.intentdefinition */; }; DA4D4DB5233F9ACB00B37E37 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = DA4D4DB4233F9ACB00B37E37 /* README.md */; }; DA65871F236F83CE007E2E7F /* UserDefaultsExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA65871E236F83CD007E2E7F /* UserDefaultsExtension.swift */; }; DA6587222370C9D8007E2E7F /* PreferencesHostingController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA6587212370C9D8007E2E7F /* PreferencesHostingController.swift */; }; @@ -224,7 +225,7 @@ }; 4D6470DE2561F935007B03FC /* Embed Foundation Extensions */ = { isa = PBXCopyFilesBuildPhase; - buildActionMask = 8; + buildActionMask = 12; dstPath = ""; dstSubfolderSpec = 13; files = ( @@ -232,16 +233,6 @@ 4D6470DA2561F935007B03FC /* openHABIntents.appex in Embed Foundation Extensions */, ); name = "Embed Foundation Extensions"; - runOnlyForDeploymentPostprocessing = 1; - }; - 93F38C4C23803499001B1451 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - ); - name = "Embed Frameworks"; runOnlyForDeploymentPostprocessing = 0; }; 93F38C61238034AE001B1451 /* Embed Frameworks */ = { @@ -1130,7 +1121,6 @@ DFB2622418830A3600D3244D /* Frameworks */, DFB2622518830A3600D3244D /* Resources */, 1224F7B7228A8AE600750965 /* Embed Watch Content */, - 93F38C4C23803499001B1451 /* Embed Frameworks */, 4D6470DE2561F935007B03FC /* Embed Foundation Extensions */, 93F8063627AE76AF0035A6B0 /* Crashlytics Run Script */, ); @@ -1300,6 +1290,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + DA4743C92B07682C00A2BD10 /* Intents.intentdefinition in Resources */, DA65AF192B064F970060EF7C /* Assets.xcassets in Resources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1963,7 +1954,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = ""; + CURRENT_PROJECT_VERSION = 1580410538; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = PBAPXHRAM9; ENABLE_HARDENED_RUNTIME = YES; @@ -1989,7 +1980,7 @@ ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MACOSX_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 2.4.60; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = es.spaphone.openhab.OpenHABWidget; @@ -2020,7 +2011,7 @@ CODE_SIGN_ENTITLEMENTS = OpenHABWidget/OpenHABWidget.entitlements; CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = ""; + CURRENT_PROJECT_VERSION = 1580410538; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = PBAPXHRAM9; ENABLE_HARDENED_RUNTIME = YES; @@ -2045,7 +2036,7 @@ ); LOCALIZATION_PREFERS_STRING_CATALOGS = YES; MACOSX_DEPLOYMENT_TARGET = 14.0; - MARKETING_VERSION = 1.0; + MARKETING_VERSION = 2.4.60; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; PRODUCT_BUNDLE_IDENTIFIER = es.spaphone.openhab.OpenHABWidget; @@ -2094,6 +2085,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; DEVELOPMENT_TEAM = PBAPXHRAM9; + ENABLE_PREVIEWS = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; @@ -2157,6 +2149,7 @@ COPY_PHASE_STRIP = NO; DEVELOPMENT_TEAM = PBAPXHRAM9; ENABLE_NS_ASSERTIONS = NO; + ENABLE_PREVIEWS = YES; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_USER_SCRIPT_SANDBOXING = NO; EXCLUDED_ARCHS = i386; diff --git a/openHAB/Resources/Base.lproj/Intents.intentdefinition b/openHAB/Resources/Base.lproj/Intents.intentdefinition index 73f3b0574..c15bff29a 100644 --- a/openHAB/Resources/Base.lproj/Intents.intentdefinition +++ b/openHAB/Resources/Base.lproj/Intents.intentdefinition @@ -9,11 +9,11 @@ INIntentDefinitionNamespace aK4nIm INIntentDefinitionSystemVersion - 21C52 + 22G313 INIntentDefinitionToolsBuildVersion - 13C100 + 15A507 INIntentDefinitionToolsVersion - 13.2.1 + 15.0.1 INIntents @@ -27,7 +27,7 @@ Retrieve the current state of an item INIntentDescriptionID GD4RTw - INIntentIneligibleForSuggestions + INIntentEligibleForWidgets INIntentKeyParameter item @@ -49,6 +49,22 @@ INIntentName GetItemState + INIntentParameterCombinations + + item + + INIntentParameterCombinationIsLinked + + INIntentParameterCombinationIsPrimary + + INIntentParameterCombinationSupportsBackgroundExecution + + INIntentParameterCombinationTitle + Get ${item} State + INIntentParameterCombinationTitleID + joyqa0 + + INIntentParameters @@ -175,6 +191,8 @@ Set the state of a switch on or off INIntentDescriptionID oOjAU0 + INIntentEligibleForWidgets + INIntentKeyParameter item INIntentLastParameterTag @@ -389,6 +407,8 @@ Set the integer value of a dimmer or roller shutter INIntentDescriptionID pg4Bec + INIntentEligibleForWidgets + INIntentKeyParameter item INIntentLastParameterTag @@ -605,6 +625,8 @@ Set the decimal value of a number control item INIntentDescriptionID pptfkD + INIntentEligibleForWidgets + INIntentKeyParameter item INIntentLastParameterTag @@ -813,6 +835,8 @@ Set the string of a string control item INIntentDescriptionID 5B4e9l + INIntentEligibleForWidgets + INIntentKeyParameter item INIntentLastParameterTag @@ -1027,6 +1051,8 @@ Set the color of a color control item INIntentDescriptionID DxO2wk + INIntentEligibleForWidgets + INIntentKeyParameter item INIntentLastParameterTag @@ -1243,6 +1269,8 @@ Set the state of a contact open or closed INIntentDescriptionID eFb7vM + INIntentEligibleForWidgets + INIntentKeyParameter item INIntentLastParameterTag diff --git a/openHABIntents/IntentHandler.swift b/openHABIntents/IntentHandler.swift index 2249c33b2..4e887b6f6 100644 --- a/openHABIntents/IntentHandler.swift +++ b/openHABIntents/IntentHandler.swift @@ -10,7 +10,6 @@ // SPDX-License-Identifier: EPL-2.0 import Intents -import OpenHABCore class IntentHandler: INExtension { override func handler(for intent: INIntent) -> Any { From ade29ac9c441a9d4c8df87029a6fe17d87c59a63 Mon Sep 17 00:00:00 2001 From: Tim Bert <5411131+timbms@users.noreply.github.com> Date: Fri, 17 Nov 2023 19:40:47 +0100 Subject: [PATCH 03/13] Update minimum deployment target for test targets to iOS 14.0 --- openHAB.xcodeproj/project.pbxproj | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/openHAB.xcodeproj/project.pbxproj b/openHAB.xcodeproj/project.pbxproj index 91ffea95e..991c2947c 100644 --- a/openHAB.xcodeproj/project.pbxproj +++ b/openHAB.xcodeproj/project.pbxproj @@ -1703,6 +1703,7 @@ GCC_C_LANGUAGE_STANDARD = gnu11; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INFOPLIST_FILE = openHABUITests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1745,6 +1746,7 @@ GCC_C_LANGUAGE_STANDARD = gnu11; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INFOPLIST_FILE = openHABUITests/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1874,6 +1876,7 @@ GCC_C_LANGUAGE_STANDARD = gnu11; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INFOPLIST_FILE = openHABTestsSwift/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", @@ -1917,6 +1920,7 @@ GCC_C_LANGUAGE_STANDARD = gnu11; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INFOPLIST_FILE = openHABTestsSwift/Info.plist; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "$(inherited)", "@executable_path/Frameworks", From 17adf7d94c27225ee877b8608df7a07306497965 Mon Sep 17 00:00:00 2001 From: Tim Bert <5411131+timbms@users.noreply.github.com> Date: Wed, 21 Feb 2024 19:07:38 +0100 Subject: [PATCH 04/13] Migrating to App Intents Async/Await versions for OpenHABItemCache --- OpenHABWidget/OpenHABWidget.swift | 87 ---------- openHAB/AppIntent/GetItemState.swift | 59 +++++++ openHAB/AppIntent/ItemAppEntity.swift | 9 ++ .../AppIntent/OpenHABShortcutProvider.swift | 9 ++ openHAB/AppIntent/SetColorValue.swift | 65 ++++++++ openHAB/AppIntent/SetContactStateValue.swift | 75 +++++++++ openHAB/AppIntent/SetDimmerRollerValue.swift | 68 ++++++++ openHAB/AppIntent/SetNumberValue.swift | 65 ++++++++ openHAB/AppIntent/SetStringValue.swift | 65 ++++++++ openHAB/AppIntent/SetSwitchState.swift | 75 +++++++++ .../AccentColor.colorset/Contents.json | 0 .../AppIcon.appiconset/Contents.json | 0 .../Assets.xcassets/Contents.json | 0 .../WidgetBackground.colorset/Contents.json | 0 .../ConfigurationAppIntent.swift | 2 +- {OpenHABWidget => openHABWidget}/Info.plist | 0 .../OpenHABWidget.entitlements | 0 .../OpenHABWidgetBundle.swift | 0 openHABWidget/OpenHABWidgetEntryView.swift | 151 ++++++++++++++++++ 19 files changed, 642 insertions(+), 88 deletions(-) delete mode 100644 OpenHABWidget/OpenHABWidget.swift create mode 100644 openHAB/AppIntent/GetItemState.swift create mode 100644 openHAB/AppIntent/ItemAppEntity.swift create mode 100644 openHAB/AppIntent/OpenHABShortcutProvider.swift create mode 100644 openHAB/AppIntent/SetColorValue.swift create mode 100644 openHAB/AppIntent/SetContactStateValue.swift create mode 100644 openHAB/AppIntent/SetDimmerRollerValue.swift create mode 100644 openHAB/AppIntent/SetNumberValue.swift create mode 100644 openHAB/AppIntent/SetStringValue.swift create mode 100644 openHAB/AppIntent/SetSwitchState.swift rename {OpenHABWidget => openHABWidget}/Assets.xcassets/AccentColor.colorset/Contents.json (100%) rename {OpenHABWidget => openHABWidget}/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename {OpenHABWidget => openHABWidget}/Assets.xcassets/Contents.json (100%) rename {OpenHABWidget => openHABWidget}/Assets.xcassets/WidgetBackground.colorset/Contents.json (100%) rename OpenHABWidget/AppIntent.swift => openHABWidget/ConfigurationAppIntent.swift (91%) rename {OpenHABWidget => openHABWidget}/Info.plist (100%) rename {OpenHABWidget => openHABWidget}/OpenHABWidget.entitlements (100%) rename {OpenHABWidget => openHABWidget}/OpenHABWidgetBundle.swift (100%) create mode 100644 openHABWidget/OpenHABWidgetEntryView.swift diff --git a/OpenHABWidget/OpenHABWidget.swift b/OpenHABWidget/OpenHABWidget.swift deleted file mode 100644 index 6183f765c..000000000 --- a/OpenHABWidget/OpenHABWidget.swift +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2010-2023 Contributors to the openHAB project -// -// See the NOTICE file(s) distributed with this work for additional -// information. -// -// This program and the accompanying materials are made available under the -// terms of the Eclipse Public License 2.0 which is available at -// http://www.eclipse.org/legal/epl-2.0 -// -// SPDX-License-Identifier: EPL-2.0 - -import SwiftUI -import WidgetKit - -struct Provider: AppIntentTimelineProvider { - func placeholder(in context: Context) -> SimpleEntry { - SimpleEntry(date: Date(), configuration: ConfigurationAppIntent()) - } - - func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry { - SimpleEntry(date: Date(), configuration: configuration) - } - - func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline { - var entries: [SimpleEntry] = [] - - // Generate a timeline consisting of five entries an hour apart, starting from the current date. - let currentDate = Date() - for hourOffset in 0 ..< 5 { - let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! - let entry = SimpleEntry(date: entryDate, configuration: configuration) - entries.append(entry) - } - - return Timeline(entries: entries, policy: .atEnd) - } -} - -struct SimpleEntry: TimelineEntry { - let date: Date - let configuration: ConfigurationAppIntent -} - -struct OpenHABWidgetEntryView: View { - var entry: Provider.Entry - - var body: some View { - Text("Time:") - Text(entry.date, style: .time) - - Text("Favorite Emoji:") - Text(entry.configuration.favoriteEmoji) - } -} - -struct OpenHABWidget: Widget { - let kind: String = "OpenHABWidget" - - var body: some WidgetConfiguration { - AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { entry in - OpenHABWidgetEntryView(entry: entry) - .containerBackground(.fill.tertiary, for: .widget) - } - .supportedFamilies([.systemSmall]) - } -} - -private extension ConfigurationAppIntent { - static var smiley: ConfigurationAppIntent { - let intent = ConfigurationAppIntent() - intent.favoriteEmoji = "😀" - return intent - } - - static var starEyes: ConfigurationAppIntent { - let intent = ConfigurationAppIntent() - intent.favoriteEmoji = "🤩" - return intent - } -} - -#Preview(as: .systemSmall) { - OpenHABWidget() -} timeline: { - SimpleEntry(date: .now, configuration: .smiley) - SimpleEntry(date: .now, configuration: .starEyes) -} diff --git a/openHAB/AppIntent/GetItemState.swift b/openHAB/AppIntent/GetItemState.swift new file mode 100644 index 000000000..1b6284f42 --- /dev/null +++ b/openHAB/AppIntent/GetItemState.swift @@ -0,0 +1,59 @@ +// +// GetItemState.swift +// +// +// Created by Tim Müller-Seydlitz on 13.02.24. +// + +import Foundation +import AppIntents + +@available(iOS 17.0, macOS 14.0, watchOS 10.0, *) +struct GetItemState: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedAppIntent, PredictableIntent { + static let intentClassName = "OpenHABGetItemStateIntent" + + static var title: LocalizedStringResource = "Get Item State" + static var description = IntentDescription("Retrieve the current state of an item") + + @Parameter(title: "Item", optionsProvider: StringOptionsProvider()) + var item: String? + + struct StringOptionsProvider: DynamicOptionsProvider { + func results() async throws -> [String] { + // TODO: Return possible options here. + return [] + } + } + + static var parameterSummary: some ParameterSummary { + Summary("Get \(\.$item) State") + } + + static var predictionConfiguration: some IntentPredictionConfiguration { + IntentPrediction(parameters: (\.$item)) { item in + DisplayRepresentation( + title: "Get \(item!) State", + subtitle: "" + ) + } + } + + func perform() async throws -> some IntentResult & ReturnsValue { + // TODO: Place your refactored intent handler code here. + return .result(value: String(/* fill in result initializer here */)) + } +} + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +fileprivate extension IntentDialog { + static var itemParameterConfiguration: Self { + "Item Name" + } + static func responseSuccess(item: String, state: String) -> Self { + "The state of \(item) is \(state)" + } + static func responseFailureInvalidItem(item: String) -> Self { + "Sorry can't find \(item)" + } +} + diff --git a/openHAB/AppIntent/ItemAppEntity.swift b/openHAB/AppIntent/ItemAppEntity.swift new file mode 100644 index 000000000..025f5672a --- /dev/null +++ b/openHAB/AppIntent/ItemAppEntity.swift @@ -0,0 +1,9 @@ +// +// ItemAppEntity.swift +// openHAB +// +// Created by Tim Müller-Seydlitz on 17.02.24. +// Copyright © 2024 openHAB e.V. All rights reserved. +// + +import Foundation diff --git a/openHAB/AppIntent/OpenHABShortcutProvider.swift b/openHAB/AppIntent/OpenHABShortcutProvider.swift new file mode 100644 index 000000000..5dd4af191 --- /dev/null +++ b/openHAB/AppIntent/OpenHABShortcutProvider.swift @@ -0,0 +1,9 @@ +// +// OpenHABShortcutProvider.swift +// openHAB +// +// Created by Tim Müller-Seydlitz on 19.02.24. +// Copyright © 2024 openHAB e.V. All rights reserved. +// + +import Foundation diff --git a/openHAB/AppIntent/SetColorValue.swift b/openHAB/AppIntent/SetColorValue.swift new file mode 100644 index 000000000..0bac67db8 --- /dev/null +++ b/openHAB/AppIntent/SetColorValue.swift @@ -0,0 +1,65 @@ +// +// SetColorValue.swift +// +// +// Created by Tim Müller-Seydlitz on 13.02.24. +// + +import Foundation +import AppIntents + +@available(iOS 17.0, macOS 14.0, watchOS 10.0, *) +struct SetColorValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedAppIntent, PredictableIntent { + static let intentClassName = "OpenHABSetColorValueIntent" + + static var title: LocalizedStringResource = "Set Color Control Value" + static var description = IntentDescription("Set the color of a color control item") + + @Parameter(title: "Item", optionsProvider: StringOptionsProvider()) + var item: String? + + struct StringOptionsProvider: DynamicOptionsProvider { + func results() async throws -> [String] { + // TODO: Return possible options here. + return [] + } + } + + @Parameter(title: "Value", default: "240,100,100") + var value: String? + + static var parameterSummary: some ParameterSummary { + Summary("Set \(\.$item) to \(\.$value) (HSB)") + } + + static var predictionConfiguration: some IntentPredictionConfiguration { + IntentPrediction(parameters: (\.$item, \.$value)) { item, value in + DisplayRepresentation( + title: "Set \(item!) to \(value!) (HSB)", + subtitle: "" + ) + } + } + + func perform() async throws -> some IntentResult { + // TODO: Place your refactored intent handler code here. + return .result() + } +} + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +fileprivate extension IntentDialog { + static var itemParameterConfiguration: Self { + "Dimmer/Roller Name" + } + static func responseSuccess(value: String, item: String) -> Self { + "Sent the color value of \(value) to \(item)" + } + static func responseFailureInvalidItem(item: String) -> Self { + "Sorry can't find \(item)" + } + static func responseFailureInvalidValue(value: String, item: String) -> Self { + "Invalid value: \(value) for \(item) must be HSB (0-360,0-100,0-100)" + } +} + diff --git a/openHAB/AppIntent/SetContactStateValue.swift b/openHAB/AppIntent/SetContactStateValue.swift new file mode 100644 index 000000000..dc01df0fb --- /dev/null +++ b/openHAB/AppIntent/SetContactStateValue.swift @@ -0,0 +1,75 @@ +// +// SetContactStateValue.swift +// +// +// Created by Tim Müller-Seydlitz on 13.02.24. +// + +import Foundation +import AppIntents + +@available(iOS 17.0, macOS 14.0, watchOS 10.0, *) +struct SetContactStateValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedAppIntent, PredictableIntent { + static let intentClassName = "OpenHABSetContactStateValueIntent" + + static var title: LocalizedStringResource = "Set Contact State Value" + static var description = IntentDescription("Set the state of a contact open or closed") + + @Parameter(title: "Item", optionsProvider: StringOptionsProvider()) + var item: String? + + struct StringOptionsProvider: DynamicOptionsProvider { + func results() async throws -> [String] { + // TODO: Return possible options here. + return [] + } + } + + @Parameter(title: "State", optionsProvider: StringOptionsProvider()) + var state: String? + + struct StringOptionsProvider: DynamicOptionsProvider { + func results() async throws -> [String] { + // TODO: Return possible options here. + return [] + } + } + + static var parameterSummary: some ParameterSummary { + Summary("Set the state of \(\.$item) to \(\.$state)") + } + + static var predictionConfiguration: some IntentPredictionConfiguration { + IntentPrediction(parameters: (\.$item, \.$state)) { item, state in + DisplayRepresentation( + title: "Set the state of \(item!) to \(state!)", + subtitle: "" + ) + } + } + + func perform() async throws -> some IntentResult { + // TODO: Place your refactored intent handler code here. + return .result() + } +} + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +fileprivate extension IntentDialog { + static var itemParameterConfiguration: Self { + "Switch name" + } + static var stateParameterConfiguration: Self { + "Action" + } + static func responseSuccess(item: String, state: String) -> Self { + "The state of \(item) was set to \(state)" + } + static func responseFailureInvalidItem(item: String) -> Self { + "Sorry can't find \(item)" + } + static func responseFailureInvalidAction(state: String, item: String) -> Self { + "State invalid: \(state) for \(item)" + } +} + diff --git a/openHAB/AppIntent/SetDimmerRollerValue.swift b/openHAB/AppIntent/SetDimmerRollerValue.swift new file mode 100644 index 000000000..d845f7523 --- /dev/null +++ b/openHAB/AppIntent/SetDimmerRollerValue.swift @@ -0,0 +1,68 @@ +// +// SetDimmerRollerValue.swift +// +// +// Created by Tim Müller-Seydlitz on 13.02.24. +// + +import Foundation +import AppIntents + +@available(iOS 17.0, macOS 14.0, watchOS 10.0, *) +struct SetDimmerRollerValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedAppIntent, PredictableIntent { + static let intentClassName = "OpenHABSetDimmerRollerValueIntent" + + static var title: LocalizedStringResource = "Set Dimmer or Roller Shutter Value" + static var description = IntentDescription("Set the integer value of a dimmer or roller shutter") + + @Parameter(title: "Item", optionsProvider: StringOptionsProvider()) + var item: String? + + struct StringOptionsProvider: DynamicOptionsProvider { + func results() async throws -> [String] { + // TODO: Return possible options here. + return [] + } + } + + @Parameter(title: "Value") + var value: Int? + + static var parameterSummary: some ParameterSummary { + Summary("Set \(\.$item) to \(\.$value)") + } + + static var predictionConfiguration: some IntentPredictionConfiguration { + IntentPrediction(parameters: (\.$item, \.$value)) { item, value in + DisplayRepresentation( + title: "Set \(item!) to \(value!)", + subtitle: "" + ) + } + } + + func perform() async throws -> some IntentResult { + // TODO: Place your refactored intent handler code here. + return .result() + } +} + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +fileprivate extension IntentDialog { + static var itemParameterConfiguration: Self { + "Dimmer/Roller Name" + } + static func responseSuccess(value: Int, item: String) -> Self { + "Sent the value of \(value) to \(item)" + } + static func responseFailureInvalidItem(item: String) -> Self { + "Sorry can't find \(item)" + } + static func responseFailureEmptyValue(item: String) -> Self { + "Invalid empty value for \(item)" + } + static func responseFailureInvalidValue(value: Int, item: String) -> Self { + "Invalid value \(value) for \(item) (0-100)" + } +} + diff --git a/openHAB/AppIntent/SetNumberValue.swift b/openHAB/AppIntent/SetNumberValue.swift new file mode 100644 index 000000000..279c82a6e --- /dev/null +++ b/openHAB/AppIntent/SetNumberValue.swift @@ -0,0 +1,65 @@ +// +// SetNumberValue.swift +// +// +// Created by Tim Müller-Seydlitz on 13.02.24. +// + +import Foundation +import AppIntents + +@available(iOS 17.0, macOS 14.0, watchOS 10.0, *) +struct SetNumberValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedAppIntent, PredictableIntent { + static let intentClassName = "OpenHABSetNumberValueIntent" + + static var title: LocalizedStringResource = "Set Number Control Value" + static var description = IntentDescription("Set the decimal value of a number control item") + + @Parameter(title: "Item", optionsProvider: StringOptionsProvider()) + var item: String? + + struct StringOptionsProvider: DynamicOptionsProvider { + func results() async throws -> [String] { + // TODO: Return possible options here. + return [] + } + } + + @Parameter(title: "Value") + var value: Double? + + static var parameterSummary: some ParameterSummary { + Summary("Set \(\.$item) to \(\.$value)") + } + + static var predictionConfiguration: some IntentPredictionConfiguration { + IntentPrediction(parameters: (\.$item, \.$value)) { item, value in + DisplayRepresentation( + title: "Set \(item!) to \(value!)", + subtitle: "" + ) + } + } + + func perform() async throws -> some IntentResult { + // TODO: Place your refactored intent handler code here. + return .result() + } +} + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +fileprivate extension IntentDialog { + static var itemParameterConfiguration: Self { + "Dimmer/Roller Name" + } + static func responseSuccess(value: Double, item: String) -> Self { + "Sent the number \(value) to \(item)" + } + static func responseFailureInvalidItem(item: String) -> Self { + "Sorry can't find \(item)" + } + static func responseFailureEmptyValue(item: String) -> Self { + "Invalid empty value for \(item)" + } +} + diff --git a/openHAB/AppIntent/SetStringValue.swift b/openHAB/AppIntent/SetStringValue.swift new file mode 100644 index 000000000..ad2467cd2 --- /dev/null +++ b/openHAB/AppIntent/SetStringValue.swift @@ -0,0 +1,65 @@ +// +// SetStringValue.swift +// +// +// Created by Tim Müller-Seydlitz on 13.02.24. +// + +import Foundation +import AppIntents + +@available(iOS 17.0, macOS 14.0, watchOS 10.0, *) +struct SetStringValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedAppIntent, PredictableIntent { + static let intentClassName = "OpenHABSetStringValueIntent" + + static var title: LocalizedStringResource = "Set String Control Value" + static var description = IntentDescription("Set the string of a string control item") + + @Parameter(title: "Item", optionsProvider: StringOptionsProvider()) + var item: String? + + struct StringOptionsProvider: DynamicOptionsProvider { + func results() async throws -> [String] { + // TODO: Return possible options here. + return [] + } + } + + @Parameter(title: "Value") + var value: String? + + static var parameterSummary: some ParameterSummary { + Summary("Set \(\.$item) to \(\.$value)") + } + + static var predictionConfiguration: some IntentPredictionConfiguration { + IntentPrediction(parameters: (\.$item, \.$value)) { item, value in + DisplayRepresentation( + title: "Set \(item!) to \(value!)", + subtitle: "" + ) + } + } + + func perform() async throws -> some IntentResult { + // TODO: Place your refactored intent handler code here. + return .result() + } +} + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +fileprivate extension IntentDialog { + static var itemParameterConfiguration: Self { + "Dimmer/Roller Name" + } + static func responseSuccess(value: String, item: String) -> Self { + "Sent the string \(value) to \(item)" + } + static func responseFailureInvalidItem(item: String) -> Self { + "Sorry can't find \(item)" + } + static func responseFailureEmptyValue(item: String) -> Self { + "Invalid empty value for \(item)" + } +} + diff --git a/openHAB/AppIntent/SetSwitchState.swift b/openHAB/AppIntent/SetSwitchState.swift new file mode 100644 index 000000000..9c4bd407d --- /dev/null +++ b/openHAB/AppIntent/SetSwitchState.swift @@ -0,0 +1,75 @@ +// +// SetSwitchState.swift +// +// +// Created by Tim Müller-Seydlitz on 13.02.24. +// + +import Foundation +import AppIntents + +@available(iOS 17.0, macOS 14.0, watchOS 10.0, *) +struct SetSwitchState: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedAppIntent, PredictableIntent { + static let intentClassName = "OpenHABSetSwitchStateIntent" + + static var title: LocalizedStringResource = "Set Switch State" + static var description = IntentDescription("Set the state of a switch on or off") + + @Parameter(title: "Item", optionsProvider: StringOptionsProvider()) + var item: String? + + struct StringOptionsProvider: DynamicOptionsProvider { + func results() async throws -> [String] { + // TODO: Return possible options here. + return [] + } + } + + @Parameter(title: "Action", optionsProvider: StringOptionsProvider()) + var action: String? + + struct StringOptionsProvider: DynamicOptionsProvider { + func results() async throws -> [String] { + // TODO: Return possible options here. + return [] + } + } + + static var parameterSummary: some ParameterSummary { + Summary("Send \(\.$action) to \(\.$item)") + } + + static var predictionConfiguration: some IntentPredictionConfiguration { + IntentPrediction(parameters: (\.$item, \.$action)) { item, action in + DisplayRepresentation( + title: "Send \(action!) to \(item!)", + subtitle: "" + ) + } + } + + func perform() async throws -> some IntentResult { + // TODO: Place your refactored intent handler code here. + return .result() + } +} + +@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +fileprivate extension IntentDialog { + static var itemParameterConfiguration: Self { + "Switch name" + } + static var actionParameterConfiguration: Self { + "Action" + } + static func responseSuccess(action: String, item: String) -> Self { + "Sent the action of \(action) to switch \(item)" + } + static func responseFailureInvalidItem(item: String) -> Self { + "Sorry can't find \(item)" + } + static func responseFailureInvalidAction(action: String, item: String) -> Self { + "Action invalid: \(action) for \(item)" + } +} + diff --git a/OpenHABWidget/Assets.xcassets/AccentColor.colorset/Contents.json b/openHABWidget/Assets.xcassets/AccentColor.colorset/Contents.json similarity index 100% rename from OpenHABWidget/Assets.xcassets/AccentColor.colorset/Contents.json rename to openHABWidget/Assets.xcassets/AccentColor.colorset/Contents.json diff --git a/OpenHABWidget/Assets.xcassets/AppIcon.appiconset/Contents.json b/openHABWidget/Assets.xcassets/AppIcon.appiconset/Contents.json similarity index 100% rename from OpenHABWidget/Assets.xcassets/AppIcon.appiconset/Contents.json rename to openHABWidget/Assets.xcassets/AppIcon.appiconset/Contents.json diff --git a/OpenHABWidget/Assets.xcassets/Contents.json b/openHABWidget/Assets.xcassets/Contents.json similarity index 100% rename from OpenHABWidget/Assets.xcassets/Contents.json rename to openHABWidget/Assets.xcassets/Contents.json diff --git a/OpenHABWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json b/openHABWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json similarity index 100% rename from OpenHABWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json rename to openHABWidget/Assets.xcassets/WidgetBackground.colorset/Contents.json diff --git a/OpenHABWidget/AppIntent.swift b/openHABWidget/ConfigurationAppIntent.swift similarity index 91% rename from OpenHABWidget/AppIntent.swift rename to openHABWidget/ConfigurationAppIntent.swift index 28925701b..510c90e98 100644 --- a/OpenHABWidget/AppIntent.swift +++ b/openHABWidget/ConfigurationAppIntent.swift @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2023 Contributors to the openHAB project +// Copyright (c) 2010-2024 Contributors to the openHAB project // // See the NOTICE file(s) distributed with this work for additional // information. diff --git a/OpenHABWidget/Info.plist b/openHABWidget/Info.plist similarity index 100% rename from OpenHABWidget/Info.plist rename to openHABWidget/Info.plist diff --git a/OpenHABWidget/OpenHABWidget.entitlements b/openHABWidget/OpenHABWidget.entitlements similarity index 100% rename from OpenHABWidget/OpenHABWidget.entitlements rename to openHABWidget/OpenHABWidget.entitlements diff --git a/OpenHABWidget/OpenHABWidgetBundle.swift b/openHABWidget/OpenHABWidgetBundle.swift similarity index 100% rename from OpenHABWidget/OpenHABWidgetBundle.swift rename to openHABWidget/OpenHABWidgetBundle.swift diff --git a/openHABWidget/OpenHABWidgetEntryView.swift b/openHABWidget/OpenHABWidgetEntryView.swift new file mode 100644 index 000000000..2e2c21231 --- /dev/null +++ b/openHABWidget/OpenHABWidgetEntryView.swift @@ -0,0 +1,151 @@ +// Copyright (c) 2010-2024 Contributors to the openHAB project +// +// See the NOTICE file(s) distributed with this work for additional +// information. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0 +// +// SPDX-License-Identifier: EPL-2.0 + +import SwiftUI +import WidgetKit + +struct OpenHABWidgetEntryView: View { + // var entry: Provider.Entry + + @Environment(\.widgetFamily) var family + + // @ViewBuilder + var body: some View { + switch family { + case .systemLarge: + Text("Time:") + // Text(entry.date, style: .time) + + Text("Favorite Emoji:") + // Text(entry.configuration.favoriteEmoji) + case .systemSmall: + VStack { + Text("Time:") + // Text(entry.date, style: .time) + + Text("Favorite Emoji:") + // Text(entry.configuration.favoriteEmoji) + + if #available(iOS 17.0, *) { + HStack(alignment: .top) { + Button(intent: SetSwitchState()) { + Image(systemName: "bolt.fill") + } + } + .tint(.white) + .padding() + } + } + // .containerBackground(for: .widget) { + // Color.gameBackgroundColor + // } + // .widgetURL(entry.hero.url) + case .systemMedium: + Text("Time:") + // Text(entry.date, style: .time) + + Text("Favorite Emoji:") + // Text(entry.configuration.favoriteEmoji) + case .systemExtraLarge: + Text("Time:") + // Text(entry.date, style: .time) + + Text("Favorite Emoji:") + // Text(entry.configuration.favoriteEmoji) + case .accessoryCircular: + Text("Time:") + // Text(entry.date, style: .time) + + Text("Favorite Emoji:") + // Text(entry.configuration.favoriteEmoji) + case .accessoryRectangular: + Text("Time:") + // Text(entry.date, style: .time) + + Text("Favorite Emoji:") + // Text(entry.configuration.favoriteEmoji) + case .accessoryInline: + Text("Time:") + // Text(entry.date, style: .time) + + Text("Favorite Emoji:") + // Text(entry.configuration.favoriteEmoji) + @unknown default: + Text("Time:") + // Text(entry.date, style: .time) + + Text("Favorite Emoji:") + // Text(entry.configuration.favoriteEmoji) + } + } +} + +struct Provider: AppIntentTimelineProvider { + func placeholder(in context: Context) -> SimpleEntry { + SimpleEntry(date: Date(), configuration: ConfigurationAppIntent()) + } + + func snapshot(for configuration: ConfigurationAppIntent, in context: Context) async -> SimpleEntry { + SimpleEntry(date: Date(), configuration: configuration) + } + + func timeline(for configuration: ConfigurationAppIntent, in context: Context) async -> Timeline { + var entries: [SimpleEntry] = [] + + // Generate a timeline consisting of five entries an hour apart, starting from the current date. + let currentDate = Date() + for hourOffset in 0 ..< 5 { + let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! + let entry = SimpleEntry(date: entryDate, configuration: configuration) + entries.append(entry) + } + + return Timeline(entries: entries, policy: .atEnd) + } +} + +struct SimpleEntry: TimelineEntry { + let date: Date + let configuration: ConfigurationAppIntent +} + +struct OpenHABWidgetView: Widget { + let kind: String = "OpenHABWidget" + + var body: some WidgetConfiguration { + AppIntentConfiguration(kind: kind, intent: ConfigurationAppIntent.self, provider: Provider()) { _ in + OpenHABWidgetEntryView() + .containerBackground(.fill.tertiary, for: .widget) + } + .supportedFamilies([.systemSmall]) + } +} + +private extension ConfigurationAppIntent { + static var smiley: ConfigurationAppIntent { + let intent = ConfigurationAppIntent() + intent.favoriteEmoji = "😀" + return intent + } + + static var starEyes: ConfigurationAppIntent { + let intent = ConfigurationAppIntent() + intent.favoriteEmoji = "🤩" + return intent + } +} + +#Preview(as: .systemSmall) { + OpenHABWidgetView() +} timeline: { + SimpleEntry(date: .now, configuration: .smiley) + SimpleEntry(date: .now, configuration: .starEyes) +} From 7e9d79fbbaba9625732815f7c1f3c2ff393965f0 Mon Sep 17 00:00:00 2001 From: Tim Bert <5411131+timbms@users.noreply.github.com> Date: Wed, 21 Feb 2024 19:08:52 +0100 Subject: [PATCH 05/13] Second commit --- .../OpenHABCore/Model/OpenHABItem.swift | 2 +- .../OpenHABCore/Util/OpenHABItemCache.swift | 73 ++++++++++++ openHAB.xcodeproj/project.pbxproj | 83 ++++++++++++-- .../xcshareddata/xcschemes/openHAB.xcscheme | 2 +- .../xcschemes/openHABTestsSwift.xcscheme | 2 +- .../xcschemes/openHABUITests.xcscheme | 2 +- .../openHABWatch (Notification).xcscheme | 2 +- .../xcschemes/openHABWatch.xcscheme | 2 +- .../openHABWatchSwift (Complication).xcscheme | 2 +- openHAB/AppIntent/GetItemState.swift | 39 +++---- openHAB/AppIntent/ItemAppEntity.swift | 105 +++++++++++++++++- .../AppIntent/OpenHABShortcutProvider.swift | 29 ++++- openHAB/AppIntent/SetColorValue.swift | 45 ++++---- openHAB/AppIntent/SetContactStateValue.swift | 63 +++++++---- openHAB/AppIntent/SetDimmerRollerValue.swift | 46 ++++---- openHAB/AppIntent/SetNumberValue.swift | 45 ++++---- openHAB/AppIntent/SetStringValue.swift | 45 ++++---- openHAB/AppIntent/SetSwitchState.swift | 66 ++++++----- .../Base.lproj/Intents.intentdefinition | 6 +- openHABWidget/OpenHABWidgetBundle.swift | 4 +- 20 files changed, 473 insertions(+), 190 deletions(-) diff --git a/OpenHABCore/Sources/OpenHABCore/Model/OpenHABItem.swift b/OpenHABCore/Sources/OpenHABCore/Model/OpenHABItem.swift index 3d0877d4f..dad749e70 100644 --- a/OpenHABCore/Sources/OpenHABCore/Model/OpenHABItem.swift +++ b/OpenHABCore/Sources/OpenHABCore/Model/OpenHABItem.swift @@ -158,7 +158,7 @@ public extension OpenHABItem { public extension OpenHABItem.CodingData { var openHABItem: OpenHABItem { let mappedMembers = members?.map(\.openHABItem) ?? [] - + // swiftlint:disable:next line_length return OpenHABItem(name: name, type: type, state: state, link: link, label: label, groupType: groupType, stateDescription: stateDescription?.openHABStateDescription, commandDescription: commandDescription?.openHABCommandDescription, members: mappedMembers, category: category, options: options) } } diff --git a/OpenHABCore/Sources/OpenHABCore/Util/OpenHABItemCache.swift b/OpenHABCore/Sources/OpenHABCore/Util/OpenHABItemCache.swift index ede1f2911..8fca3d02d 100644 --- a/OpenHABCore/Sources/OpenHABCore/Util/OpenHABItemCache.swift +++ b/OpenHABCore/Sources/OpenHABCore/Util/OpenHABItemCache.swift @@ -28,6 +28,15 @@ public class OpenHABItemCache { var lastUrlConnected = URL_NONE var lastLoad = Date().timeIntervalSince1970 + @available(iOS 17.0, macOS 14.0, watchOS 10.0, *) + public func getItemNames(searchTerm: String?, types: [OpenHABItem.ItemType]?) async -> [String] { + await withCheckedContinuation { continuation in + getItemNames(searchTerm: searchTerm, types: types) { result in + continuation.resume(returning: result.map { String($0) }) + } + } + } + public func getItemNames(searchTerm: String?, types: [OpenHABItem.ItemType]?, completion: @escaping ([NSString]) -> Void) { var ret = [NSString]() @@ -45,6 +54,24 @@ public class OpenHABItemCache { completion(ret) } + @available(iOS 17.0, macOS 14.0, watchOS 10.0, *) + public func getItems(types: [OpenHABItem.ItemType]?) async -> [OpenHABItem] { + guard let items else { + items = await reload(searchTerm: nil, types: types) + return [] + } + return items.filter { (types == nil || ($0.type != nil && types!.contains($0.type!))) }.sorted(by: \.name) + } + + @available(iOS 17.0, macOS 14.0, watchOS 10.0, *) + public func getItem(name: String) async -> OpenHABItem? { + await withCheckedContinuation { continuation in + getItem(name: name) { result in + continuation.resume(returning: result) + } + } + } + @available(iOS 12.0, *) public func getItem(name: String, completion: @escaping (OpenHABItem?) -> Void) { let now = Date().timeIntervalSince1970 @@ -70,6 +97,52 @@ public class OpenHABItemCache { commandOperation?.resume() } + @available(iOS 17.0, macOS 14.0, watchOS 10.0, *) + public func reload(searchTerm: String?, types: [OpenHABItem.ItemType]?) async -> [OpenHABItem] { + await withCheckedContinuation { continuation in + reload(searchTerm: searchTerm, types: types) { result in + continuation.resume(returning: result) + } + } + } + + @available(iOS 12.0, *) + public func reload(searchTerm: String?, types: [OpenHABItem.ItemType]?, completion: @escaping ([OpenHABItem]) -> Void) { + lastLoad = Date().timeIntervalSince1970 + + guard let uurl = getURL() else { return } + + os_log("Loading items from %{PUBLIC}@", log: .default, type: .info, url) + + if NetworkConnection.shared == nil { + NetworkConnection.initialize(ignoreSSL: Preferences.ignoreSSL, interceptor: nil) + } + + NetworkConnection.load(from: uurl, timeout: timeout) { response in + switch response.result { + case let .success(data): + do { + try self.decodeItemsData(data) + + let ret = self.items?.filter { (searchTerm == nil || $0.name.contains(searchTerm.orEmpty)) && (types == nil || ($0.type != nil && types!.contains($0.type!))) }.sorted(by: \.name) ?? [] + + completion(ret) + } catch { + os_log("%{PUBLIC}@ ", log: .default, type: .error, error.localizedDescription) + } + case let .failure(error): + if self.lastUrlConnected == OpenHABItemCache.URL_LOCAL { + self.localUrlFailed = true + os_log("%{PUBLIC}@ ", log: .default, type: .info, error.localizedDescription) + self.reload(searchTerm: searchTerm, types: types, completion: completion) // try remote + + } else { + os_log("%{PUBLIC}@ ", log: .default, type: .error, error.localizedDescription) + } + } + } + } + @available(iOS 12.0, *) public func reload(searchTerm: String?, types: [OpenHABItem.ItemType]?, completion: @escaping ([NSString]) -> Void) { lastLoad = Date().timeIntervalSince1970 diff --git a/openHAB.xcodeproj/project.pbxproj b/openHAB.xcodeproj/project.pbxproj index e78e63179..dfae363c8 100644 --- a/openHAB.xcodeproj/project.pbxproj +++ b/openHAB.xcodeproj/project.pbxproj @@ -70,6 +70,7 @@ A07EF7A02230C0A30040919F /* OpenHABClientCertificatesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = A07EF79F2230C0A20040919F /* OpenHABClientCertificatesViewController.swift */; }; A3F4C3A51A49A5940019A09F /* MainLaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = A3F4C3A41A49A5940019A09F /* MainLaunchScreen.xib */; }; B7D5ECE121499E55001B0EC6 /* MapViewTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B7D5ECE021499E55001B0EC6 /* MapViewTableViewCell.swift */; }; + DA01B9FD2B83FE03007F87A3 /* OpenHABShortcutProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA01B9FC2B83FE03007F87A3 /* OpenHABShortcutProvider.swift */; }; DA0749DE23E0B5950057FA83 /* ColorPickerRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA0749DD23E0B5950057FA83 /* ColorPickerRow.swift */; }; DA0749E023E0BF510057FA83 /* ColorSelection.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA0749DF23E0BF510057FA83 /* ColorSelection.swift */; }; DA0775192346705D0086C685 /* Interface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DA0775172346705D0086C685 /* Interface.storyboard */; }; @@ -91,6 +92,17 @@ DA2E0AA423DC96E9009B0A99 /* EncircledIconWithAction.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2E0AA323DC96E9009B0A99 /* EncircledIconWithAction.swift */; }; DA2E0B0E23DCC153009B0A99 /* MapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2E0B0D23DCC152009B0A99 /* MapView.swift */; }; DA2E0B1023DCC439009B0A99 /* MapViewRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA2E0B0F23DCC439009B0A99 /* MapViewRow.swift */; }; + DA3D999F2B7BB2E0001A903E /* GetItemState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3D99992B7BB2DE001A903E /* GetItemState.swift */; }; + DA3D99A02B7BB2E0001A903E /* SetSwitchState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3D99982B7BB2DE001A903E /* SetSwitchState.swift */; }; + DA3D99A12B7BB2E0001A903E /* SetColorValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3D999E2B7BB2DF001A903E /* SetColorValue.swift */; }; + DA3D99A22B7BB2E0001A903E /* SetContactStateValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3D999A2B7BB2DE001A903E /* SetContactStateValue.swift */; }; + DA3D99A42B7BB2E0001A903E /* SetStringValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3D999D2B7BB2DF001A903E /* SetStringValue.swift */; }; + DA3D99A52B7BB2E0001A903E /* SetDimmerRollerValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3D999B2B7BB2DF001A903E /* SetDimmerRollerValue.swift */; }; + DA3D99AC2B7D71E4001A903E /* SetNumberValue.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3D99AB2B7D71E3001A903E /* SetNumberValue.swift */; }; + DA3D99AE2B8127B4001A903E /* ItemAppEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3D99AD2B8127B4001A903E /* ItemAppEntity.swift */; }; + DA3D99AF2B812A84001A903E /* SetSwitchState.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3D99982B7BB2DE001A903E /* SetSwitchState.swift */; }; + DA3D99B02B812C85001A903E /* ItemAppEntity.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA3D99AD2B8127B4001A903E /* ItemAppEntity.swift */; }; + DA3D99B22B813B72001A903E /* OpenHABCore in Frameworks */ = {isa = PBXBuildFile; productRef = DA3D99B12B813B72001A903E /* OpenHABCore */; }; DA4743C92B07682C00A2BD10 /* Intents.intentdefinition in Resources */ = {isa = PBXBuildFile; fileRef = 935D340A257B7DC00020A404 /* Intents.intentdefinition */; }; DA4D4DB5233F9ACB00B37E37 /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = DA4D4DB4233F9ACB00B37E37 /* README.md */; }; DA50C7BD2B0A51BD0009F716 /* SliderWithSwitchSupportRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA50C7BC2B0A51BD0009F716 /* SliderWithSwitchSupportRow.swift */; }; @@ -100,8 +112,8 @@ DA65AF0E2B064F940060EF7C /* WidgetKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA65AF0D2B064F940060EF7C /* WidgetKit.framework */; }; DA65AF102B064F940060EF7C /* SwiftUI.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = DA65AF0F2B064F940060EF7C /* SwiftUI.framework */; }; DA65AF132B064F940060EF7C /* OpenHABWidgetBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA65AF122B064F940060EF7C /* OpenHABWidgetBundle.swift */; }; - DA65AF152B064F940060EF7C /* OpenHABWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA65AF142B064F940060EF7C /* OpenHABWidget.swift */; }; - DA65AF172B064F940060EF7C /* AppIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA65AF162B064F940060EF7C /* AppIntent.swift */; }; + DA65AF152B064F940060EF7C /* OpenHABWidgetEntryView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA65AF142B064F940060EF7C /* OpenHABWidgetEntryView.swift */; }; + DA65AF172B064F940060EF7C /* ConfigurationAppIntent.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA65AF162B064F940060EF7C /* ConfigurationAppIntent.swift */; }; DA65AF192B064F970060EF7C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DA65AF182B064F970060EF7C /* Assets.xcassets */; }; DA65AF1E2B064F970060EF7C /* OpenHABWidgetExtension.appex in Embed Foundation Extensions */ = {isa = PBXBuildFile; fileRef = DA65AF0C2B064F940060EF7C /* OpenHABWidgetExtension.appex */; settings = {ATTRIBUTES = (RemoveHeadersOnCopy, ); }; }; DA7224D223828D3400712D20 /* PreviewConstants.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA7224D123828D3300712D20 /* PreviewConstants.swift */; }; @@ -313,6 +325,7 @@ A07EF79F2230C0A20040919F /* OpenHABClientCertificatesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OpenHABClientCertificatesViewController.swift; sourceTree = ""; }; A3F4C3A41A49A5940019A09F /* MainLaunchScreen.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; name = MainLaunchScreen.xib; path = ../MainLaunchScreen.xib; sourceTree = ""; }; B7D5ECE021499E55001B0EC6 /* MapViewTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewTableViewCell.swift; sourceTree = ""; }; + DA01B9FC2B83FE03007F87A3 /* OpenHABShortcutProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenHABShortcutProvider.swift; sourceTree = ""; }; DA0749DD23E0B5950057FA83 /* ColorPickerRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorPickerRow.swift; sourceTree = ""; }; DA0749DF23E0BF510057FA83 /* ColorSelection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorSelection.swift; sourceTree = ""; }; DA0775152346705D0086C685 /* openHABWatch.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = openHABWatch.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -373,6 +386,14 @@ DA2E0AA323DC96E9009B0A99 /* EncircledIconWithAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncircledIconWithAction.swift; sourceTree = ""; }; DA2E0B0D23DCC152009B0A99 /* MapView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapView.swift; sourceTree = ""; }; DA2E0B0F23DCC439009B0A99 /* MapViewRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewRow.swift; sourceTree = ""; }; + DA3D99982B7BB2DE001A903E /* SetSwitchState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SetSwitchState.swift; path = "/Users/tms/Developer/openhab-ios7/openhab-ios/openHAB/AppIntent/SetSwitchState.swift"; sourceTree = ""; }; + DA3D99992B7BB2DE001A903E /* GetItemState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GetItemState.swift; path = "/Users/tms/Developer/openhab-ios7/openhab-ios/openHAB/AppIntent/GetItemState.swift"; sourceTree = ""; }; + DA3D999A2B7BB2DE001A903E /* SetContactStateValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SetContactStateValue.swift; path = "/Users/tms/Developer/openhab-ios7/openhab-ios/openHAB/AppIntent/SetContactStateValue.swift"; sourceTree = ""; }; + DA3D999B2B7BB2DF001A903E /* SetDimmerRollerValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SetDimmerRollerValue.swift; path = "/Users/tms/Developer/openhab-ios7/openhab-ios/openHAB/AppIntent/SetDimmerRollerValue.swift"; sourceTree = ""; }; + DA3D999D2B7BB2DF001A903E /* SetStringValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SetStringValue.swift; path = "/Users/tms/Developer/openhab-ios7/openhab-ios/openHAB/AppIntent/SetStringValue.swift"; sourceTree = ""; }; + DA3D999E2B7BB2DF001A903E /* SetColorValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SetColorValue.swift; path = "/Users/tms/Developer/openhab-ios7/openhab-ios/openHAB/AppIntent/SetColorValue.swift"; sourceTree = ""; }; + DA3D99AB2B7D71E3001A903E /* SetNumberValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetNumberValue.swift; sourceTree = ""; }; + DA3D99AD2B8127B4001A903E /* ItemAppEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemAppEntity.swift; sourceTree = ""; }; DA4D4DB4233F9ACB00B37E37 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; DA4D4E0E2340A00200B37E37 /* Changes.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = Changes.md; sourceTree = ""; }; DA50C7BC2B0A51BD0009F716 /* SliderWithSwitchSupportRow.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SliderWithSwitchSupportRow.swift; sourceTree = ""; }; @@ -383,8 +404,8 @@ DA65AF0D2B064F940060EF7C /* WidgetKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = WidgetKit.framework; path = /System/Library/Frameworks/WidgetKit.framework; sourceTree = ""; }; DA65AF0F2B064F940060EF7C /* SwiftUI.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SwiftUI.framework; path = /System/Library/Frameworks/SwiftUI.framework; sourceTree = ""; }; DA65AF122B064F940060EF7C /* OpenHABWidgetBundle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenHABWidgetBundle.swift; sourceTree = ""; }; - DA65AF142B064F940060EF7C /* OpenHABWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenHABWidget.swift; sourceTree = ""; }; - DA65AF162B064F940060EF7C /* AppIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIntent.swift; sourceTree = ""; }; + DA65AF142B064F940060EF7C /* OpenHABWidgetEntryView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OpenHABWidgetEntryView.swift; sourceTree = ""; }; + DA65AF162B064F940060EF7C /* ConfigurationAppIntent.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConfigurationAppIntent.swift; sourceTree = ""; }; DA65AF182B064F970060EF7C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; DA65AF1A2B064F970060EF7C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; DA65AF1B2B064F970060EF7C /* OpenHABWidget.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = OpenHABWidget.entitlements; sourceTree = ""; }; @@ -513,6 +534,7 @@ buildActionMask = 2147483647; files = ( DA65AF102B064F940060EF7C /* SwiftUI.framework in Frameworks */, + DA3D99B22B813B72001A903E /* OpenHABCore in Frameworks */, DA65AF0E2B064F940060EF7C /* WidgetKit.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -751,6 +773,22 @@ path = openHABTestsSwift; sourceTree = ""; }; + DA3D99952B7B9EAF001A903E /* AppIntent */ = { + isa = PBXGroup; + children = ( + DA3D99AB2B7D71E3001A903E /* SetNumberValue.swift */, + DA3D999A2B7BB2DE001A903E /* SetContactStateValue.swift */, + DA3D99982B7BB2DE001A903E /* SetSwitchState.swift */, + DA3D999D2B7BB2DF001A903E /* SetStringValue.swift */, + DA3D999E2B7BB2DF001A903E /* SetColorValue.swift */, + DA3D99992B7BB2DE001A903E /* GetItemState.swift */, + DA3D999B2B7BB2DF001A903E /* SetDimmerRollerValue.swift */, + DA3D99AD2B8127B4001A903E /* ItemAppEntity.swift */, + DA01B9FC2B83FE03007F87A3 /* OpenHABShortcutProvider.swift */, + ); + path = AppIntent; + sourceTree = ""; + }; DA658720236F841F007E2E7F /* Views */ = { isa = PBXGroup; children = ( @@ -762,17 +800,17 @@ path = Views; sourceTree = ""; }; - DA65AF112B064F940060EF7C /* OpenHABWidget */ = { + DA65AF112B064F940060EF7C /* openHABWidget */ = { isa = PBXGroup; children = ( DA65AF122B064F940060EF7C /* OpenHABWidgetBundle.swift */, - DA65AF142B064F940060EF7C /* OpenHABWidget.swift */, - DA65AF162B064F940060EF7C /* AppIntent.swift */, + DA65AF142B064F940060EF7C /* OpenHABWidgetEntryView.swift */, + DA65AF162B064F940060EF7C /* ConfigurationAppIntent.swift */, DA65AF182B064F970060EF7C /* Assets.xcassets */, DA65AF1A2B064F970060EF7C /* Info.plist */, DA65AF1B2B064F970060EF7C /* OpenHABWidget.entitlements */, ); - path = OpenHABWidget; + path = openHABWidget; sourceTree = ""; }; DAE238252806E5C800196467 /* Recovered References */ = { @@ -917,7 +955,7 @@ DA0775162346705D0086C685 /* openHABWatch */, DA0775252346705F0086C685 /* openHABWatch Extension */, 4D6470D42561F935007B03FC /* openHABIntents */, - DA65AF112B064F940060EF7C /* OpenHABWidget */, + DA65AF112B064F940060EF7C /* openHABWidget */, DFB2622818830A3600D3244D /* Products */, DFB2622918830A3600D3244D /* Frameworks */, DA1C2E4A230DC28F00FACFB0 /* fastlane */, @@ -965,6 +1003,7 @@ DFDEE3FF18832293008B26AC /* Util */, 1224F78B228A89E300750965 /* Watch */, DFB2623118830A3600D3244D /* Supporting Files */, + DA3D99952B7B9EAF001A903E /* AppIntent */, 938BF9C724EFCCC000E6B52F /* Resources */, ); path = openHAB; @@ -1114,6 +1153,9 @@ dependencies = ( ); name = OpenHABWidgetExtension; + packageProductDependencies = ( + DA3D99B12B813B72001A903E /* OpenHABCore */, + ); productName = OpenHABWidgetExtension; productReference = DA65AF0C2B064F940060EF7C /* OpenHABWidgetExtension.appex */; productType = "com.apple.product-type.app-extension"; @@ -1165,7 +1207,7 @@ BuildIndependentTargetsInParallel = YES; CLASSPREFIX = OpenHAB; LastSwiftUpdateCheck = 1500; - LastUpgradeCheck = 1500; + LastUpgradeCheck = 1520; ORGANIZATIONNAME = "openHAB e.V."; TargetAttributes = { 4D6470D22561F935007B03FC = { @@ -1456,8 +1498,10 @@ buildActionMask = 2147483647; files = ( DA65AF132B064F940060EF7C /* OpenHABWidgetBundle.swift in Sources */, - DA65AF152B064F940060EF7C /* OpenHABWidget.swift in Sources */, - DA65AF172B064F940060EF7C /* AppIntent.swift in Sources */, + DA65AF152B064F940060EF7C /* OpenHABWidgetEntryView.swift in Sources */, + DA3D99AF2B812A84001A903E /* SetSwitchState.swift in Sources */, + DA65AF172B064F940060EF7C /* ConfigurationAppIntent.swift in Sources */, + DA3D99B02B812C85001A903E /* ItemAppEntity.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1469,9 +1513,12 @@ DA7E1E4B2233986E002AEFD8 /* PlayerView.swift in Sources */, DA7E1E492230227E002AEFD8 /* OpenHABTracker.swift in Sources */, DF06F1F918FEA8420011E7B9 /* ColorPickerUITableViewCell.swift in Sources */, + DA01B9FD2B83FE03007F87A3 /* OpenHABShortcutProvider.swift in Sources */, 65570A7D2476D16A00D524EA /* OpenHABWebViewController.swift in Sources */, DF06F1FC18FEC2020011E7B9 /* ColorPickerViewController.swift in Sources */, 1224F78F228A89FD00750965 /* WatchMessageService.swift in Sources */, + DA3D99A52B7BB2E0001A903E /* SetDimmerRollerValue.swift in Sources */, + DA3D99A22B7BB2E0001A903E /* SetContactStateValue.swift in Sources */, DAA42BAC21DC984A00244B2A /* WebUITableViewCell.swift in Sources */, DF05EF121D00696200DD646D /* DrawerUITableViewCell.swift in Sources */, DF4B84131886DAC400F34902 /* FrameUITableViewCell.swift in Sources */, @@ -1489,11 +1536,13 @@ DA21EAE22339621C001AB415 /* Throttler.swift in Sources */, DAF4F6C0222734D300C24876 /* NewImageUITableViewCell.swift in Sources */, DAEAA89B21E2611000267EA3 /* OpenHABNotificationsViewController.swift in Sources */, + DA3D99AE2B8127B4001A903E /* ItemAppEntity.swift in Sources */, DF1B302D1CF5C667009C921C /* OpenHABNotification.swift in Sources */, 938BF9D324EFD0B700E6B52F /* UIViewController+Localization.swift in Sources */, DF06F1F618FE7A160011E7B9 /* OpenHABSelectionTableViewController.swift in Sources */, DAA42BA821DC97E000244B2A /* NotificationTableViewCell.swift in Sources */, 6595667E28E0BE8E00E8A53B /* MulticastDelegate.swift in Sources */, + DA3D999F2B7BB2E0001A903E /* GetItemState.swift in Sources */, 286F556F22EA062700AECC5C /* DynamicButtonStyleBell.swift in Sources */, DFDEE3FD18831099008B26AC /* OpenHABSettingsViewController.swift in Sources */, 938EDCE122C4FEB800661CA1 /* ScaleAspectFitImageView.swift in Sources */, @@ -1505,12 +1554,16 @@ DFA16EC118898A8400EDB0BB /* SegmentedUITableViewCell.swift in Sources */, DAEAA89D21E6B06400267EA3 /* ReusableView.swift in Sources */, DF05FF231896BD2D00FF2F9B /* SelectionUITableViewCell.swift in Sources */, + DA3D99A02B7BB2E0001A903E /* SetSwitchState.swift in Sources */, DFA16EB818883CF300EDB0BB /* SetpointUITableViewCell.swift in Sources */, DFA16EBB18883DE500EDB0BB /* SliderUITableViewCell.swift in Sources */, DFA13CB418872EBD006355C3 /* SwitchUITableViewCell.swift in Sources */, DFFD8FD118EDBD4F003B502A /* UICircleButton.swift in Sources */, A07EF7A02230C0A30040919F /* OpenHABClientCertificatesViewController.swift in Sources */, + DA3D99A12B7BB2E0001A903E /* SetColorValue.swift in Sources */, + DA3D99A42B7BB2E0001A903E /* SetStringValue.swift in Sources */, 938BF9C624EFCC0700E6B52F /* UILabel+Localization.swift in Sources */, + DA3D99AC2B7D71E4001A903E /* SetNumberValue.swift in Sources */, 653B54C0285C0AC700298ECD /* OpenHABRootViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; @@ -1964,6 +2017,7 @@ "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1580410538; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = PBAPXHRAM9; ENABLE_HARDENED_RUNTIME = YES; @@ -2021,6 +2075,7 @@ CODE_SIGN_IDENTITY = "Apple Development"; CODE_SIGN_STYLE = Automatic; CURRENT_PROJECT_VERSION = 1580410538; + DEAD_CODE_STRIPPING = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; DEVELOPMENT_TEAM = PBAPXHRAM9; ENABLE_HARDENED_RUNTIME = YES; @@ -2542,6 +2597,10 @@ package = 93F8065127AE7B580035A6B0 /* XCRemoteSwiftPackageReference "SVGKit" */; productName = SVGKit; }; + DA3D99B12B813B72001A903E /* OpenHABCore */ = { + isa = XCSwiftPackageProductDependency; + productName = OpenHABCore; + }; /* End XCSwiftPackageProductDependency section */ }; rootObject = DFB2621F18830A3600D3244D /* Project object */; diff --git a/openHAB.xcodeproj/xcshareddata/xcschemes/openHAB.xcscheme b/openHAB.xcodeproj/xcshareddata/xcschemes/openHAB.xcscheme index fe4eb7c51..d7bed9a1d 100644 --- a/openHAB.xcodeproj/xcshareddata/xcschemes/openHAB.xcscheme +++ b/openHAB.xcodeproj/xcshareddata/xcschemes/openHAB.xcscheme @@ -1,6 +1,6 @@ [String] { - // TODO: Return possible options here. - return [] - } - } - static var parameterSummary: some ParameterSummary { Summary("Get \(\.$item) State") } @@ -32,28 +29,32 @@ struct GetItemState: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedA static var predictionConfiguration: some IntentPredictionConfiguration { IntentPrediction(parameters: (\.$item)) { item in DisplayRepresentation( - title: "Get \(item!) State", + title: "Get \(item) State", subtitle: "" ) } } + @Parameter(title: "Item") + var item: ItemAppEntity + func perform() async throws -> some IntentResult & ReturnsValue { - // TODO: Place your refactored intent handler code here. - return .result(value: String(/* fill in result initializer here */)) + let validatedItem = await OpenHABItemCache.instance.getItem(name: item.id) + return .result(value: validatedItem?.state ?? NSLocalizedString("unknown", comment: "unknown item")) } } @available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) -fileprivate extension IntentDialog { +private extension IntentDialog { static var itemParameterConfiguration: Self { "Item Name" } + static func responseSuccess(item: String, state: String) -> Self { "The state of \(item) is \(state)" } + static func responseFailureInvalidItem(item: String) -> Self { "Sorry can't find \(item)" } } - diff --git a/openHAB/AppIntent/ItemAppEntity.swift b/openHAB/AppIntent/ItemAppEntity.swift index 025f5672a..bb4918bc0 100644 --- a/openHAB/AppIntent/ItemAppEntity.swift +++ b/openHAB/AppIntent/ItemAppEntity.swift @@ -1,9 +1,104 @@ +// Copyright (c) 2010-2024 Contributors to the openHAB project // -// ItemAppEntity.swift -// openHAB +// See the NOTICE file(s) distributed with this work for additional +// information. // -// Created by Tim Müller-Seydlitz on 17.02.24. -// Copyright © 2024 openHAB e.V. All rights reserved. +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0 // +// SPDX-License-Identifier: EPL-2.0 -import Foundation +import AppIntents +import Intents +import OpenHABCore +import os.log + +@available(iOS 17.0, macOS 14.0, watchOS 10.0, *) +struct ItemAppEntity: AppEntity { + struct ItemAppEntityQuery: EntityQuery { + func entities(for identifiers: [ItemAppEntity.ID]) async throws -> [ItemAppEntity] { + let items = await OpenHABItemCache.instance.getItems(types: [OpenHABItem.ItemType.switchItem]).filter { $0.name == identifiers.first } + let result = items.map { item -> ItemAppEntity in + ItemAppEntity(item) + } + return result + } + + func entities(matching string: String) async throws -> [ItemAppEntity] { + let items = await OpenHABItemCache.instance.getItems(types: [OpenHABItem.ItemType.switchItem]).filter { $0.name == string } + let result = items.map { item -> ItemAppEntity in + ItemAppEntity(item) + } + return result + } + + func entities(matching string: String) async throws -> IntentItemCollection { + let items = await OpenHABItemCache.instance.getItems(types: [OpenHABItem.ItemType.switchItem]).filter { $0.name == string } + return ItemCollection { + ItemSection( + "Regulars", + items: + items.map { + IntentItem( + ItemAppEntity($0), + title: LocalizedStringResource(stringLiteral: ItemAppEntity($0).label), + image: ItemAppEntity($0).displayRepresentation.image + ) + } + ) + } + } + + func suggestedEntities() async throws -> [ItemAppEntity] { + let items = await OpenHABItemCache.instance.getItems(types: [OpenHABItem.ItemType.switchItem]) + let result = items.map { item -> ItemAppEntity in + ItemAppEntity(item) + } + return result + } + + /// - Tag: suggestedEntities +// func suggestedEntities() async throws -> IntentItemCollection { +// let items = await OpenHABItemCache.instance.getItems(types: [OpenHABItem.ItemType.switchItem]) +// return ItemCollection { +// ItemSection( +// items: +// items.map { +// IntentItem( +// ItemAppEntity($0), +// title: LocalizedStringResource(stringLiteral: ItemAppEntity($0).displayString), +// image: ItemAppEntity($0).displayRepresentation.image +// ) +// } +// ) +// } +// } + } + + static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Item") + static var typeDisplayName: LocalizedStringResource = "Item" + + static var defaultQuery = ItemAppEntityQuery() + + var id: String // if your identifier is not a String, conform the entity to EntityIdentifierConvertible. + var label: String + var displayRepresentation: DisplayRepresentation { + DisplayRepresentation(title: "\(id)", subtitle: "\(label)") + } + + init(id: String, label: String, category: String, link: String, type: OpenHABItem.ItemType?) { + self.id = id + self.label = label + } + + init(_ openHABItem: OpenHABItem) { + self.init( + id: openHABItem.name, + label: openHABItem.label, + category: openHABItem.category, + link: openHABItem.link, + type: openHABItem.type + ) + } +} diff --git a/openHAB/AppIntent/OpenHABShortcutProvider.swift b/openHAB/AppIntent/OpenHABShortcutProvider.swift index 5dd4af191..c9b3478de 100644 --- a/openHAB/AppIntent/OpenHABShortcutProvider.swift +++ b/openHAB/AppIntent/OpenHABShortcutProvider.swift @@ -1,9 +1,28 @@ +// Copyright (c) 2010-2024 Contributors to the openHAB project // -// OpenHABShortcutProvider.swift -// openHAB +// See the NOTICE file(s) distributed with this work for additional +// information. // -// Created by Tim Müller-Seydlitz on 19.02.24. -// Copyright © 2024 openHAB e.V. All rights reserved. +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0 // +// SPDX-License-Identifier: EPL-2.0 -import Foundation +import AppIntents + +/// - Tag: AppShortcuts +@available(iOS 17.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) +struct OpenHABAppShortcutsProvider: AppShortcutsProvider { + static var appShortcuts: [AppShortcut] { + AppShortcut( + intent: SetSwitchState(), + phrases: [ + "Set \(.applicationName)", + "Set switch \(\.$item) from \(.applicationName)" + ], + shortTitle: "Set switch" + ) + } + static var shortcutTileColor: ShortcutTileColor = .orange +} diff --git a/openHAB/AppIntent/SetColorValue.swift b/openHAB/AppIntent/SetColorValue.swift index 0bac67db8..a1bd38da6 100644 --- a/openHAB/AppIntent/SetColorValue.swift +++ b/openHAB/AppIntent/SetColorValue.swift @@ -1,12 +1,19 @@ +// Copyright (c) 2010-2024 Contributors to the openHAB project // -// SetColorValue.swift -// +// See the NOTICE file(s) distributed with this work for additional +// information. // -// Created by Tim Müller-Seydlitz on 13.02.24. +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0 // +// SPDX-License-Identifier: EPL-2.0 -import Foundation import AppIntents +import Foundation +import Intents +import OpenHABCore +import os.log @available(iOS 17.0, macOS 14.0, watchOS 10.0, *) struct SetColorValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedAppIntent, PredictableIntent { @@ -15,19 +22,6 @@ struct SetColorValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigrated static var title: LocalizedStringResource = "Set Color Control Value" static var description = IntentDescription("Set the color of a color control item") - @Parameter(title: "Item", optionsProvider: StringOptionsProvider()) - var item: String? - - struct StringOptionsProvider: DynamicOptionsProvider { - func results() async throws -> [String] { - // TODO: Return possible options here. - return [] - } - } - - @Parameter(title: "Value", default: "240,100,100") - var value: String? - static var parameterSummary: some ParameterSummary { Summary("Set \(\.$item) to \(\.$value) (HSB)") } @@ -35,31 +29,40 @@ struct SetColorValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigrated static var predictionConfiguration: some IntentPredictionConfiguration { IntentPrediction(parameters: (\.$item, \.$value)) { item, value in DisplayRepresentation( - title: "Set \(item!) to \(value!) (HSB)", + title: "Set \(item) to \(value) (HSB)", subtitle: "" ) } } + @Parameter(title: "Item") + var item: ItemAppEntity + + @Parameter(title: "Value", default: "240,100,100") + var value: String + func perform() async throws -> some IntentResult { - // TODO: Place your refactored intent handler code here. + let validatedItem = await OpenHABItemCache.instance.getItem(name: item.id) + OpenHABItemCache.instance.sendCommand(validatedItem!, commandToSend: value) return .result() } } @available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) -fileprivate extension IntentDialog { +private extension IntentDialog { static var itemParameterConfiguration: Self { "Dimmer/Roller Name" } + static func responseSuccess(value: String, item: String) -> Self { "Sent the color value of \(value) to \(item)" } + static func responseFailureInvalidItem(item: String) -> Self { "Sorry can't find \(item)" } + static func responseFailureInvalidValue(value: String, item: String) -> Self { "Invalid value: \(value) for \(item) must be HSB (0-360,0-100,0-100)" } } - diff --git a/openHAB/AppIntent/SetContactStateValue.swift b/openHAB/AppIntent/SetContactStateValue.swift index dc01df0fb..97a25416c 100644 --- a/openHAB/AppIntent/SetContactStateValue.swift +++ b/openHAB/AppIntent/SetContactStateValue.swift @@ -1,40 +1,45 @@ +// Copyright (c) 2010-2024 Contributors to the openHAB project // -// SetContactStateValue.swift -// +// See the NOTICE file(s) distributed with this work for additional +// information. // -// Created by Tim Müller-Seydlitz on 13.02.24. +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0 // +// SPDX-License-Identifier: EPL-2.0 -import Foundation import AppIntents +import Foundation +import Intents +import OpenHABCore +import os.log @available(iOS 17.0, macOS 14.0, watchOS 10.0, *) struct SetContactStateValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedAppIntent, PredictableIntent { - static let intentClassName = "OpenHABSetContactStateValueIntent" - - static var title: LocalizedStringResource = "Set Contact State Value" - static var description = IntentDescription("Set the state of a contact open or closed") - - @Parameter(title: "Item", optionsProvider: StringOptionsProvider()) - var item: String? - struct StringOptionsProvider: DynamicOptionsProvider { func results() async throws -> [String] { // TODO: Return possible options here. - return [] + [] } } - @Parameter(title: "State", optionsProvider: StringOptionsProvider()) - var state: String? + enum Contact: String, AppEnum { + case open = "OPEN" + case close = "CLOSE" - struct StringOptionsProvider: DynamicOptionsProvider { - func results() async throws -> [String] { - // TODO: Return possible options here. - return [] - } + static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Action") + static var caseDisplayRepresentations: [Self: DisplayRepresentation] = [ + .open: "OPEN", + .close: "CLOSE" + ] } + static let intentClassName = "OpenHABSetContactStateValueIntent" + + static var title: LocalizedStringResource = "Set Contact State Value" + static var description = IntentDescription("Set the state of a contact open or closed") + static var parameterSummary: some ParameterSummary { Summary("Set the state of \(\.$item) to \(\.$state)") } @@ -42,34 +47,44 @@ struct SetContactStateValue: AppIntent, WidgetConfigurationIntent, CustomIntentM static var predictionConfiguration: some IntentPredictionConfiguration { IntentPrediction(parameters: (\.$item, \.$state)) { item, state in DisplayRepresentation( - title: "Set the state of \(item!) to \(state!)", + title: "Set the state of \(item) to \(state)", subtitle: "" ) } } + @Parameter(title: "Item") + var item: ItemAppEntity + + @Parameter(title: "State") + var state: Contact + func perform() async throws -> some IntentResult { - // TODO: Place your refactored intent handler code here. + let validatedItem = await OpenHABItemCache.instance.getItem(name: item.id) + OpenHABItemCache.instance.sendCommand(validatedItem!, commandToSend: state.rawValue) return .result() } } @available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) -fileprivate extension IntentDialog { +private extension IntentDialog { static var itemParameterConfiguration: Self { "Switch name" } + static var stateParameterConfiguration: Self { "Action" } + static func responseSuccess(item: String, state: String) -> Self { "The state of \(item) was set to \(state)" } + static func responseFailureInvalidItem(item: String) -> Self { "Sorry can't find \(item)" } + static func responseFailureInvalidAction(state: String, item: String) -> Self { "State invalid: \(state) for \(item)" } } - diff --git a/openHAB/AppIntent/SetDimmerRollerValue.swift b/openHAB/AppIntent/SetDimmerRollerValue.swift index d845f7523..1cc02453a 100644 --- a/openHAB/AppIntent/SetDimmerRollerValue.swift +++ b/openHAB/AppIntent/SetDimmerRollerValue.swift @@ -1,12 +1,19 @@ +// Copyright (c) 2010-2024 Contributors to the openHAB project // -// SetDimmerRollerValue.swift -// +// See the NOTICE file(s) distributed with this work for additional +// information. // -// Created by Tim Müller-Seydlitz on 13.02.24. +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0 // +// SPDX-License-Identifier: EPL-2.0 -import Foundation import AppIntents +import Foundation +import Intents +import OpenHABCore +import os.log @available(iOS 17.0, macOS 14.0, watchOS 10.0, *) struct SetDimmerRollerValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedAppIntent, PredictableIntent { @@ -15,19 +22,6 @@ struct SetDimmerRollerValue: AppIntent, WidgetConfigurationIntent, CustomIntentM static var title: LocalizedStringResource = "Set Dimmer or Roller Shutter Value" static var description = IntentDescription("Set the integer value of a dimmer or roller shutter") - @Parameter(title: "Item", optionsProvider: StringOptionsProvider()) - var item: String? - - struct StringOptionsProvider: DynamicOptionsProvider { - func results() async throws -> [String] { - // TODO: Return possible options here. - return [] - } - } - - @Parameter(title: "Value") - var value: Int? - static var parameterSummary: some ParameterSummary { Summary("Set \(\.$item) to \(\.$value)") } @@ -35,34 +29,44 @@ struct SetDimmerRollerValue: AppIntent, WidgetConfigurationIntent, CustomIntentM static var predictionConfiguration: some IntentPredictionConfiguration { IntentPrediction(parameters: (\.$item, \.$value)) { item, value in DisplayRepresentation( - title: "Set \(item!) to \(value!)", + title: "Set \(item) to \(value)", subtitle: "" ) } } + @Parameter(title: "Item") + var item: ItemAppEntity + + @Parameter(title: "Value") + var value: Int + func perform() async throws -> some IntentResult { - // TODO: Place your refactored intent handler code here. + let validatedItem = await OpenHABItemCache.instance.getItem(name: item.id) + OpenHABItemCache.instance.sendCommand(validatedItem!, commandToSend: String(value)) return .result() } } @available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) -fileprivate extension IntentDialog { +private extension IntentDialog { static var itemParameterConfiguration: Self { "Dimmer/Roller Name" } + static func responseSuccess(value: Int, item: String) -> Self { "Sent the value of \(value) to \(item)" } + static func responseFailureInvalidItem(item: String) -> Self { "Sorry can't find \(item)" } + static func responseFailureEmptyValue(item: String) -> Self { "Invalid empty value for \(item)" } + static func responseFailureInvalidValue(value: Int, item: String) -> Self { "Invalid value \(value) for \(item) (0-100)" } } - diff --git a/openHAB/AppIntent/SetNumberValue.swift b/openHAB/AppIntent/SetNumberValue.swift index 279c82a6e..9b3318ef2 100644 --- a/openHAB/AppIntent/SetNumberValue.swift +++ b/openHAB/AppIntent/SetNumberValue.swift @@ -1,12 +1,19 @@ +// Copyright (c) 2010-2024 Contributors to the openHAB project // -// SetNumberValue.swift -// +// See the NOTICE file(s) distributed with this work for additional +// information. // -// Created by Tim Müller-Seydlitz on 13.02.24. +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0 // +// SPDX-License-Identifier: EPL-2.0 -import Foundation import AppIntents +import Foundation +import Intents +import OpenHABCore +import os.log @available(iOS 17.0, macOS 14.0, watchOS 10.0, *) struct SetNumberValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedAppIntent, PredictableIntent { @@ -15,19 +22,6 @@ struct SetNumberValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigrate static var title: LocalizedStringResource = "Set Number Control Value" static var description = IntentDescription("Set the decimal value of a number control item") - @Parameter(title: "Item", optionsProvider: StringOptionsProvider()) - var item: String? - - struct StringOptionsProvider: DynamicOptionsProvider { - func results() async throws -> [String] { - // TODO: Return possible options here. - return [] - } - } - - @Parameter(title: "Value") - var value: Double? - static var parameterSummary: some ParameterSummary { Summary("Set \(\.$item) to \(\.$value)") } @@ -35,31 +29,40 @@ struct SetNumberValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigrate static var predictionConfiguration: some IntentPredictionConfiguration { IntentPrediction(parameters: (\.$item, \.$value)) { item, value in DisplayRepresentation( - title: "Set \(item!) to \(value!)", + title: "Set \(item) to \(value)", subtitle: "" ) } } + @Parameter(title: "Item") + var item: ItemAppEntity + + @Parameter(title: "Value") + var value: Double + func perform() async throws -> some IntentResult { - // TODO: Place your refactored intent handler code here. + let validatedItem = await OpenHABItemCache.instance.getItem(name: item.id) + OpenHABItemCache.instance.sendCommand(validatedItem!, commandToSend: value.valueText(step: 0.1)) return .result() } } @available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) -fileprivate extension IntentDialog { +private extension IntentDialog { static var itemParameterConfiguration: Self { "Dimmer/Roller Name" } + static func responseSuccess(value: Double, item: String) -> Self { "Sent the number \(value) to \(item)" } + static func responseFailureInvalidItem(item: String) -> Self { "Sorry can't find \(item)" } + static func responseFailureEmptyValue(item: String) -> Self { "Invalid empty value for \(item)" } } - diff --git a/openHAB/AppIntent/SetStringValue.swift b/openHAB/AppIntent/SetStringValue.swift index ad2467cd2..bd7a8d1ee 100644 --- a/openHAB/AppIntent/SetStringValue.swift +++ b/openHAB/AppIntent/SetStringValue.swift @@ -1,12 +1,19 @@ +// Copyright (c) 2010-2024 Contributors to the openHAB project // -// SetStringValue.swift -// +// See the NOTICE file(s) distributed with this work for additional +// information. // -// Created by Tim Müller-Seydlitz on 13.02.24. +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0 // +// SPDX-License-Identifier: EPL-2.0 -import Foundation import AppIntents +import Foundation +import Intents +import OpenHABCore +import os.log @available(iOS 17.0, macOS 14.0, watchOS 10.0, *) struct SetStringValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedAppIntent, PredictableIntent { @@ -15,19 +22,6 @@ struct SetStringValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigrate static var title: LocalizedStringResource = "Set String Control Value" static var description = IntentDescription("Set the string of a string control item") - @Parameter(title: "Item", optionsProvider: StringOptionsProvider()) - var item: String? - - struct StringOptionsProvider: DynamicOptionsProvider { - func results() async throws -> [String] { - // TODO: Return possible options here. - return [] - } - } - - @Parameter(title: "Value") - var value: String? - static var parameterSummary: some ParameterSummary { Summary("Set \(\.$item) to \(\.$value)") } @@ -35,31 +29,40 @@ struct SetStringValue: AppIntent, WidgetConfigurationIntent, CustomIntentMigrate static var predictionConfiguration: some IntentPredictionConfiguration { IntentPrediction(parameters: (\.$item, \.$value)) { item, value in DisplayRepresentation( - title: "Set \(item!) to \(value!)", + title: "Set \(item) to \(value)", subtitle: "" ) } } + @Parameter(title: "Item") + var item: ItemAppEntity + + @Parameter(title: "Value") + var value: String + func perform() async throws -> some IntentResult { - // TODO: Place your refactored intent handler code here. + let validatedItem = await OpenHABItemCache.instance.getItem(name: item.id) + OpenHABItemCache.instance.sendCommand(validatedItem!, commandToSend: value) return .result() } } @available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) -fileprivate extension IntentDialog { +private extension IntentDialog { static var itemParameterConfiguration: Self { "Dimmer/Roller Name" } + static func responseSuccess(value: String, item: String) -> Self { "Sent the string \(value) to \(item)" } + static func responseFailureInvalidItem(item: String) -> Self { "Sorry can't find \(item)" } + static func responseFailureEmptyValue(item: String) -> Self { "Invalid empty value for \(item)" } } - diff --git a/openHAB/AppIntent/SetSwitchState.swift b/openHAB/AppIntent/SetSwitchState.swift index 9c4bd407d..6d3fb7b50 100644 --- a/openHAB/AppIntent/SetSwitchState.swift +++ b/openHAB/AppIntent/SetSwitchState.swift @@ -1,39 +1,37 @@ +// Copyright (c) 2010-2024 Contributors to the openHAB project // -// SetSwitchState.swift -// +// See the NOTICE file(s) distributed with this work for additional +// information. // -// Created by Tim Müller-Seydlitz on 13.02.24. +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0 // +// SPDX-License-Identifier: EPL-2.0 -import Foundation import AppIntents +import Foundation +import Intents +import OpenHABCore +import os.log @available(iOS 17.0, macOS 14.0, watchOS 10.0, *) struct SetSwitchState: AppIntent, WidgetConfigurationIntent, CustomIntentMigratedAppIntent, PredictableIntent { - static let intentClassName = "OpenHABSetSwitchStateIntent" - - static var title: LocalizedStringResource = "Set Switch State" - static var description = IntentDescription("Set the state of a switch on or off") - - @Parameter(title: "Item", optionsProvider: StringOptionsProvider()) - var item: String? + enum Action: String, AppEnum { + case on = "ON" + case off = "OFF" - struct StringOptionsProvider: DynamicOptionsProvider { - func results() async throws -> [String] { - // TODO: Return possible options here. - return [] - } + static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Action") + static var caseDisplayRepresentations: [Self: DisplayRepresentation] = [ + .on: "ON", + .off: "OFF" + ] } - @Parameter(title: "Action", optionsProvider: StringOptionsProvider()) - var action: String? + static let intentClassName = "OpenHABSetSwitchStateIntent" - struct StringOptionsProvider: DynamicOptionsProvider { - func results() async throws -> [String] { - // TODO: Return possible options here. - return [] - } - } + static var title: LocalizedStringResource = "Set Switch State" + static var description = IntentDescription("Set the state of a switch on or off") static var parameterSummary: some ParameterSummary { Summary("Send \(\.$action) to \(\.$item)") @@ -42,34 +40,44 @@ struct SetSwitchState: AppIntent, WidgetConfigurationIntent, CustomIntentMigrate static var predictionConfiguration: some IntentPredictionConfiguration { IntentPrediction(parameters: (\.$item, \.$action)) { item, action in DisplayRepresentation( - title: "Send \(action!) to \(item!)", + title: "Send \(action) to \(item)", subtitle: "" ) } } + @Parameter(title: "Item") + var item: ItemAppEntity + + @Parameter(title: "Action") + var action: Action + func perform() async throws -> some IntentResult { - // TODO: Place your refactored intent handler code here. + let validatedItem = await OpenHABItemCache.instance.getItem(name: item.id) + OpenHABItemCache.instance.sendCommand(validatedItem!, commandToSend: action.rawValue) return .result() } } -@available(iOS 16.0, macOS 13.0, watchOS 9.0, tvOS 16.0, *) -fileprivate extension IntentDialog { +@available(iOS 17.0, macOS 14.0, watchOS 10.0, tvOS 16.0, *) +private extension IntentDialog { static var itemParameterConfiguration: Self { "Switch name" } + static var actionParameterConfiguration: Self { "Action" } + static func responseSuccess(action: String, item: String) -> Self { "Sent the action of \(action) to switch \(item)" } + static func responseFailureInvalidItem(item: String) -> Self { "Sorry can't find \(item)" } + static func responseFailureInvalidAction(action: String, item: String) -> Self { "Action invalid: \(action) for \(item)" } } - diff --git a/openHAB/Resources/Base.lproj/Intents.intentdefinition b/openHAB/Resources/Base.lproj/Intents.intentdefinition index c15bff29a..37cb82d28 100644 --- a/openHAB/Resources/Base.lproj/Intents.intentdefinition +++ b/openHAB/Resources/Base.lproj/Intents.intentdefinition @@ -9,11 +9,11 @@ INIntentDefinitionNamespace aK4nIm INIntentDefinitionSystemVersion - 22G313 + 22G513 INIntentDefinitionToolsBuildVersion - 15A507 + 15C500b INIntentDefinitionToolsVersion - 15.0.1 + 15.2 INIntents diff --git a/openHABWidget/OpenHABWidgetBundle.swift b/openHABWidget/OpenHABWidgetBundle.swift index 32bedcfb7..ad121e117 100644 --- a/openHABWidget/OpenHABWidgetBundle.swift +++ b/openHABWidget/OpenHABWidgetBundle.swift @@ -1,4 +1,4 @@ -// Copyright (c) 2010-2023 Contributors to the openHAB project +// Copyright (c) 2010-2024 Contributors to the openHAB project // // See the NOTICE file(s) distributed with this work for additional // information. @@ -15,6 +15,6 @@ import WidgetKit @main struct OpenHABWidgetBundle: WidgetBundle { var body: some Widget { - OpenHABWidget() + OpenHABWidgetView() } } From efc25eeeeb3fff1a82571d50c328d715aa764e9f Mon Sep 17 00:00:00 2001 From: Tim Bert <5411131+timbms@users.noreply.github.com> Date: Wed, 21 Feb 2024 19:13:07 +0100 Subject: [PATCH 06/13] Migrate to App Intents Signed-off-by: Tim Bert <5411131+timbms@users.noreply.github.com> --- .../xcshareddata/xcschemes/openHABWatch (Notification).xcscheme | 2 +- openHAB.xcodeproj/xcshareddata/xcschemes/openHABWatch.xcscheme | 2 +- .../xcschemes/openHABWatchSwift (Complication).xcscheme | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/openHAB.xcodeproj/xcshareddata/xcschemes/openHABWatch (Notification).xcscheme b/openHAB.xcodeproj/xcshareddata/xcschemes/openHABWatch (Notification).xcscheme index a1eb22a3a..0ae68e971 100644 --- a/openHAB.xcodeproj/xcshareddata/xcschemes/openHABWatch (Notification).xcscheme +++ b/openHAB.xcodeproj/xcshareddata/xcschemes/openHABWatch (Notification).xcscheme @@ -1,6 +1,6 @@ Date: Wed, 21 Feb 2024 19:40:34 +0100 Subject: [PATCH 07/13] File location set to "Relative to Group" Signed-off-by: Tim Bert <5411131+timbms@users.noreply.github.com> --- openHAB.xcodeproj/project.pbxproj | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/openHAB.xcodeproj/project.pbxproj b/openHAB.xcodeproj/project.pbxproj index dfae363c8..c2f9192aa 100644 --- a/openHAB.xcodeproj/project.pbxproj +++ b/openHAB.xcodeproj/project.pbxproj @@ -386,12 +386,12 @@ DA2E0AA323DC96E9009B0A99 /* EncircledIconWithAction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EncircledIconWithAction.swift; sourceTree = ""; }; DA2E0B0D23DCC152009B0A99 /* MapView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MapView.swift; sourceTree = ""; }; DA2E0B0F23DCC439009B0A99 /* MapViewRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MapViewRow.swift; sourceTree = ""; }; - DA3D99982B7BB2DE001A903E /* SetSwitchState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SetSwitchState.swift; path = "/Users/tms/Developer/openhab-ios7/openhab-ios/openHAB/AppIntent/SetSwitchState.swift"; sourceTree = ""; }; - DA3D99992B7BB2DE001A903E /* GetItemState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = GetItemState.swift; path = "/Users/tms/Developer/openhab-ios7/openhab-ios/openHAB/AppIntent/GetItemState.swift"; sourceTree = ""; }; - DA3D999A2B7BB2DE001A903E /* SetContactStateValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SetContactStateValue.swift; path = "/Users/tms/Developer/openhab-ios7/openhab-ios/openHAB/AppIntent/SetContactStateValue.swift"; sourceTree = ""; }; - DA3D999B2B7BB2DF001A903E /* SetDimmerRollerValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SetDimmerRollerValue.swift; path = "/Users/tms/Developer/openhab-ios7/openhab-ios/openHAB/AppIntent/SetDimmerRollerValue.swift"; sourceTree = ""; }; - DA3D999D2B7BB2DF001A903E /* SetStringValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SetStringValue.swift; path = "/Users/tms/Developer/openhab-ios7/openhab-ios/openHAB/AppIntent/SetStringValue.swift"; sourceTree = ""; }; - DA3D999E2B7BB2DF001A903E /* SetColorValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SetColorValue.swift; path = "/Users/tms/Developer/openhab-ios7/openhab-ios/openHAB/AppIntent/SetColorValue.swift"; sourceTree = ""; }; + DA3D99982B7BB2DE001A903E /* SetSwitchState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetSwitchState.swift; sourceTree = ""; }; + DA3D99992B7BB2DE001A903E /* GetItemState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GetItemState.swift; sourceTree = ""; }; + DA3D999A2B7BB2DE001A903E /* SetContactStateValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetContactStateValue.swift; sourceTree = ""; }; + DA3D999B2B7BB2DF001A903E /* SetDimmerRollerValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetDimmerRollerValue.swift; sourceTree = ""; }; + DA3D999D2B7BB2DF001A903E /* SetStringValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetStringValue.swift; sourceTree = ""; }; + DA3D999E2B7BB2DF001A903E /* SetColorValue.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SetColorValue.swift; sourceTree = ""; }; DA3D99AB2B7D71E3001A903E /* SetNumberValue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SetNumberValue.swift; sourceTree = ""; }; DA3D99AD2B8127B4001A903E /* ItemAppEntity.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ItemAppEntity.swift; sourceTree = ""; }; DA4D4DB4233F9ACB00B37E37 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = ""; }; From 810c0af134cc379a58977bc32e304c8560b8344b Mon Sep 17 00:00:00 2001 From: Tim Bert <5411131+timbms@users.noreply.github.com> Date: Wed, 21 Feb 2024 19:58:37 +0100 Subject: [PATCH 08/13] Update actions/checkout@v4, maierj/fastlane-action@v3 to use Node.js 20 Signed-off-by: Tim Bert <5411131+timbms@users.noreply.github.com> --- .github/workflows/pull_requests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/pull_requests.yml b/.github/workflows/pull_requests.yml index e87a5f25e..448297ea3 100644 --- a/.github/workflows/pull_requests.yml +++ b/.github/workflows/pull_requests.yml @@ -14,7 +14,7 @@ jobs: with: xcode-version: latest-stable - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Install dependencies run: | @@ -25,6 +25,6 @@ jobs: LANG: en_US.UTF-8 LC_ALL: en_US.UTF-8 FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT: 60 - uses: maierj/fastlane-action@v2.3.0 + uses: maierj/fastlane-action@v3 with: lane: unittests From 5d51bdfba4ce4a4381f70e4165714a42557f7366 Mon Sep 17 00:00:00 2001 From: Tim Bert <5411131+timbms@users.noreply.github.com> Date: Wed, 21 Feb 2024 22:09:59 +0100 Subject: [PATCH 09/13] v3.0.0 Signed-off-by: Tim Bert <5411131+timbms@users.noreply.github.com> --- .github/workflows/pull_requests.yml | 2 +- BuildTools/Package.resolved | 4 ++-- openHAB/AppIntent/OpenHABShortcutProvider.swift | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.github/workflows/pull_requests.yml b/.github/workflows/pull_requests.yml index 448297ea3..d440a0b02 100644 --- a/.github/workflows/pull_requests.yml +++ b/.github/workflows/pull_requests.yml @@ -25,6 +25,6 @@ jobs: LANG: en_US.UTF-8 LC_ALL: en_US.UTF-8 FASTLANE_XCODEBUILD_SETTINGS_TIMEOUT: 60 - uses: maierj/fastlane-action@v3 + uses: maierj/fastlane-action@v3.0.0 with: lane: unittests diff --git a/BuildTools/Package.resolved b/BuildTools/Package.resolved index 9b421369d..8fc218a3c 100644 --- a/BuildTools/Package.resolved +++ b/BuildTools/Package.resolved @@ -5,8 +5,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/weakfl/SwiftFormatPlugin", "state" : { - "revision" : "6b9dc79c428f3237d4c10fa4605b499f5e06c7bd", - "version" : "0.53.0" + "revision" : "29d6c0bc4c078f819504d92fb5b359e63fd32046", + "version" : "0.53.2" } }, { diff --git a/openHAB/AppIntent/OpenHABShortcutProvider.swift b/openHAB/AppIntent/OpenHABShortcutProvider.swift index c9b3478de..edcde3811 100644 --- a/openHAB/AppIntent/OpenHABShortcutProvider.swift +++ b/openHAB/AppIntent/OpenHABShortcutProvider.swift @@ -24,5 +24,6 @@ struct OpenHABAppShortcutsProvider: AppShortcutsProvider { shortTitle: "Set switch" ) } + static var shortcutTileColor: ShortcutTileColor = .orange } From 5a99e6f98d6dcd3f58c0d221e41ccf0b855de633 Mon Sep 17 00:00:00 2001 From: Tim Bert <5411131+timbms@users.noreply.github.com> Date: Thu, 22 Feb 2024 08:54:38 +0100 Subject: [PATCH 10/13] Disabled addressSanitizer because of build error (to be reversed later) Raised IPHONEOS_DEPLOYMENT_TARGET to 13.0 Signed-off-by: Tim Bert <5411131+timbms@users.noreply.github.com> --- TestPlans/openHABTests.xctestplan | 3 --- openHAB.xcodeproj/project.pbxproj | 4 ++-- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/TestPlans/openHABTests.xctestplan b/TestPlans/openHABTests.xctestplan index 3ed419e45..a73ed46d8 100644 --- a/TestPlans/openHABTests.xctestplan +++ b/TestPlans/openHABTests.xctestplan @@ -4,9 +4,6 @@ "id" : "660BC591-F2EF-425A-B637-F63CCEF0251A", "name" : "ASAN", "options" : { - "addressSanitizer" : { - "enabled" : true - }, "undefinedBehaviorSanitizerEnabled" : true } } diff --git a/openHAB.xcodeproj/project.pbxproj b/openHAB.xcodeproj/project.pbxproj index c2f9192aa..a6c32348e 100644 --- a/openHAB.xcodeproj/project.pbxproj +++ b/openHAB.xcodeproj/project.pbxproj @@ -1847,7 +1847,7 @@ GCC_C_LANGUAGE_STANDARD = "compiler-default"; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INFOPLIST_FILE = openHABWatch/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "@executable_path/Frameworks", "@executable_path/../../Frameworks", @@ -1892,7 +1892,7 @@ GCC_C_LANGUAGE_STANDARD = "compiler-default"; GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; INFOPLIST_FILE = openHABWatch/Info.plist; - IPHONEOS_DEPLOYMENT_TARGET = 12.0; + IPHONEOS_DEPLOYMENT_TARGET = 13.0; LD_RUNPATH_SEARCH_PATHS = ( "@executable_path/Frameworks", "@executable_path/../../Frameworks", From 824ebd53fdd268655e51d2eb6401bb1f1ee6c70f Mon Sep 17 00:00:00 2001 From: Tim Bert <5411131+timbms@users.noreply.github.com> Date: Thu, 22 Feb 2024 11:29:50 +0100 Subject: [PATCH 11/13] Lifted minimum version for firebase to 10.0.0 Reenabled address sanitizer Signed-off-by: Tim Bert <5411131+timbms@users.noreply.github.com> --- TestPlans/openHABTests.xctestplan | 3 + openHAB.xcodeproj/project.pbxproj | 2 +- .../xcshareddata/swiftpm/Package.resolved | 61 +++++++++++-------- 3 files changed, 39 insertions(+), 27 deletions(-) diff --git a/TestPlans/openHABTests.xctestplan b/TestPlans/openHABTests.xctestplan index a73ed46d8..3ed419e45 100644 --- a/TestPlans/openHABTests.xctestplan +++ b/TestPlans/openHABTests.xctestplan @@ -4,6 +4,9 @@ "id" : "660BC591-F2EF-425A-B637-F63CCEF0251A", "name" : "ASAN", "options" : { + "addressSanitizer" : { + "enabled" : true + }, "undefinedBehaviorSanitizerEnabled" : true } } diff --git a/openHAB.xcodeproj/project.pbxproj b/openHAB.xcodeproj/project.pbxproj index a6c32348e..4fab7beb6 100644 --- a/openHAB.xcodeproj/project.pbxproj +++ b/openHAB.xcodeproj/project.pbxproj @@ -2440,7 +2440,7 @@ repositoryURL = "https://github.com/firebase/firebase-ios-sdk.git"; requirement = { kind = upToNextMajorVersion; - minimumVersion = 8.0.0; + minimumVersion = 10.0.0; }; }; 93F8064527AE7A050035A6B0 /* XCRemoteSwiftPackageReference "SwiftMessages" */ = { diff --git a/openHAB.xcworkspace/xcshareddata/swiftpm/Package.resolved b/openHAB.xcworkspace/xcshareddata/swiftpm/Package.resolved index b1fdc5be8..26b615f03 100644 --- a/openHAB.xcworkspace/xcshareddata/swiftpm/Package.resolved +++ b/openHAB.xcworkspace/xcshareddata/swiftpm/Package.resolved @@ -3,11 +3,11 @@ "pins": [ { "package": "abseil", - "repositoryURL": "https://github.com/firebase/abseil-cpp-SwiftPM.git", + "repositoryURL": "https://github.com/google/abseil-cpp-binary.git", "state": { "branch": null, - "revision": "fffc3c2729be5747390ad02d5100291a0d9ad26a", - "version": "0.20200225.4" + "revision": "bfc0b6f81adc06ce5121eb23f628473638d67c5c", + "version": "1.2022062300.0" } }, { @@ -29,12 +29,12 @@ } }, { - "package": "BoringSSL-GRPC", - "repositoryURL": "https://github.com/firebase/boringssl-SwiftPM.git", + "package": "AppCheck", + "repositoryURL": "https://github.com/google/app-check.git", "state": { "branch": null, - "revision": "734a8247442fde37df4364c21f6a0085b6a36728", - "version": "0.7.2" + "revision": "3e464dad87dad2d29bb29a97836789bf0f8f67d2", + "version": "10.18.1" } }, { @@ -69,8 +69,8 @@ "repositoryURL": "https://github.com/firebase/firebase-ios-sdk.git", "state": { "branch": null, - "revision": "5344857522053b5d4403ec8173ec0d23200a97ea", - "version": "8.11.0" + "revision": "f91c8167141d0279726c6f6d9d4a47c026785cbc", + "version": "10.21.0" } }, { @@ -96,8 +96,8 @@ "repositoryURL": "https://github.com/google/GoogleAppMeasurement.git", "state": { "branch": null, - "revision": "9b2f6aca5b4685c45f9f5481f19bee8e7982c538", - "version": "8.9.1" + "revision": "cb8617fab75d181270a1d8f763f26b15c73e2e1e", + "version": "10.21.0" } }, { @@ -105,8 +105,8 @@ "repositoryURL": "https://github.com/google/GoogleDataTransport.git", "state": { "branch": null, - "revision": "15ccdfd25ac55b9239b82809531ff26605e7556e", - "version": "9.1.2" + "revision": "a732a4b47f59e4f725a2ea10f0c77e93a7131117", + "version": "9.3.0" } }, { @@ -114,17 +114,17 @@ "repositoryURL": "https://github.com/google/GoogleUtilities.git", "state": { "branch": null, - "revision": "b3bb0c5551fb3f80ca939829639ab5b093edd14f", - "version": "7.7.0" + "revision": "bc27fad73504f3d4af235de451f02ee22586ebd3", + "version": "7.12.1" } }, { "package": "gRPC", - "repositoryURL": "https://github.com/firebase/grpc-SwiftPM.git", + "repositoryURL": "https://github.com/google/grpc-binary.git", "state": { "branch": null, - "revision": "fb405dd2c7901485f7e158b24e3a0a47e4efd8b5", - "version": "1.28.4" + "revision": "a673bc2937fbe886dd1f99c401b01b6d977a9c98", + "version": "1.49.1" } }, { @@ -132,8 +132,17 @@ "repositoryURL": "https://github.com/google/gtm-session-fetcher.git", "state": { "branch": null, - "revision": "bc6a19702ac76ac4e488b68148710eb815f9bc56", - "version": "1.7.0" + "revision": "76135c9f4e1ac85459d5fec61b6f76ac47ab3a4c", + "version": "3.3.1" + } + }, + { + "package": "InteropForGoogle", + "repositoryURL": "https://github.com/google/interop-ios-for-google-sdks.git", + "state": { + "branch": null, + "revision": "2d12673670417654f08f5f90fdd62926dc3a2648", + "version": "100.0.0" } }, { @@ -159,8 +168,8 @@ "repositoryURL": "https://github.com/firebase/nanopb.git", "state": { "branch": null, - "revision": "7ee9ef9f627d85cbe1b8c4f49a3ed26eed216c77", - "version": "2.30908.0" + "revision": "819d0a2173aff699fb8c364b6fb906f7cdb1a692", + "version": "2.30909.0" } }, { @@ -168,8 +177,8 @@ "repositoryURL": "https://github.com/google/promises.git", "state": { "branch": null, - "revision": "611337c330350c9c1823ad6d671e7f936af5ee13", - "version": "2.0.0" + "revision": "540318ecedd63d883069ae7f1ed811a2df00b6ac", + "version": "2.4.0" } }, { @@ -204,8 +213,8 @@ "repositoryURL": "https://github.com/apple/swift-protobuf.git", "state": { "branch": null, - "revision": "7e2c5f3cbbeea68e004915e3a8961e20bd11d824", - "version": "1.18.0" + "revision": "65e8f29b2d63c4e38e736b25c27b83e012159be8", + "version": "1.25.2" } }, { From f274b7c09f1f78354af5f8853f9a5fd27e3fbab0 Mon Sep 17 00:00:00 2001 From: Tim Bert <5411131+timbms@users.noreply.github.com> Date: Thu, 22 Feb 2024 13:27:39 +0100 Subject: [PATCH 12/13] Timeout in RESTAPITests increased to 6s --- OpenHABCore/Tests/OpenHABCoreTests/RESTAPITests.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/OpenHABCore/Tests/OpenHABCoreTests/RESTAPITests.swift b/OpenHABCore/Tests/OpenHABCoreTests/RESTAPITests.swift index feb81bae6..250eeb0b5 100644 --- a/OpenHABCore/Tests/OpenHABCoreTests/RESTAPITests.swift +++ b/OpenHABCore/Tests/OpenHABCoreTests/RESTAPITests.swift @@ -62,7 +62,7 @@ final class RESTAPITests: XCTestCase { registrationOperation.resume() // then - wait(for: [expectation], timeout: 3) + wait(for: [expectation], timeout: 6) } func testRegisterApp() { @@ -77,7 +77,7 @@ final class RESTAPITests: XCTestCase { expectation.fulfill() } // then - wait(for: [expectation], timeout: 3) + wait(for: [expectation], timeout: 6) } func testSitemap() { @@ -92,7 +92,7 @@ final class RESTAPITests: XCTestCase { expectation.fulfill() } // then - wait(for: [expectation], timeout: 3) + wait(for: [expectation], timeout: 6) } func testTracker() { @@ -107,6 +107,6 @@ final class RESTAPITests: XCTestCase { expectation.fulfill() } // then - wait(for: [expectation], timeout: 3) + wait(for: [expectation], timeout: 6) } } From 2d1fd425b7e899897ed97033a87a2fa5d55e2fdc Mon Sep 17 00:00:00 2001 From: Tim Bert <5411131+timbms@users.noreply.github.com> Date: Wed, 12 Jun 2024 11:08:05 +0200 Subject: [PATCH 13/13] Prefix embedded binary's bundle identifier with the parent app's bundle identifier --- openHAB.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openHAB.xcodeproj/project.pbxproj b/openHAB.xcodeproj/project.pbxproj index 218408e02..24d76ace3 100644 --- a/openHAB.xcodeproj/project.pbxproj +++ b/openHAB.xcodeproj/project.pbxproj @@ -1780,7 +1780,7 @@ MARKETING_VERSION = 2.4.60; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = es.spaphone.openHABUITests; + PRODUCT_BUNDLE_IDENTIFIER = org.openhab.app.UITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_INSTALL_OBJC_HEADER = NO; @@ -1823,7 +1823,7 @@ MARKETING_VERSION = 2.4.60; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = es.spaphone.openHABUITests; + PRODUCT_BUNDLE_IDENTIFIER = org.openhab.app.UITests; PRODUCT_NAME = "$(TARGET_NAME)"; SWIFT_INSTALL_OBJC_HEADER = NO; SWIFT_OPTIMIZATION_LEVEL = "-O"; @@ -2055,7 +2055,7 @@ MARKETING_VERSION = 2.4.60; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = es.spaphone.openhab.OpenHABWidget; + PRODUCT_BUNDLE_IDENTIFIER = org.openhab.app.widget; PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = auto; SKIP_INSTALL = YES; @@ -2112,7 +2112,7 @@ MARKETING_VERSION = 2.4.60; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; - PRODUCT_BUNDLE_IDENTIFIER = es.spaphone.openhab.OpenHABWidget; + PRODUCT_BUNDLE_IDENTIFIER = org.openhab.app.widget; PRODUCT_NAME = "$(TARGET_NAME)"; PROVISIONING_PROFILE_SPECIFIER = ""; SDKROOT = auto;