1bdb8824ac
Add preset-driven polish scenarios (Settings, onboarding, ScenarioChip) with ScenarioPrompt and style directives; drive keyboard height from content (240pt) and use viewIsAppearing encapsulated-height offset for smoother keyboard switches; remove redundant StatusBadge and hide system dictation via hasDictationKey.
68 lines
2.1 KiB
Swift
68 lines
2.1 KiB
Swift
// FlowSessionDarwin.swift
|
|
// OSGKeyboard · Shared
|
|
//
|
|
// Cross-process Darwin notification when the host app changes Flow session
|
|
// state (start, extend, end). Keyboard extension listens without polling alone.
|
|
|
|
import Foundation
|
|
|
|
public enum FlowSessionDarwin {
|
|
public static let notificationName = "com.osgkeyboard.flow.session.changed"
|
|
|
|
public static func postSessionChanged() {
|
|
CFNotificationCenterPostNotification(
|
|
CFNotificationCenterGetDarwinNotifyCenter(),
|
|
CFNotificationName(notificationName as CFString),
|
|
nil,
|
|
nil,
|
|
true
|
|
)
|
|
}
|
|
}
|
|
|
|
/// Observes Darwin notifications on a background thread; invokes
|
|
/// `handler` on the main actor.
|
|
public final class FlowSessionDarwinObserver {
|
|
private final class Box: @unchecked Sendable {
|
|
let handler: @MainActor () -> Void
|
|
init(handler: @escaping @MainActor () -> Void) { self.handler = handler }
|
|
}
|
|
|
|
private let box: Box
|
|
private let token: UnsafeMutableRawPointer
|
|
private let notificationName: CFString
|
|
|
|
public init(
|
|
notificationName: String = FlowSessionDarwin.notificationName,
|
|
handler: @escaping @MainActor () -> Void
|
|
) {
|
|
let box = Box(handler: handler)
|
|
self.box = box
|
|
self.token = Unmanaged.passRetained(box).toOpaque()
|
|
self.notificationName = notificationName as CFString
|
|
|
|
CFNotificationCenterAddObserver(
|
|
CFNotificationCenterGetDarwinNotifyCenter(),
|
|
token,
|
|
{ _, observer, _, _, _ in
|
|
guard let observer else { return }
|
|
let box = Unmanaged<Box>.fromOpaque(observer).takeUnretainedValue()
|
|
Task { @MainActor in box.handler() }
|
|
},
|
|
self.notificationName,
|
|
nil,
|
|
.deliverImmediately
|
|
)
|
|
}
|
|
|
|
deinit {
|
|
CFNotificationCenterRemoveObserver(
|
|
CFNotificationCenterGetDarwinNotifyCenter(),
|
|
token,
|
|
CFNotificationName(notificationName),
|
|
nil
|
|
)
|
|
Unmanaged<Box>.fromOpaque(token).release()
|
|
}
|
|
}
|