diff --git a/macos/Onit/Accessibility/Notifications/AccessibilityNotificationsManager.swift b/macos/Onit/Accessibility/Notifications/AccessibilityNotificationsManager.swift index 2f48afee..529f1d82 100644 --- a/macos/Onit/Accessibility/Notifications/AccessibilityNotificationsManager.swift +++ b/macos/Onit/Accessibility/Notifications/AccessibilityNotificationsManager.swift @@ -18,28 +18,8 @@ class AccessibilityNotificationsManager: ObservableObject { static let shared = AccessibilityNotificationsManager() - // MARK: - ScreenResult - - struct ScreenResult { - struct UserInteractions { - var selectedText: String? - var input: String? - } - - var elapsedTime: String? - var applicationName: String? - var applicationTitle: String? - var userInteraction: UserInteractions = .init() - var others: [String: String]? - var errorMessage: String? // Renamed field for error message - var errorCode: Int32? - var appBundleUrl: URL? - } - // MARK: - Properties - @Published var screenResult: ScreenResult = .init() - let windowsManager = AccessibilityWindowsManager() private let highlightedTextCoordinator = HighlightedTextCoordinator() @@ -54,6 +34,9 @@ class AccessibilityNotificationsManager: ObservableObject { private var valueDebounceWorkItem: DispatchWorkItem? private var selectionDebounceWorkItem: DispatchWorkItem? private var parseDebounceWorkItem: DispatchWorkItem? + + // Published property for selected text that QuickEditManager can observe + @Published var selectedText: String? // MARK: - Private initializer @@ -124,7 +107,6 @@ class AccessibilityNotificationsManager: ObservableObject { func reset() { windowsManager.reset() - screenResult = .init() Task.detached { await self.highlightedTextCoordinator.reset() @@ -137,6 +119,8 @@ class AccessibilityNotificationsManager: ObservableObject { selectionDebounceWorkItem?.cancel() parseDebounceWorkItem?.cancel() + selectedText = nil + ContextFetchingService.shared.reset() } @@ -318,12 +302,10 @@ class AccessibilityNotificationsManager: ObservableObject { dispatchPrecondition(condition: .onQueue(.main)) guard let value = element.value() else { - screenResult.userInteraction.input = nil showDebug() return } - screenResult.userInteraction.input = value showDebug() } @@ -365,14 +347,15 @@ class AccessibilityNotificationsManager: ObservableObject { let selectedText = text, HighlightedTextValidator.isValid(text: selectedText) else { - screenResult.userInteraction.selectedText = nil PanelStateCoordinator.shared.state.pendingInput = nil PanelStateCoordinator.shared.state.trackedPendingInput = nil + self.selectedText = nil return } - screenResult.userInteraction.selectedText = selectedText - + // Update the published selectedText property + self.selectedText = selectedText + let input = Input(selectedText: selectedText, application: currentSource ?? "") if Defaults[.autoAddHighlightedTextToContext] { @@ -397,42 +380,8 @@ class AccessibilityNotificationsManager: ObservableObject { // MARK: Debug private func showDebug() { - var debugText = """ - ===== Debug Information ===== - - Elapsed Time: \(screenResult.elapsedTime ?? "N/A") - - Application Name: \(screenResult.applicationName ?? "N/A") - - Application Title: \(screenResult.applicationTitle ?? "N/A") - - Selected Text: \(screenResult.userInteraction.selectedText ?? "N/A") - - User Input: \(screenResult.userInteraction.input ?? "N/A") - - Error Message: \(screenResult.errorMessage ?? "N/A") - - ============================= - - """ - - if let results = screenResult.others { - debugText += "\n======== Additional Data ========\n" - for result in results.sorted(by: { $0.key < $1.key }) { - debugText += """ - - --------------------------------- - Key: \(result.key) - --------------------------------- - \(result.value) - """ - } - debugText += "\n=================================\n" - } else { - debugText += "\nNo additional data available.\n" - } - - DebugManager.shared.debugText = debugText + // Debug information is now handled by ContextFetchingService + DebugManager.shared.debugText = "Debug information moved to ContextFetchingService" } } diff --git a/macos/Onit/Context/ContextFetchingService.swift b/macos/Onit/Context/ContextFetchingService.swift index 19463c22..e39e0ead 100644 --- a/macos/Onit/Context/ContextFetchingService.swift +++ b/macos/Onit/Context/ContextFetchingService.swift @@ -101,16 +101,17 @@ class ContextFetchingService { errorCode = 1500 } - // Update screenResult with error information - AccessibilityNotificationsManager.shared.screenResult.applicationName = appName - AccessibilityNotificationsManager.shared.screenResult.applicationTitle = appTitle - AccessibilityNotificationsManager.shared.screenResult.errorMessage = errorMessage - AccessibilityNotificationsManager.shared.screenResult.errorCode = errorCode - AccessibilityNotificationsManager.shared.screenResult.appBundleUrl = appBundleUrl - AccessibilityNotificationsManager.shared.screenResult.others = nil + // Create ScreenResult with error information + let screenResult = ScreenResult( + applicationName: appName, + applicationTitle: appTitle, + errorMessage: errorMessage, + errorCode: errorCode, + appBundleUrl: appBundleUrl + ) // Call addAutoContext to handle the error case - state.addAutoContext(trackedWindow: trackedWindow) + state.addAutoContext(trackedWindow: trackedWindow, screenResult: screenResult) } } else { // This creates an error state for when google drive is not authorized @@ -122,16 +123,17 @@ class ContextFetchingService { } } - // Update screenResult with unauthorized error - AccessibilityNotificationsManager.shared.screenResult.applicationName = appName - AccessibilityNotificationsManager.shared.screenResult.applicationTitle = appTitle - AccessibilityNotificationsManager.shared.screenResult.errorMessage = "Google Drive Plugin Required" - AccessibilityNotificationsManager.shared.screenResult.errorCode = 1500 - AccessibilityNotificationsManager.shared.screenResult.appBundleUrl = appBundleUrl - AccessibilityNotificationsManager.shared.screenResult.others = nil + // Create ScreenResult with unauthorized error + let screenResult = ScreenResult( + applicationName: appName, + applicationTitle: appTitle, + errorMessage: "Google Drive Plugin Required", + errorCode: 1500, + appBundleUrl: appBundleUrl + ) // Call addAutoContext to handle the error case - state.addAutoContext(trackedWindow: trackedWindow) + state.addAutoContext(trackedWindow: trackedWindow, screenResult: screenResult) } } else { parseAccessibility( @@ -263,16 +265,16 @@ class ContextFetchingService { self.timedOutWindowHash.insert(windowHash) AnalyticsManager.Accessibility.parseTimedOut(appName: appName) - // Update screenResult with timeout error - AccessibilityNotificationsManager.shared.screenResult.applicationName = appName - AccessibilityNotificationsManager.shared.screenResult.applicationTitle = "" - AccessibilityNotificationsManager.shared.screenResult.errorMessage = "Timeout occurred, could not read application in reasonable amount of time." - AccessibilityNotificationsManager.shared.screenResult.errorCode = 1500 - AccessibilityNotificationsManager.shared.screenResult.appBundleUrl = nil - AccessibilityNotificationsManager.shared.screenResult.others = nil + // Create ScreenResult with timeout error + let screenResult = ScreenResult( + applicationName: appName, + applicationTitle: "", + errorMessage: "Timeout occurred, could not read application in reasonable amount of time.", + errorCode: 1500 + ) // Call addAutoContext to handle the error case - state.addAutoContext(trackedWindow: trackedWindow) + state.addAutoContext(trackedWindow: trackedWindow, screenResult: screenResult) } } } @@ -296,16 +298,16 @@ class ContextFetchingService { let appName = results?[AccessibilityParsedElements.applicationName] ?? "" let appTitle = results?[AccessibilityParsedElements.applicationTitle] ?? "" - // Update screenResult with the parsed content - AccessibilityNotificationsManager.shared.screenResult.applicationName = appName - AccessibilityNotificationsManager.shared.screenResult.applicationTitle = appTitle - AccessibilityNotificationsManager.shared.screenResult.errorMessage = nil - AccessibilityNotificationsManager.shared.screenResult.errorCode = nil - AccessibilityNotificationsManager.shared.screenResult.appBundleUrl = appBundleUrl - AccessibilityNotificationsManager.shared.screenResult.others = results + // Create ScreenResult object + let screenResult = ScreenResult( + applicationName: appName, + applicationTitle: appTitle, + others: results, + appBundleUrl: appBundleUrl + ) // Call addAutoContext to handle the context creation and cleanup - state.addAutoContext(trackedWindow: trackedWindow) + state.addAutoContext(trackedWindow: trackedWindow, screenResult: screenResult) } func reset() { @@ -317,8 +319,7 @@ class ContextFetchingService { // MARK: - Debug private func showDebug() { - // This method is called to update debug information - // Since we're no longer using screenResult, we'll just clear the debug text - DebugManager.shared.debugText = "Context fetching moved to ContextFetchingService" + // Debug information is now handled by individual ScreenResult objects + DebugManager.shared.debugText = "Context fetching using ScreenResult objects" } } diff --git a/macos/Onit/Data/Structures/ScreenResult.swift b/macos/Onit/Data/Structures/ScreenResult.swift new file mode 100644 index 00000000..55bae7cb --- /dev/null +++ b/macos/Onit/Data/Structures/ScreenResult.swift @@ -0,0 +1,44 @@ +// +// ScreenResult.swift +// Onit +// +// Created by Kévin Naudin on 22/01/2025. +// + +import Foundation + +struct ScreenResult { + struct UserInteractions { + var selectedText: String? + var input: String? + } + + var elapsedTime: String? + var applicationName: String? + var applicationTitle: String? + var userInteraction: UserInteractions = .init() + var others: [String: String]? + var errorMessage: String? // Renamed field for error message + var errorCode: Int32? + var appBundleUrl: URL? + + init( + elapsedTime: String? = nil, + applicationName: String? = nil, + applicationTitle: String? = nil, + userInteraction: UserInteractions = UserInteractions(), + others: [String: String]? = nil, + errorMessage: String? = nil, + errorCode: Int32? = nil, + appBundleUrl: URL? = nil + ) { + self.elapsedTime = elapsedTime + self.applicationName = applicationName + self.applicationTitle = applicationTitle + self.userInteraction = userInteraction + self.others = others + self.errorMessage = errorMessage + self.errorCode = errorCode + self.appBundleUrl = appBundleUrl + } +} \ No newline at end of file diff --git a/macos/Onit/UI/Panels/State/OnitPanelState+Input.swift b/macos/Onit/UI/Panels/State/OnitPanelState+Input.swift index ae60721e..829164f1 100644 --- a/macos/Onit/UI/Panels/State/OnitPanelState+Input.swift +++ b/macos/Onit/UI/Panels/State/OnitPanelState+Input.swift @@ -9,25 +9,25 @@ import AppKit import Defaults extension OnitPanelState { - func addAutoContext(trackedWindow: TrackedWindow? = nil) { + func addAutoContext(trackedWindow: TrackedWindow? = nil, screenResult: ScreenResult? = nil) { guard Defaults[.autoContextFromCurrentWindow] else { return } - let appName = AccessibilityNotificationsManager.shared.screenResult.applicationName ?? "AutoContext" + let appName = screenResult?.applicationName ?? "AutoContext" let trackedWindowTitle = trackedWindow?.title - let trackedWindowHash = trackedWindow?.hash ?? 0 // This is all all horrible. There's no reason why we should be putting these things on the 'screenResult" - if let errorMessage = AccessibilityNotificationsManager.shared.screenResult.errorMessage { + let trackedWindowHash = trackedWindow?.hash ?? 0 + if let errorMessage = screenResult?.errorMessage { let errorContext = Context( appName: appName, appHash: trackedWindow?.hash ?? 0, appTitle: trackedWindowTitle ?? "Unknown", - appContent: ["error": errorMessage, "errorCode" : String(AccessibilityNotificationsManager.shared.screenResult.errorCode ?? 0)], - appBundleUrl: AccessibilityNotificationsManager.shared.screenResult.appBundleUrl) + appContent: ["error": errorMessage, "errorCode" : String(screenResult?.errorCode ?? 0)], + appBundleUrl: screenResult?.appBundleUrl) pendingContextList.insert(errorContext, at: 0) cleanupWindowContextTask(uniqueWindowIdentifier: trackedWindowHash) return } - guard var appContent = AccessibilityNotificationsManager.shared.screenResult.others else { + guard var appContent = screenResult?.others else { let errorContext = Context(appName: "Unable to add \(appName)", appHash: 0, appTitle: "", appContent: ["error": "Empty text"]) pendingContextList.insert(errorContext, at: 0) cleanupWindowContextTask(uniqueWindowIdentifier: trackedWindowHash) @@ -69,7 +69,7 @@ extension OnitPanelState { appHash: appHash, appTitle: appTitle, appContent: appContent, - appBundleUrl: AccessibilityNotificationsManager.shared.screenResult.appBundleUrl, + appBundleUrl: screenResult?.appBundleUrl, ocrMatchingPercentage: ocrMatchingPercentage ) let newContext = Context.auto(autoContext) @@ -106,7 +106,7 @@ extension OnitPanelState { appHash: appHash, appTitle: appTitle, appContent: appContent, - appBundleUrl: AccessibilityNotificationsManager.shared.screenResult.appBundleUrl, + appBundleUrl: screenResult?.appBundleUrl, ocrMatchingPercentage: ocrMatchingPercentage ) diff --git a/macos/Onit/UI/QuickEdit/QuickEditManager.swift b/macos/Onit/UI/QuickEdit/QuickEditManager.swift index fca426af..2d382084 100644 --- a/macos/Onit/UI/QuickEdit/QuickEditManager.swift +++ b/macos/Onit/UI/QuickEdit/QuickEditManager.swift @@ -106,8 +106,8 @@ class QuickEditManager: ObservableObject, CaretPositionDelegate { } private func setupTextSelectionMonitoring() { - accessibilityManager.$screenResult - .map(\.userInteraction.selectedText) + // Monitor the selectedText property from AccessibilityNotificationsManager + AccessibilityNotificationsManager.shared.$selectedText .removeDuplicates() .sink { [weak self] selectedText in self?.handleTextSelectionChange(selectedText) @@ -284,7 +284,7 @@ extension QuickEditManager { } func caretDidDisappear() { - if !hasTextSelection(accessibilityManager.screenResult.userInteraction.selectedText) { + if !hasTextSelection(PanelStateCoordinator.shared.state.pendingInput?.selectedText ?? PanelStateCoordinator.shared.state.trackedPendingInput?.selectedText) { hideHint() } }