Add visionOS support#3
Draft
owenselles wants to merge 14 commits into
Draft
Conversation
Add platform-specific support for tvOS and visionOS across project and runtime code.
- Xcode project: add SUPPORTED_PLATFORMS, disable Mac Catalyst, and include tvOS device family ("3,7").
- GFNStreamController: guard tvOS-only remoteMode and toggle; adjust AVAudioSession setup (Bluetooth options on tvOS, simplified handling for other platforms) and use visionOS for microphone permission request.
- InputSender: make RemoteInputMode, remote sensitivity, micro-gamepad handling, and related logic tvOS-only (Siri Remote). Ensure tick() processes micro gamepad only on tvOS and keep existing extended gamepad handling for other platforms.
- StreamView: gate onExitCommand to tvOS; show an explicit menu button on non-tvOS (visionOS) and show remote-mode toggle only on tvOS.
- VideoSurfaceView: use layerClass override on tvOS but add AVSampleBufferDisplayLayer as a sublayer on visionOS (and update layoutSubviews) because layerClass is not supported by the visionOS compositor.
These changes separate tvOS-specific Siri Remote behavior and audio routing from visionOS rendering and permission differences to ensure correct runtime behavior on both platforms.
Pass game.id to viewModel.toggleFavorite instead of the whole game object and guard .buttonStyle(.card) with #if os(tvOS) so the card button style is only applied on tvOS. Changes applied to CloudNow/UI/LibraryView.swift and CloudNow/UI/StoreView.swift to fix argument type and platform-specific styling.
Introduce an ImmersiveSpace-based streaming flow for visionOS: add ImmersiveStreamView, register an ImmersiveSpace scene in CloudNowApp, and wire up open/dismiss behavior from MainTabView. Persist and expose an immersion style via AppStorage (gfn.immersionStyle) with runtime syncing and a Settings picker to choose between full and mixed immersion; users can also toggle via the Digital Crown. Add pendingGame/pendingSession fields to GamesViewModel to pass the selected game/session into the ImmersiveSpace and clear state on dismiss. Also make small UI adjustments: use .plain buttonStyle on non-tvOS card buttons and update the exit button to borderedProminent with white foreground for better visibility.
Move GamesViewModel ownership to the App so a single instance can be injected into WindowGroup and ImmersiveSpace (visionOS) and shared across platforms. MainTabView now reads GamesViewModel from the environment instead of owning its own state. Refactor play flow into a private play(_:, session:) helper that sets sessionToResume and gameToPlay, update callers, and simplify active-session lookup. Also wire .environment(viewModel) at the App level and keep existing load/refresh/save tasks intact.
Add platform-specific support for tvOS and visionOS across project and runtime code.
- Xcode project: add SUPPORTED_PLATFORMS, disable Mac Catalyst, and include tvOS device family ("3,7").
- GFNStreamController: guard tvOS-only remoteMode and toggle; adjust AVAudioSession setup (Bluetooth options on tvOS, simplified handling for other platforms) and use visionOS for microphone permission request.
- InputSender: make RemoteInputMode, remote sensitivity, micro-gamepad handling, and related logic tvOS-only (Siri Remote). Ensure tick() processes micro gamepad only on tvOS and keep existing extended gamepad handling for other platforms.
- StreamView: gate onExitCommand to tvOS; show an explicit menu button on non-tvOS (visionOS) and show remote-mode toggle only on tvOS.
- VideoSurfaceView: use layerClass override on tvOS but add AVSampleBufferDisplayLayer as a sublayer on visionOS (and update layoutSubviews) because layerClass is not supported by the visionOS compositor.
These changes separate tvOS-specific Siri Remote behavior and audio routing from visionOS rendering and permission differences to ensure correct runtime behavior on both platforms.
Pass game.id to viewModel.toggleFavorite instead of the whole game object and guard .buttonStyle(.card) with #if os(tvOS) so the card button style is only applied on tvOS. Changes applied to CloudNow/UI/LibraryView.swift and CloudNow/UI/StoreView.swift to fix argument type and platform-specific styling.
Introduce an ImmersiveSpace-based streaming flow for visionOS: add ImmersiveStreamView, register an ImmersiveSpace scene in CloudNowApp, and wire up open/dismiss behavior from MainTabView. Persist and expose an immersion style via AppStorage (gfn.immersionStyle) with runtime syncing and a Settings picker to choose between full and mixed immersion; users can also toggle via the Digital Crown. Add pendingGame/pendingSession fields to GamesViewModel to pass the selected game/session into the ImmersiveSpace and clear state on dismiss. Also make small UI adjustments: use .plain buttonStyle on non-tvOS card buttons and update the exit button to borderedProminent with white foreground for better visibility.
Move GamesViewModel ownership to the App so a single instance can be injected into WindowGroup and ImmersiveSpace (visionOS) and shared across platforms. MainTabView now reads GamesViewModel from the environment instead of owning its own state. Refactor play flow into a private play(_:, session:) helper that sets sessionToResume and gameToPlay, update callers, and simplify active-session lookup. Also wire .environment(viewModel) at the App level and keep existing load/refresh/save tasks intact.
ee3b365 to
a476d17
Compare
…dNow into feature/visionos
Wrap tvOS-specific input and UI behavior with #if os(tvOS) to ensure remoteMode, input pausing, focusSection, and gamepad UI only apply on tvOS. Expose RemoteInputMode enum on all platforms (removed the tvOS-only guard). Clamp saved FPS to UIScreen.main.maximumFramesPerSecond on tvOS and use a 120 Hz fallback for available FPS on non-tvOS. Remove duplicated visionOS pending session/game properties. Fix VideoSurfaceView memory access by caching plane pointers (srcY/srcU/srcV) before copying into CVPixelBuffer to avoid optional unwraps inside loops. Files changed: GFNStreamController.swift, InputSender.swift, GamesViewModel.swift, HomeView.swift, StreamView.swift, VideoSurfaceView.swift.
Removes a copy-paste duplicate #if os(visionOS) Section("Display") block
in SettingsView that would have rendered two identical Immersion Style
pickers on visionOS. Also applies swiftformat to all modified files.
Resolves conflicts between the visionOS platform support branch and 21 commits on main (rumble/haptics, localization, InputSender refactor, HDR fixes, save-in-game-settings, store filter chips, library refresh, etc.). Merge strategy per file: - InputSender.swift: took main's complete rewrite (DispatchSource timer, packet pooling, haptics, steam overlay); cross-platform without tvOS guards - GFNStreamController.swift: took main's configureAudioSession() helper and sender.configure() API - LibraryView.swift: took main's structure (refresh button, store filters, isLibraryLoading) + kept visionOS branch's #if os(tvOS) buttonStyle guard - MainTabView.swift: merged visionOS env vars + main's selectedTab, tab values, and ControllerTabNavigationBridge - SettingsView.swift: merged visionOS Display (immersion style) section before main's Controller (rumble) section - StoreView.swift: kept main's L10n strings + visionOS branch's tvOS buttonStyle conditional - StreamView.swift: merged .onPlayPauseCommand inside os(tvOS) block; used L10n for remoteModeLabel
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This pull request introduces significant enhancements for visionOS and tvOS support, refactors input handling for platform specificity, and improves the user experience across platforms. The changes include support for immersive streaming on visionOS, platform-specific input and audio session logic, and UI adaptations for both tvOS and visionOS.
Platform Support and Scene Management:
SUPPORTED_PLATFORMSandTARGETED_DEVICE_FAMILY, and disabled Mac Catalyst. [1] [2]ImmersiveStreamViewand immersive scene management for visionOS, allowing full or mixed immersion streaming with user-selectable modes. TheCloudNowAppnow manages a sharedGamesViewModeland immersion style state, and injects these into both the main window and immersive space. [1] [2] [3]Platform-Specific Input and Audio Handling:
UI and User Experience Improvements:
.cardstyle for tvOS,.plainelsewhere, for a more native look and feel. [1] [2] [3] [4]ViewModel and State Management:
GamesViewModelnow stores pending game/session info for visionOS immersive streaming, ensuring correct state transfer between scenes. MainTabView now uses the injected environment view model and centralizes play logic. [1] [2] [3]Minor Fixes and Consistency:
game.idinstead of the full game object for consistency. [1] [2]These changes collectively improve platform support, streamline input and audio handling, and enhance the user experience on both visionOS and tvOS.