mirror of
https://github.com/wu736139669/hapi.git
synced 2026-11-08 01:43:07 +00:00
Build the app and notification extension for Mac Catalyst with the Mac idiom, so Macs get a 1:1 native window instead of the scaled iPad app. The Mac build keeps the run.hapi.app bundle ID and adds Mac entitlements (sandbox, network, microphone, user-selected files, Mac APNs). - Always use the split on Mac with a sidebar list style, denser rows, 14pt reading text, a hidden duplicate titlebar title, a minimum window size and page-sized sheets; open web links in the default browser and hide the unavailable live QR scanner. - Add menu bar / hardware-keyboard commands: New Session, Settings, Toggle Sidebar, a Session menu (settings, files, rename, export, stop, previous/next session) and a guide link. - Composer: Return sends on Mac (Shift/Option-Return for a newline, IME untouched, first suggestion picked); dropped files and pasted images or copied files become attachments on all platforms. - CI builds Mac Catalyst and runs the navigation, split and transcript geometry tests there; README documents the Mac build.
46 lines
1.5 KiB
Swift
46 lines
1.5 KiB
Swift
import HapiProtocol
|
|
import OSLog
|
|
import SwiftUI
|
|
|
|
@main
|
|
struct HapiApp: App {
|
|
/// APNs registration callbacks + notification-center delegate install
|
|
/// (P3) — SwiftUI lifecycle apps get them only through the adaptor.
|
|
@UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate
|
|
@State private var model = AppModel()
|
|
@Environment(\.scenePhase) private var scenePhase
|
|
|
|
private let log = Logger(subsystem: "run.hapi.companion", category: "app")
|
|
|
|
var body: some Scene {
|
|
WindowGroup {
|
|
RootView()
|
|
.environment(model)
|
|
.onOpenURL { url in
|
|
handleIncomingURL(url)
|
|
}
|
|
}
|
|
.onChange(of: scenePhase, initial: true) { _, phase in
|
|
model.handleScenePhase(phase)
|
|
}
|
|
.commands {
|
|
HapiCommands()
|
|
}
|
|
}
|
|
|
|
/// `hapicompanion://bind?hub=<url>&code=<accessToken>` — parse and route
|
|
/// through `AppModel`: unpaired → pairing confirm; already paired to that
|
|
/// hub → switch with a notice; a different hub → add-hub confirm.
|
|
///
|
|
/// Never log the URL itself: the query carries the access token.
|
|
private func handleIncomingURL(_ url: URL) {
|
|
guard let link = BindLink.parse(url.absoluteString) else {
|
|
log.warning("Ignoring malformed URL (scheme: \(url.scheme ?? "none", privacy: .public))")
|
|
return
|
|
}
|
|
if !model.handleBindLink(link) {
|
|
log.warning("Bind link carried an unusable hub URL")
|
|
}
|
|
}
|
|
}
|