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.
85 lines
3.0 KiB
Swift
85 lines
3.0 KiB
Swift
import HapiClient
|
|
import HapiUI
|
|
import SwiftUI
|
|
|
|
/// Switches the app root on pairing state and hosts the presentation that
|
|
/// must survive that switch: the deep-link pairing confirm sheet, the
|
|
/// "already paired" notice, the HapiUI palette resolved from the persisted
|
|
/// theme choice (A-M4e: system follows the OS scheme, explicit modes
|
|
/// override it, OLED = dark palette on pure black), and the app-wide
|
|
/// markdown link handler.
|
|
struct RootView: View {
|
|
@Environment(AppModel.self) private var model
|
|
@Environment(\.colorScheme) private var colorScheme
|
|
@State private var themePrefs = ThemePrefs()
|
|
|
|
var body: some View {
|
|
@Bindable var model = model
|
|
Group {
|
|
switch model.state {
|
|
case .unpaired:
|
|
PairingFlowView()
|
|
case .paired:
|
|
if let session = model.session {
|
|
// `.id` resets navigation + list state on hub switch —
|
|
// each hub gets a fresh HomeView over its own stores.
|
|
HomeView(session: session)
|
|
.id(session.hubUrl)
|
|
} else {
|
|
// Defensive: .paired always carries a session; fall back
|
|
// to pairing rather than a dead screen.
|
|
PairingFlowView()
|
|
}
|
|
}
|
|
}
|
|
.sheet(item: $model.pendingPairing) { pending in
|
|
NavigationStack {
|
|
PairingConfirmView(pending: pending)
|
|
.toolbar {
|
|
ToolbarItem(placement: .cancellationAction) {
|
|
Button("Cancel") {
|
|
model.pendingPairing = nil
|
|
}
|
|
}
|
|
}
|
|
}
|
|
.macSheetSizing()
|
|
}
|
|
.alert(
|
|
"Hub already paired",
|
|
isPresented: Binding(
|
|
get: { model.infoNotice != nil },
|
|
set: { presented in
|
|
if !presented {
|
|
model.infoNotice = nil
|
|
}
|
|
}
|
|
)
|
|
) {
|
|
Button("OK") {
|
|
model.infoNotice = nil
|
|
}
|
|
} message: {
|
|
Text(model.infoNotice ?? "")
|
|
}
|
|
.background(MacWindowConfigurator())
|
|
.hapiTypography()
|
|
.hapiTheme(themePrefs.mode.hapiTheme(systemColorScheme: colorScheme))
|
|
// Explicit modes force the presentation's chrome to match their
|
|
// palette; `.system` passes nil so the OS scheme flows through.
|
|
// (Under an explicit mode `colorScheme` reflects the override, but
|
|
// the palette resolution only consults it in `.system` mode.)
|
|
.preferredColorScheme(themePrefs.mode.preferredColorScheme)
|
|
.environment(themePrefs)
|
|
.handlesHapiLinks()
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
RootView()
|
|
.environment(AppModel(
|
|
registry: HubRegistry(defaults: UserDefaults(suiteName: "preview") ?? .standard),
|
|
credentialStore: InMemoryCredentialStore()
|
|
))
|
|
}
|