mirror of
https://github.com/home-assistant/iOS.git
synced 2026-06-23 23:34:42 -05:00
## Summary Enables AssistView to open in a dedicated window on macOS while maintaining modal presentation on iOS/iPad. **Implementation:** - Added `.assist` case to `SceneActivity` enum with `ha.assist` identifier - Created `AssistSceneDelegate` extending `BasicSceneDelegate` to manage Assist windows - Updated `Info.plist` with Assist scene configuration - Added `SceneManager.activateAnyScene(for:with:)` to pass parameters via `NSUserActivity.userInfo` - Modified `WebViewExternalMessageHandler.showAssist()` to branch on `Current.isCatalyst`: - macOS: `SceneManager.activateAnyScene(for: .assist, with: userInfo)` - iOS/iPad: Existing modal presentation (unchanged) - Window centering: Assist window opens centered on screen (600x600) using `UIWindowScene.MacGeometryPreferences` (iOS 17+) - Close button: Removed toolbar close button in scene mode since window has native close button; modal presentation on iOS/iPad retains close button **Parameters passed via userInfo:** - `server`: Server identifier string - `pipelineId`: Pipeline ID string - `autoStartRecording`: Boolean ## Screenshots N/A - Scene system change, requires macOS build to screenshot ## Link to pull request in Documentation repository Documentation: home-assistant/companion.home-assistant# ## Any other notes Follows existing scene patterns from `SettingsSceneDelegate` and `AboutSceneDelegate`. No breaking changes to iOS/iPad behavior. The `showCloseButton` parameter in `AssistView` allows flexible control of close button visibility - `false` for scene mode (window has native controls), `true` for modal presentation. <!-- START COPILOT CODING AGENT SUFFIX --> <details> <summary>Original prompt</summary> > Turn AssistView into a scene, so it can be initiated in a new window on macOS </details> <!-- START COPILOT CODING AGENT TIPS --> --- 💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs. --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: bgoncal <5808343+bgoncal@users.noreply.github.com>
80 lines
2.9 KiB
Swift
80 lines
2.9 KiB
Swift
import Foundation
|
|
import Shared
|
|
import SwiftUI
|
|
import UIKit
|
|
|
|
@objc class AssistSceneDelegate: BasicSceneDelegate {
|
|
private var server: Server?
|
|
private var preferredPipelineId: String = ""
|
|
private var autoStartRecording: Bool = false
|
|
|
|
override func basicConfig(in traitCollection: UITraitCollection) -> BasicSceneDelegate.BasicConfig {
|
|
let server = server ?? Current.servers.all.first!
|
|
let assistView = AssistView.build(
|
|
server: server,
|
|
preferredPipelineId: preferredPipelineId,
|
|
autoStartRecording: autoStartRecording,
|
|
showCloseButton: false
|
|
)
|
|
let hostingController = UIHostingController(rootView: assistView)
|
|
|
|
return .init(
|
|
title: "Assist",
|
|
rootViewController: hostingController
|
|
)
|
|
}
|
|
|
|
override func scene(
|
|
_ scene: UIScene,
|
|
willConnectTo session: UISceneSession,
|
|
options connectionOptions: UIScene.ConnectionOptions
|
|
) {
|
|
// Extract parameters from userInfo if available
|
|
if let userActivity = connectionOptions.userActivities.first,
|
|
let userInfo = userActivity.userInfo {
|
|
if let serverIdentifier = userInfo["server"] as? String,
|
|
let server = Current.servers.all.first(where: { $0.identifier.rawValue == serverIdentifier }) {
|
|
self.server = server
|
|
}
|
|
preferredPipelineId = userInfo["pipelineId"] as? String ?? ""
|
|
autoStartRecording = userInfo["autoStartRecording"] as? Bool ?? false
|
|
}
|
|
|
|
super.scene(scene, willConnectTo: session, options: connectionOptions)
|
|
|
|
#if targetEnvironment(macCatalyst)
|
|
// Center the window on screen
|
|
if let windowScene = scene as? UIWindowScene {
|
|
let screen = windowScene.screen
|
|
let screenBounds = screen.bounds
|
|
let windowSize = CGSize(width: 400, height: 600)
|
|
let centeredFrame = CGRect(
|
|
x: (screenBounds.width - windowSize.width) / 2,
|
|
y: (screenBounds.height - windowSize.height) / 2,
|
|
width: windowSize.width,
|
|
height: windowSize.height
|
|
)
|
|
|
|
if #available(macCatalyst 16.0, *) {
|
|
windowScene.requestGeometryUpdate(.Mac(systemFrame: centeredFrame)) { error in
|
|
Current.Log.info(["Failed to request geometry": error.localizedDescription])
|
|
}
|
|
} else {
|
|
// For earlier versions, we can't set the initial frame directly
|
|
// The window will use default positioning
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
func sceneDidDisconnect(_ scene: UIScene) {
|
|
// Clean up when scene is destroyed
|
|
Current.Log.info("Assist scene disconnected")
|
|
window = nil
|
|
self.scene = nil
|
|
server = nil
|
|
preferredPipelineId = ""
|
|
autoStartRecording = false
|
|
}
|
|
}
|