From 8bb4876fcebddb823231f0003ae1e3bc4f70b2bf Mon Sep 17 00:00:00 2001 From: Roman Schlagowsky Date: Mon, 4 Mar 2024 11:38:47 +0100 Subject: [PATCH] Final adjustments for alpha release (#37) * Remove CocoaPods for now * Provide index instead of context * Pass "missing entitlement" error to state handler * Fix build badge in README --- Documentation/GettingStarted.md | 28 ++--- Documentation/Layout/README.md | 14 +-- .../1_StatelessStreamDeckLayout.swift | 14 +-- .../Example App/StreamDeckKitExampleApp.swift | 7 +- Gemfile | 3 - Gemfile.lock | 107 ------------------ README.md | 28 ++--- Sources/StreamDeckCApi/StreamDeckCApi.c | 2 + .../StreamDeckCApi/include/StreamDeckCApi.h | 3 + .../Layout/StreamDeckDialAreaLayout.swift | 13 ++- .../Layout/StreamDeckKeypadLayout.swift | 4 +- .../Session/InternalStreamDeckSession.swift | 3 + ...n.State+CustomDebugStringConvertible.swift | 1 + .../Session/StreamDeckSession.swift | 3 + .../StreamDeckSimulatorClient.swift | 2 +- .../Views/SimulatorTouchView.swift | 24 ++-- .../Views/StreamDeckSimulatorView.swift | 20 +--- StreamDeckCApi.podspec | 22 ---- StreamDeckKit.podspec | 19 ---- StreamDeckSimulator.podspec | 22 ---- .../StreamDeckLayoutTests.swift | 4 +- 21 files changed, 84 insertions(+), 259 deletions(-) delete mode 100644 Gemfile delete mode 100644 Gemfile.lock delete mode 100644 StreamDeckCApi.podspec delete mode 100644 StreamDeckKit.podspec delete mode 100644 StreamDeckSimulator.podspec diff --git a/Documentation/GettingStarted.md b/Documentation/GettingStarted.md index 8ea04fd4..c9052153 100644 --- a/Documentation/GettingStarted.md +++ b/Documentation/GettingStarted.md @@ -20,7 +20,11 @@ During the alpha phase, the app is not in available in the App Store. [Click her ## Installation -### Swift Package Manager +### Package + +You can add the library to your XCode project via Swift Package Manager. See "[Adding package dependencies to your app](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app)". + +If you want to add it to your own libraries `Package.swift`, use this code instead: ```swift dependencies: [ @@ -28,24 +32,12 @@ dependencies: [ ] ``` -### CocoaPods - -Example Podfile +### Entitlements -```Ruby -platform :ios, '16.0' - -target 'YourAppTarget' do - use_frameworks! - pod 'StreamDeckKit' - pod 'StreamDeckSimulator', :configurations => ['Debug'] -end -``` +In order to connect to the Stream Deck driver, you need to add the "[Communicates with Drivers](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_driverkit_communicates-with-drivers)" (`com.apple.developer.driverkit.communicates-with-drivers`) capability to your app target. Refer to "[Adding capabilities to your app](https://developer.apple.com/documentation/xcode/adding-capabilities-to-your-app/)" for guidance. ## First steps -First, add the [DriverKit Communicates with Drivers](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_driverkit_communicates-with-drivers) capability to your app target. Refer to [Adding capabilities to your app](https://developer.apple.com/documentation/xcode/adding-capabilities-to-your-app/) for guidance. - Rendering content on a Stream Deck is very simple with SwiftUI, much like designing a typical app UI. ```swift @@ -74,15 +66,15 @@ struct MyFirstStreamDeckLayout { StreamDeckLayout { // Define key area // Use StreamDeckKeyAreaLayout for rendering separate keys - StreamDeckKeyAreaLayout { context in + StreamDeckKeyAreaLayout { keyIndex in // Define content for each key. - // StreamDeckKeyAreaLayout provides a context for each available key, + // StreamDeckKeyAreaLayout provides an index for each available key, // and StreamDeckKeyView provides a callback for the key action // Example: StreamDeckKeyView { pressed in print("pressed \(pressed)") } content: { - Text("\(context.index)") + Text("\(keyIndex)") .frame(maxWidth: .infinity, maxHeight: .infinity) .background(.teal) } diff --git a/Documentation/Layout/README.md b/Documentation/Layout/README.md index 0a63cce3..f213773d 100644 --- a/Documentation/Layout/README.md +++ b/Documentation/Layout/README.md @@ -44,15 +44,15 @@ struct StatelessStreamDeckLayout { StreamDeckLayout { // Define key area // Use StreamDeckKeyAreaLayout for rendering separate keys - StreamDeckKeyAreaLayout { context in + StreamDeckKeyAreaLayout { keyIndex in // Define content for each key. - // StreamDeckKeyAreaLayout provides a context for each available key, + // StreamDeckKeyAreaLayout provides an index for each available key, // and StreamDeckKeyView provides a callback for the key action // Example: StreamDeckKeyView { pressed in print("pressed \(pressed)") } content: { - Text("\(context.index)") + Text("\(keyIndex)") .frame(maxWidth: .infinity, maxHeight: .infinity) .background(.teal) } @@ -60,9 +60,9 @@ struct StatelessStreamDeckLayout { } windowArea: { // Define window area // Use StreamDeckDialAreaLayout for rendering separate parts of the display - StreamDeckDialAreaLayout { context in + StreamDeckDialAreaLayout { dialIndex in // Define content for each dial - // StreamDeckDialAreaLayout provides a context for each available dial, + // StreamDeckDialAreaLayout provides an index for each available dial, // and StreamDeckDialView provides callbacks for the dial actions // Example: StreamDeckDialView { rotations in @@ -72,9 +72,9 @@ struct StatelessStreamDeckLayout { } touch: { location in print("touched at \(location)") } content: { - Text("\(context.index)") + Text("\(dialIndex)") .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(Color(white: Double(context.index) / 5 + 0.5)) + .background(Color(white: Double(dialIndex) / 5 + 0.5)) } } }.background(.indigo) diff --git a/Example/Example App/Examples/1_StatelessStreamDeckLayout.swift b/Example/Example App/Examples/1_StatelessStreamDeckLayout.swift index 2dfc6d15..d5b332bb 100644 --- a/Example/Example App/Examples/1_StatelessStreamDeckLayout.swift +++ b/Example/Example App/Examples/1_StatelessStreamDeckLayout.swift @@ -15,15 +15,15 @@ struct StatelessStreamDeckLayout { StreamDeckLayout { // Define key area // Use StreamDeckKeyAreaLayout for rendering separate keys - StreamDeckKeyAreaLayout { context in + StreamDeckKeyAreaLayout { keyIndex in // Define content for each key. - // StreamDeckKeyAreaLayout provides a context for each available key, + // StreamDeckKeyAreaLayout provides an index for each available key, // and StreamDeckKeyView provides a callback for the key action // Example: StreamDeckKeyView { pressed in print("pressed \(pressed)") } content: { - Text("\(context.index)") + Text("\(keyIndex)") .frame(maxWidth: .infinity, maxHeight: .infinity) .background(.teal) } @@ -31,9 +31,9 @@ struct StatelessStreamDeckLayout { } windowArea: { // Define window area // Use StreamDeckDialAreaLayout for rendering separate parts of the display - StreamDeckDialAreaLayout { context in + StreamDeckDialAreaLayout { dialIndex in // Define content for each dial - // StreamDeckDialAreaLayout provides a context for each available dial, + // StreamDeckDialAreaLayout provides an index for each available dial, // and StreamDeckDialView provides callbacks for the dial actions // Example: StreamDeckDialView { rotations in @@ -43,9 +43,9 @@ struct StatelessStreamDeckLayout { } touch: { location in print("touched at \(location)") } content: { - Text("\(context.index)") + Text("\(dialIndex)") .frame(maxWidth: .infinity, maxHeight: .infinity) - .background(Color(white: Double(context.index) / 5 + 0.5)) + .background(Color(white: Double(dialIndex) / 5 + 0.5)) } } }.background(.indigo) diff --git a/Example/Example App/StreamDeckKitExampleApp.swift b/Example/Example App/StreamDeckKitExampleApp.swift index 0a3e0317..dc8f52e0 100644 --- a/Example/Example App/StreamDeckKitExampleApp.swift +++ b/Example/Example App/StreamDeckKitExampleApp.swift @@ -16,9 +16,10 @@ struct StreamDeckKitExampleApp: App { // Uncomment the next line to enable StreamDeckKit internal logging. // streamDeckLoggingHandler = { os_log($0, "\($1)") } - StreamDeckSession.setUp(newDeviceHandler: { - $0.render(BaseStreamDeckView()) - }) + StreamDeckSession.setUp( + stateHandler: { os_log("Stream Deck session state: %s", String(describing: $0)) }, + newDeviceHandler: { $0.render(BaseStreamDeckView()) } + ) } var body: some Scene { diff --git a/Gemfile b/Gemfile deleted file mode 100644 index fb666243..00000000 --- a/Gemfile +++ /dev/null @@ -1,3 +0,0 @@ -source "https://rubygems.org" - -gem "cocoapods", '~>1.14' \ No newline at end of file diff --git a/Gemfile.lock b/Gemfile.lock deleted file mode 100644 index c6fe1b3c..00000000 --- a/Gemfile.lock +++ /dev/null @@ -1,107 +0,0 @@ -GEM - remote: https://rubygems.org/ - specs: - CFPropertyList (3.0.6) - rexml - activesupport (7.1.2) - base64 - bigdecimal - concurrent-ruby (~> 1.0, >= 1.0.2) - connection_pool (>= 2.2.5) - drb - i18n (>= 1.6, < 2) - minitest (>= 5.1) - mutex_m - tzinfo (~> 2.0) - addressable (2.8.6) - public_suffix (>= 2.0.2, < 6.0) - algoliasearch (1.27.5) - httpclient (~> 2.8, >= 2.8.3) - json (>= 1.5.1) - atomos (0.1.3) - base64 (0.2.0) - bigdecimal (3.1.5) - claide (1.1.0) - cocoapods (1.14.3) - addressable (~> 2.8) - claide (>= 1.0.2, < 2.0) - cocoapods-core (= 1.14.3) - cocoapods-deintegrate (>= 1.0.3, < 2.0) - cocoapods-downloader (>= 2.1, < 3.0) - cocoapods-plugins (>= 1.0.0, < 2.0) - cocoapods-search (>= 1.0.0, < 2.0) - cocoapods-trunk (>= 1.6.0, < 2.0) - cocoapods-try (>= 1.1.0, < 2.0) - colored2 (~> 3.1) - escape (~> 0.0.4) - fourflusher (>= 2.3.0, < 3.0) - gh_inspector (~> 1.0) - molinillo (~> 0.8.0) - nap (~> 1.0) - ruby-macho (>= 2.3.0, < 3.0) - xcodeproj (>= 1.23.0, < 2.0) - cocoapods-core (1.14.3) - activesupport (>= 5.0, < 8) - addressable (~> 2.8) - algoliasearch (~> 1.0) - concurrent-ruby (~> 1.1) - fuzzy_match (~> 2.0.4) - nap (~> 1.0) - netrc (~> 0.11) - public_suffix (~> 4.0) - typhoeus (~> 1.0) - cocoapods-deintegrate (1.0.5) - cocoapods-downloader (2.1) - cocoapods-plugins (1.0.0) - nap - cocoapods-search (1.0.1) - cocoapods-trunk (1.6.0) - nap (>= 0.8, < 2.0) - netrc (~> 0.11) - cocoapods-try (1.2.0) - colored2 (3.1.2) - concurrent-ruby (1.2.2) - connection_pool (2.4.1) - drb (2.2.0) - ruby2_keywords - escape (0.0.4) - ethon (0.16.0) - ffi (>= 1.15.0) - ffi (1.16.3) - fourflusher (2.3.1) - fuzzy_match (2.0.4) - gh_inspector (1.1.3) - httpclient (2.8.3) - i18n (1.14.1) - concurrent-ruby (~> 1.0) - json (2.7.1) - minitest (5.20.0) - molinillo (0.8.0) - mutex_m (0.2.0) - nanaimo (0.3.0) - nap (1.1.0) - netrc (0.11.0) - public_suffix (4.0.7) - rexml (3.2.6) - ruby-macho (2.5.1) - ruby2_keywords (0.0.5) - typhoeus (1.4.1) - ethon (>= 0.9.0) - tzinfo (2.0.6) - concurrent-ruby (~> 1.0) - xcodeproj (1.23.0) - CFPropertyList (>= 2.3.3, < 4.0) - atomos (~> 0.1.3) - claide (>= 1.0.2, < 2.0) - colored2 (~> 3.1) - nanaimo (~> 0.3.0) - rexml (~> 3.2.4) - -PLATFORMS - arm64-darwin-23 - -DEPENDENCIES - cocoapods (~> 1.14) - -BUNDLED WITH - 2.4.22 diff --git a/README.md b/README.md index ec8b015d..71d49763 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ Stream Deck Kit is a Swift Library for controlling physical [Elgato Stream Deck](https://www.elgato.com/stream-deck) devices with an iPadOS app. - - - +![Build all targets workflow badge](https://github.com/elgatosf/streamdeck-kit-ipad/actions/workflows/build-all-targets.yml/badge.svg) +![Lint workflow badge](https://github.com/elgatosf/streamdeck-kit-ipad/actions/workflows/lint.yml/badge.svg) +![Tests workflow badge](https://github.com/elgatosf/streamdeck-kit-ipad/actions/workflows/test.yml/badge.svg) ## Features @@ -46,7 +46,11 @@ However, if you want to verify your implementation using the [Stream Deck Simula ## Installation -### Swift Package Manager +### Package + +You can add the library to your XCode project via Swift Package Manager. See "[Adding package dependencies to your app](https://developer.apple.com/documentation/xcode/adding-package-dependencies-to-your-app)". + +If you want to add it to your own libraries `Package.swift`, use this code instead: ```swift dependencies: [ @@ -54,24 +58,12 @@ dependencies: [ ] ``` -### CocoaPods - -Example Podfile +### Entitlements -```Ruby -platform :ios, '16.0' - -target 'YourAppTarget' do - use_frameworks! - pod 'StreamDeckKit' - pod 'StreamDeckSimulator', :configurations => ['Debug'] -end -``` +In order to connect to the Stream Deck driver, you need to add the "[Communicates with Drivers](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_driverkit_communicates-with-drivers)" (`com.apple.developer.driverkit.communicates-with-drivers`) capability to your app target. Refer to "[Adding capabilities to your app](https://developer.apple.com/documentation/xcode/adding-capabilities-to-your-app/)" for guidance. ## Getting started -First, add the [DriverKit Communicates with Drivers](https://developer.apple.com/documentation/bundleresources/entitlements/com_apple_developer_driverkit_communicates-with-drivers) capability to your app target. Refer to [Adding capabilities to your app](https://developer.apple.com/documentation/xcode/adding-capabilities-to-your-app/) for guidance. - Rendering content on a Stream Deck is very simple with SwiftUI, much like designing a typical app UI. ```swift diff --git a/Sources/StreamDeckCApi/StreamDeckCApi.c b/Sources/StreamDeckCApi/StreamDeckCApi.c index 9ea2c35d..494438f3 100644 --- a/Sources/StreamDeckCApi/StreamDeckCApi.c +++ b/Sources/StreamDeckCApi/StreamDeckCApi.c @@ -27,3 +27,5 @@ #include #import "include/StreamDeckCApi.h" + +const IOReturn sdkIOReturnNotPermitted = kIOReturnNotPermitted; diff --git a/Sources/StreamDeckCApi/include/StreamDeckCApi.h b/Sources/StreamDeckCApi/include/StreamDeckCApi.h index 6d455718..0c22c577 100644 --- a/Sources/StreamDeckCApi/include/StreamDeckCApi.h +++ b/Sources/StreamDeckCApi/include/StreamDeckCApi.h @@ -31,4 +31,7 @@ #include #include "StreamDeckDriverShared.h" +/// Exported error constant to handle problems with "Communicates with Driver" capability in Swift. +extern const IOReturn sdkIOReturnNotPermitted; + #endif /* StreamDeckCApi_h */ diff --git a/Sources/StreamDeckKit/Layout/StreamDeckDialAreaLayout.swift b/Sources/StreamDeckKit/Layout/StreamDeckDialAreaLayout.swift index 9f9a1f69..81ad5e23 100644 --- a/Sources/StreamDeckKit/Layout/StreamDeckDialAreaLayout.swift +++ b/Sources/StreamDeckKit/Layout/StreamDeckDialAreaLayout.swift @@ -41,9 +41,10 @@ public struct StreamDeckDialAreaLayout: View { /// A handler for press events on a rotary encoder(dial). /// /// The first parameter is the index of the dial. The second one indicates if the dial is down or not. - public typealias DialPressHandler = @MainActor (Int, Bool) -> Void + public typealias DialPressHandler = @MainActor (_ index: Int, _ isPressed: Bool) -> Void public typealias TouchHandler = @MainActor (CGPoint) -> Void - public typealias FlingHandler = @MainActor (CGPoint, CGPoint, InputEvent.Direction) -> Void + public typealias FlingHandler = @MainActor (_ start: CGPoint, _ end: CGPoint, _ direction: InputEvent.Direction) -> Void + public typealias DialProvider = @MainActor (_ keyIndex: Int) -> Dial @Environment(\.streamDeckViewContext) private var context @@ -51,14 +52,14 @@ public struct StreamDeckDialAreaLayout: View { private let press: DialPressHandler? private let touch: TouchHandler? private let fling: FlingHandler? - @ViewBuilder private let dial: @MainActor (StreamDeckViewContext) -> Dial + @ViewBuilder private let dial: DialProvider public init( rotate: DialRotationHandler? = nil, press: DialPressHandler? = nil, touch: TouchHandler? = nil, fling: FlingHandler? = nil, - @ViewBuilder dial: @escaping @MainActor (StreamDeckViewContext) -> Dial + @ViewBuilder dial: @escaping DialProvider ) { self.rotate = rotate self.press = press @@ -72,7 +73,7 @@ public struct StreamDeckDialAreaLayout: View { press: @escaping @MainActor (Int) -> Void, touch: TouchHandler? = nil, fling: FlingHandler? = nil, - @ViewBuilder dial: @escaping @MainActor (StreamDeckViewContext) -> Dial + @ViewBuilder dial: @escaping DialProvider ) { self.init( rotate: rotate, @@ -96,7 +97,7 @@ public struct StreamDeckDialAreaLayout: View { index: section ) - dial(dialContext) + dial(dialContext.index) .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .center) .environment(\.streamDeckViewContext, dialContext) } diff --git a/Sources/StreamDeckKit/Layout/StreamDeckKeypadLayout.swift b/Sources/StreamDeckKit/Layout/StreamDeckKeypadLayout.swift index f85cf6c5..399fb60c 100644 --- a/Sources/StreamDeckKit/Layout/StreamDeckKeypadLayout.swift +++ b/Sources/StreamDeckKit/Layout/StreamDeckKeypadLayout.swift @@ -35,7 +35,7 @@ public struct StreamDeckKeyAreaLayout: View { /// A factory function that provides a view for a key. /// /// Use the ``StreamDeckViewContext/index`` property of the context parameter to distinguish keys. - public typealias KeyViewProvider = @MainActor (StreamDeckViewContext) -> Key + public typealias KeyViewProvider = @MainActor (_ keyIndex: Int) -> Key @Environment(\.streamDeckViewContext) private var context @@ -67,7 +67,7 @@ public struct StreamDeckKeyAreaLayout: View { index: position ) - keyView(keyContext) + keyView(keyContext.index) .frame(width: keySize.width, height: keySize.height) .environment(\.streamDeckViewContext, keyContext) } diff --git a/Sources/StreamDeckKit/Session/InternalStreamDeckSession.swift b/Sources/StreamDeckKit/Session/InternalStreamDeckSession.swift index 47aaf016..7ca38229 100644 --- a/Sources/StreamDeckKit/Session/InternalStreamDeckSession.swift +++ b/Sources/StreamDeckKit/Session/InternalStreamDeckSession.swift @@ -99,6 +99,9 @@ final actor InternalStreamDeckSession { guard ret == kIOReturnSuccess else { os_log(.error, "Failed opening service with error: \(String(ioReturn: ret)).") + if ret == sdkIOReturnNotPermitted { + state.value = .failed(.missingEntitlement) + } continue } diff --git a/Sources/StreamDeckKit/Session/StreamDeckSession.State+CustomDebugStringConvertible.swift b/Sources/StreamDeckKit/Session/StreamDeckSession.State+CustomDebugStringConvertible.swift index 1fd103b4..d20aa2fb 100644 --- a/Sources/StreamDeckKit/Session/StreamDeckSession.State+CustomDebugStringConvertible.swift +++ b/Sources/StreamDeckKit/Session/StreamDeckSession.State+CustomDebugStringConvertible.swift @@ -36,6 +36,7 @@ extension StreamDeckSession.State: CustomDebugStringConvertible { switch sessionError { case .unexpectedDriverError: return ".failed(.unexpectedDriverError)" case .driverVersionMismatch: return ".failed(.driverVersionMismatch)" + case .missingEntitlement: return ".failed(.missingEntitlement)" } } } diff --git a/Sources/StreamDeckKit/Session/StreamDeckSession.swift b/Sources/StreamDeckKit/Session/StreamDeckSession.swift index dd547647..df7df6a4 100644 --- a/Sources/StreamDeckKit/Session/StreamDeckSession.swift +++ b/Sources/StreamDeckKit/Session/StreamDeckSession.swift @@ -72,6 +72,9 @@ public final class StreamDeckSession { case unexpectedDriverError /// The driver has a different major version. Either the SDK or the driver app needs an update. case driverVersionMismatch + /// The app needs to have the "Communicates with Drivers" + /// (com.apple.developer.driverkit.communicates-with-drivers) capability set in its entitlements. + case missingEntitlement } /// Reflects the current state of a StreamDeck session. diff --git a/Sources/StreamDeckSimulator/StreamDeckSimulatorClient.swift b/Sources/StreamDeckSimulator/StreamDeckSimulatorClient.swift index ea078bbb..e02aecb4 100644 --- a/Sources/StreamDeckSimulator/StreamDeckSimulatorClient.swift +++ b/Sources/StreamDeckSimulator/StreamDeckSimulatorClient.swift @@ -31,7 +31,7 @@ import StreamDeckCApi import StreamDeckKit import UIKit -public final class StreamDeckSimulatorClient { +final class StreamDeckSimulatorClient { private let capabilities: DeviceCapabilities private let brightnessSubject = CurrentValueSubject(0) diff --git a/Sources/StreamDeckSimulator/Views/SimulatorTouchView.swift b/Sources/StreamDeckSimulator/Views/SimulatorTouchView.swift index a4bb731e..8860e606 100644 --- a/Sources/StreamDeckSimulator/Views/SimulatorTouchView.swift +++ b/Sources/StreamDeckSimulator/Views/SimulatorTouchView.swift @@ -28,24 +28,34 @@ import SwiftUI import StreamDeckKit -struct SimulatorTouchView: View { +@StreamDeckView +struct SimulatorTouchView { - let onTouch: (CGPoint) -> Void - let onFling: (CGPoint, CGPoint) -> Void + let client: StreamDeckSimulatorClient? - var body: some View { + var streamDeckBody: some View { StreamDeckDialView { Color.clear } .contentShape(Rectangle()) .frame(maxWidth: .infinity, maxHeight: .infinity) - .onTapGesture(coordinateSpace: .local) { location in - onTouch(location) + .onTapGesture(coordinateSpace: .local) { localLocation in + guard let client = client else { return } + let x = CGFloat(viewIndex) * viewSize.width + localLocation.x + Task { await client.emit(.touch(.init(x: x, y: localLocation.y))) } } .gesture( DragGesture(minimumDistance: 10, coordinateSpace: .local) .onEnded { value in - onFling(value.startLocation, value.location) + guard let client = client else { return } + let startX = CGFloat(viewIndex) * viewSize.width + value.startLocation.x + let endX = CGFloat(viewIndex) * viewSize.width + value.location.x + Task { + await client.emit(.fling( + start: .init(x: startX, y: value.startLocation.y), + end: .init(x: endX, y: value.location.y) + )) + } } ) } diff --git a/Sources/StreamDeckSimulator/Views/StreamDeckSimulatorView.swift b/Sources/StreamDeckSimulator/Views/StreamDeckSimulatorView.swift index b8afeff6..4a6e1335 100644 --- a/Sources/StreamDeckSimulator/Views/StreamDeckSimulatorView.swift +++ b/Sources/StreamDeckSimulator/Views/StreamDeckSimulatorView.swift @@ -169,22 +169,12 @@ private extension StreamDeckSimulatorView { @ViewBuilder var touchPad: some View { StreamDeckLayout { - StreamDeckKeyAreaLayout { context in - SimulatorKeyView(client: client, index: context.index) + StreamDeckKeyAreaLayout { keyIndex in + SimulatorKeyView(client: client, index: keyIndex) } } windowArea: { - StreamDeckDialAreaLayout { context in - SimulatorTouchView { localLocation in - let x = CGFloat(context.index) * context.size.width + localLocation.x - client.emit(.touch(.init(x: x, y: localLocation.y))) - } onFling: { startLocation, endLocation in - let startX = CGFloat(context.index) * context.size.width + startLocation.x - let endX = CGFloat(context.index) * context.size.width + endLocation.x - client.emit(.fling( - start: .init(x: startX, y: startLocation.y), - end: .init(x: endX, y: endLocation.y) - )) - } + StreamDeckDialAreaLayout { _ in + SimulatorTouchView(client: client) } } .background { @@ -216,7 +206,7 @@ private extension StreamDeckSimulatorView { } } windowArea: { StreamDeckDialAreaLayout { _ in - SimulatorTouchView { _ in } onFling: { _, _ in } + SimulatorTouchView(client: nil) .background { Color.clear.border(.red) } diff --git a/StreamDeckCApi.podspec b/StreamDeckCApi.podspec deleted file mode 100644 index 0325afe7..00000000 --- a/StreamDeckCApi.podspec +++ /dev/null @@ -1,22 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'StreamDeckCApi' - s.version = '0.0.1' - s.swift_version = '5.9' - - s.summary = 'C header for StreamDeckKit. Not for standalone use.' - s.author = { 'Elgato' => 'info@elgato.com' } - s.homepage = 'https://docs.elgato.com/ipad' - s.license = { :type => 'MIT', :file => 'LICENSE' } - s.source = { :git => 'https://github.com/elgatosf/streamdeck-kit-ipad.git', :tag => "#{s.version}" } - - s.requires_arc = true - s.frameworks = 'IOKit' - s.source_files = "Sources/#{s.name}/**/*.{c,h}" - s.public_header_files = "Sources/#{s.name}/**/*.h" - - # See: https://github.com/CocoaPods/CocoaPods/issues/12073#issuecomment-1737821281 - s.xcconfig = { 'ENABLE_USER_SCRIPT_SANDBOXING' => false } - - s.platform = :ios, '16.0' - s.ios.deployment_target = '16' -end diff --git a/StreamDeckKit.podspec b/StreamDeckKit.podspec deleted file mode 100644 index 8482f940..00000000 --- a/StreamDeckKit.podspec +++ /dev/null @@ -1,19 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'StreamDeckKit' - s.version = '0.0.1' - s.swift_version = '5.9' - - s.summary = 'Integrate StreamDeck hardware into your App' - s.author = { 'Elgato' => 'info@elgato.com' } - s.homepage = 'https://docs.elgato.com/ipad' - s.license = { :type => 'MIT', :file => 'LICENSE' } - s.source = { :git => 'https://github.com/elgatosf/streamdeck-kit-ipad.git', :tag => "#{s.version}" } - - s.requires_arc = true - s.frameworks = 'UIKit', 'SwiftUI' - s.source_files = "Sources/#{s.name}/**/*.swift" - s.dependency 'StreamDeckCApi', "#{s.version.to_s}" - - s.platform = :ios, '16.0' - s.ios.deployment_target = '16' -end diff --git a/StreamDeckSimulator.podspec b/StreamDeckSimulator.podspec deleted file mode 100644 index 0b577282..00000000 --- a/StreamDeckSimulator.podspec +++ /dev/null @@ -1,22 +0,0 @@ -Pod::Spec.new do |s| - s.name = 'StreamDeckSimulator' - s.version = '0.0.1' - s.swift_version = '5.9' - - s.summary = 'Simulate different StreamDeck devices to test your StreamDeckKit integration.' - s.author = { 'Elgato' => 'info@elgato.com' } - s.homepage = 'https://docs.elgato.com/ipad' - s.license = { :type => 'MIT', :file => 'LICENSE' } - s.source = { :git => 'https://github.com/elgatosf/streamdeck-kit-ipad.git', :tag => "#{s.version}" } - - s.requires_arc = true - s.source_files = "Sources/#{s.name}/**/*.swift" - s.dependency 'StreamDeckKit', "#{s.version.to_s}" - - # To be compatible with SPM integration, we give the resource bundle the same name as SPM would do. - # See: https://medium.com/clutter-engineering/supporting-both-swift-package-manager-and-cocoapods-in-your-library-861f00b6b0f9#8694 - s.resource_bundles = { "StreamDeckKit_#{s.name}" => ["Sources/#{s.name}/Resources/**/*"] } - - s.platform = :ios, '16.0' - s.ios.deployment_target = '16' -end diff --git a/Tests/StreamDeckSDKTests/StreamDeckLayoutTests.swift b/Tests/StreamDeckSDKTests/StreamDeckLayoutTests.swift index 48c116f5..35926221 100644 --- a/Tests/StreamDeckSDKTests/StreamDeckLayoutTests.swift +++ b/Tests/StreamDeckSDKTests/StreamDeckLayoutTests.swift @@ -141,9 +141,9 @@ final class StreamDeckLayoutTests: XCTestCase { var events = [(index: Int, pressed: Bool)]() try await robot.use(.pedal, rendering: StreamDeckLayout(keyArea: { - StreamDeckKeyAreaLayout { context in + StreamDeckKeyAreaLayout { keyIndex in StreamDeckKeyView { pressed in - events.append((index: context.index, pressed: pressed)) + events.append((index: keyIndex, pressed: pressed)) } content: { EmptyView() } } }), waitForLayout: false)