185 lines
6.0 KiB
Swift
185 lines
6.0 KiB
Swift
import SwiftUI
|
|
|
|
@MainActor
|
|
public protocol MacToolsPlugin: AnyObject {
|
|
var metadata: PluginMetadata { get }
|
|
var primaryPanel: (any PluginPrimaryPanel)? { get }
|
|
var componentPanel: (any PluginComponentPanel)? { get }
|
|
var permissionRequirements: [PluginPermissionRequirement] { get }
|
|
var settingsSections: [PluginSettingsSection] { get }
|
|
var shortcutDefinitions: [PluginShortcutDefinition] { get }
|
|
var configuration: PluginConfiguration? { get }
|
|
var onStateChange: (() -> Void)? { get set }
|
|
var requestPermissionGuidance: ((String) -> Void)? { get set }
|
|
var shortcutBindingResolver: ((String) -> ShortcutBinding?)? { get set }
|
|
|
|
func refresh()
|
|
func activate(context: PluginRuntimeContext)
|
|
func deactivate(reason: PluginDeactivationReason)
|
|
func permissionState(for permissionID: String) -> PluginPermissionState
|
|
func handlePermissionAction(id: String)
|
|
func handleSettingsAction(id: String)
|
|
func handleShortcutAction(id: String)
|
|
}
|
|
|
|
@MainActor
|
|
public protocol PluginPrimaryPanel: AnyObject {
|
|
var primaryPanelDescriptor: PluginPrimaryPanelDescriptor { get }
|
|
var primaryPanelState: PluginPanelState { get }
|
|
|
|
func handleAction(_ action: PluginPanelAction)
|
|
}
|
|
|
|
public enum PluginShortcutEventPhase: Sendable {
|
|
case pressed
|
|
case released
|
|
}
|
|
|
|
@MainActor
|
|
public protocol PluginShortcutEventHandling: AnyObject {
|
|
func handleShortcutEvent(id: String, phase: PluginShortcutEventPhase)
|
|
}
|
|
|
|
public extension MacToolsPlugin {
|
|
var primaryPanel: (any PluginPrimaryPanel)? {
|
|
nil
|
|
}
|
|
|
|
var componentPanel: (any PluginComponentPanel)? {
|
|
nil
|
|
}
|
|
|
|
var permissionRequirements: [PluginPermissionRequirement] {
|
|
[]
|
|
}
|
|
|
|
var settingsSections: [PluginSettingsSection] {
|
|
[]
|
|
}
|
|
|
|
var shortcutDefinitions: [PluginShortcutDefinition] {
|
|
[]
|
|
}
|
|
|
|
var configuration: PluginConfiguration? {
|
|
nil
|
|
}
|
|
|
|
func refresh() {}
|
|
|
|
func activate(context: PluginRuntimeContext) {}
|
|
|
|
func deactivate(reason: PluginDeactivationReason) {}
|
|
|
|
func permissionState(for permissionID: String) -> PluginPermissionState {
|
|
PluginPermissionState(isGranted: true, footnote: nil)
|
|
}
|
|
|
|
func handlePermissionAction(id: String) {}
|
|
func handleSettingsAction(id: String) {}
|
|
func handleShortcutAction(id: String) {}
|
|
}
|
|
|
|
public extension MacToolsPlugin where Self: PluginPrimaryPanel {
|
|
var primaryPanel: (any PluginPrimaryPanel)? {
|
|
self
|
|
}
|
|
}
|
|
|
|
@MainActor
|
|
public protocol PluginComponentPanel: AnyObject {
|
|
var descriptor: PluginComponentDescriptor { get }
|
|
var componentPanelState: PluginComponentState { get }
|
|
|
|
func makeView(context: PluginComponentContext) -> AnyView
|
|
}
|
|
|
|
public extension MacToolsPlugin where Self: PluginComponentPanel {
|
|
var componentPanel: (any PluginComponentPanel)? {
|
|
self
|
|
}
|
|
}
|
|
|
|
public enum PluginPanelSurface: CaseIterable, Hashable, Sendable {
|
|
case component
|
|
case primary
|
|
}
|
|
|
|
@MainActor
|
|
public protocol PluginPanelSurfaceLifecycleHandling: AnyObject {
|
|
func panelSurfaceDidBecomeVisible(_ surface: PluginPanelSurface)
|
|
func panelSurfaceDidBecomeHidden(_ surface: PluginPanelSurface)
|
|
}
|
|
|
|
public extension PluginPanelSurfaceLifecycleHandling {
|
|
func panelSurfaceDidBecomeVisible(_ surface: PluginPanelSurface) {}
|
|
func panelSurfaceDidBecomeHidden(_ surface: PluginPanelSurface) {}
|
|
}
|
|
|
|
@MainActor
|
|
public protocol PluginProvider {
|
|
func makePlugins() -> [any MacToolsPlugin]
|
|
}
|
|
|
|
public protocol MacToolsPluginBundleFactory: AnyObject {
|
|
static func makeProvider(context: PluginRuntimeContext) throws -> any PluginProvider
|
|
}
|
|
|
|
@MainActor
|
|
public protocol AccessibilityPermissionRefreshing {
|
|
func refreshAccessibilityPermission()
|
|
}
|
|
|
|
@MainActor
|
|
public protocol DisplayTopologyRefreshing {
|
|
func refreshDisplayTopology()
|
|
}
|
|
|
|
/// Optional protocol for plugins that expose a compact, read-only status in the primary panel row.
|
|
/// Does not change the `MacToolsPlugin` witness table, so installed legacy plugins are unaffected.
|
|
@MainActor
|
|
public protocol PluginPrimaryPanelIndicatorProviding: AnyObject {
|
|
var primaryPanelIndicator: PluginPrimaryPanelIndicator? { get }
|
|
}
|
|
|
|
/// Optional protocol for plugins that need a floating-window anchor.
|
|
/// Does not change the `MacToolsPlugin` witness table, so installed legacy plugins are unaffected.
|
|
@MainActor
|
|
public protocol DropZoneAnchorProviding: AnyObject {
|
|
/// Host-injected provider returning the status-item button frame in screen coordinates.
|
|
var anchorRectProvider: (() -> NSRect?)? { get set }
|
|
}
|
|
|
|
/// Optional protocol for plugins that need to protect the host menu-bar status-item position.
|
|
@MainActor
|
|
public protocol MenuBarHostStatusItemRecovering: AnyObject {
|
|
var hostStatusItemFrameProvider: (() -> NSRect?)? { get set }
|
|
var resetHostStatusItemPosition: (() -> Void)? { get set }
|
|
}
|
|
|
|
/// Optional protocol for plugins that need to open their settings page from custom UI, such as a floating panel.
|
|
/// Does not change the `MacToolsPlugin` witness table, so installed legacy plugins are unaffected.
|
|
@MainActor
|
|
public protocol PluginConfigurationPresenting: AnyObject {
|
|
/// Host-injected callback requesting presentation of this plugin's settings page.
|
|
var requestConfigurationPresentation: (() -> Void)? { get set }
|
|
}
|
|
|
|
/// Optional protocol for built-in plugins whose feature visibility should
|
|
/// pause/resume heavyweight observers or external side effects.
|
|
/// Dynamic plugins are paused by `DynamicPluginManager` instead.
|
|
@MainActor
|
|
public protocol PluginFeatureVisibilityLifecycleHandling: AnyObject {
|
|
func featureVisibilityDidChange(_ isVisible: Bool)
|
|
}
|
|
|
|
/// Optional hook for built-in plugins that cache localized descriptors or
|
|
/// other language-dependent presentation data. The host invokes it when the
|
|
/// app language changes; implementations must not activate, deactivate, or
|
|
/// reset the plugin's functional state. Dynamic plugins read localization at
|
|
/// render time and do not need this hook.
|
|
@MainActor
|
|
public protocol PluginRuntimeLocalizationRefreshing: AnyObject {
|
|
func refreshLocalization()
|
|
}
|