From 646210f1a3917e5086fb6c5dcfb057933e968f9c Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Fri, 21 Jul 2023 12:43:15 +0530 Subject: [PATCH] updated operation type --- .../Accessibility/AccessibilityHandler.swift | 71 +++++++++++-------- 1 file changed, 43 insertions(+), 28 deletions(-) diff --git a/MVMCoreUI/Accessibility/AccessibilityHandler.swift b/MVMCoreUI/Accessibility/AccessibilityHandler.swift index a7e0f245..63fb3f74 100644 --- a/MVMCoreUI/Accessibility/AccessibilityHandler.swift +++ b/MVMCoreUI/Accessibility/AccessibilityHandler.swift @@ -21,8 +21,10 @@ public enum AccessibilityNotificationType: String, Codable { //By default from iOS 13+ focus is getting shifted to first interactive element inside viewcontroller not to the navigationitem left barbutton item so posting layoutChanged notification with delay to push to leftbarbutton item on new screen push var delay: Double { switch self { - case .controllerChanged, .webPageLoaded: + case .controllerChanged: return 1.5 + case .webPageLoaded: + return 2.0 case .screenChanged, .layoutChanged: return 0.0 default: @@ -44,35 +46,40 @@ public enum AccessibilityNotificationType: String, Codable { } } +public typealias ArgumentHandler = ((NavigationOperationType?) -> Any?) + public class AccessbilityOperation: MVMCoreOperation { - let argument: Any? - let notificationType: AccessibilityNotificationType + private let operationType: NavigationOperationType + private let argumentHandler: ArgumentHandler? + private let notificationType: AccessibilityNotificationType private var timerSource: DispatchSourceTimer? - public init(notificationType: AccessibilityNotificationType, argument: Any?) { + public init(notificationType: AccessibilityNotificationType, operationType: NavigationOperationType = .default, argumentHandler: ArgumentHandler?) { self.notificationType = notificationType - self.argument = argument + self.argumentHandler = argumentHandler + self.operationType = operationType } public override func main() { - Task { @MainActor in - guard UIAccessibility.isVoiceOverRunning, !checkAndHandleForCancellation() else { - stop() - return - } - timerSource = DispatchSource.makeTimerSource() - timerSource?.setEventHandler { [weak self] in + guard UIAccessibility.isVoiceOverRunning, !checkAndHandleForCancellation() else { + stop() + return + } + timerSource = DispatchSource.makeTimerSource() + timerSource?.setEventHandler { + Task { @MainActor [weak self] in if !(self?.isCancelled ?? false), let notification = self?.notificationType.accessibilityNotification { - UIAccessibility.post(notification: notification, argument: self?.argument) + print("argumentHandler \(self?.argumentHandler?(self?.operationType))") + UIAccessibility.post(notification: notification, argument: self?.argumentHandler?(self?.operationType)) self?.markAsFinished() } else { self?.stop() } } - timerSource?.schedule(deadline: .now() + notificationType.delay) - timerSource?.activate() } + timerSource?.schedule(deadline: .now() + notificationType.delay) + timerSource?.activate() } public func stop() { @@ -82,6 +89,8 @@ public class AccessbilityOperation: MVMCoreOperation { } } +public enum NavigationOperationType { case `default`, tab } + open class AccessibilityHandler { public static func shared() -> Self? { @@ -126,15 +135,18 @@ open class AccessibilityHandler { //Since foucs shifted to other elements cancelling existing focus shift notifications if any NotificationCenter.default.publisher(for: UIAccessibility.elementFocusedNotification) .sink { [weak self] notification in + print("testing \(UIAccessibility.focusedElement(using: .notificationVoiceOver))") + print("testing \(notification.userInfo)") self?.cancelAllOperations() }.store(in: &anyCancellable) } private func registerForTopNotificationsChanges() { - NotificationHandler.shared()?.onNotificationWillShow.sink { [weak self] (_, model) in - self?.hasTopNotitificationInPage = true - self?.capturePreviousFocusElement(for: model.molecule) - }.store(in: &anyCancellable) + NotificationHandler.shared()?.onNotificationWillShow + .sink { [weak self] (_, model) in + self?.hasTopNotitificationInPage = true + self?.capturePreviousFocusElement(for: model.molecule) + }.store(in: &anyCancellable) NotificationHandler.shared()?.onNotificationShown .sink { [weak self] (view, model) in self?.post(notification: .layoutChanged, argument: view) @@ -147,7 +159,6 @@ open class AccessibilityHandler { .sink { [weak self] (view, model) in self?.postAccessbilityToPrevElement(for: model.molecule) }.store(in: &anyCancellable) - print(anyCancellable) } open func capturePreviousFocusElement(for model: MoleculeModelProtocol) { @@ -166,13 +177,15 @@ open class AccessibilityHandler { accessibilityOperationQueue.cancelAllOperations() } - open func post(webpageChanged type: AccessibilityNotificationType, argument: Any? = nil) { - post(notification: type, argument: argument) + open func post(webpageChanged type: AccessibilityNotificationType) { + post(notification: type) } - public func post(notification type: AccessibilityNotificationType, argument: Any? = nil) { + public func post(notification type: AccessibilityNotificationType, operationType: NavigationOperationType = .default, argument: Any? = nil) { guard UIAccessibility.isVoiceOverRunning else { return } - let accessbilityOperation = AccessbilityOperation(notificationType: type, argument: argument) + let accessbilityOperation = AccessbilityOperation(notificationType: type, operationType: operationType) { [weak self] in + ($0 == .tab) ? self?.getFirstFocusedElementOnScreen() : argument + } add(operation: accessbilityOperation) } @@ -187,16 +200,17 @@ open class AccessibilityHandler { extension AccessibilityHandler: MVMCorePresentationDelegateProtocol { - public func navigationController(_ navigationController: UINavigationController, prepareDisplayFor viewController: UIViewController) { + open func navigationController(_ navigationController: UINavigationController, prepareDisplayFor viewController: UIViewController) { previousAccessiblityElement = nil delegate = viewController as? MVMCoreViewControllerProtocol if let announcementText { - let accessbilityOperation = AccessbilityOperation(notificationType: .announcement, argument: announcementText) + let accessbilityOperation = AccessbilityOperation(notificationType: .announcement) { _ in announcementText } add(operation: accessbilityOperation) } } - public func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) { + @MainActor + open func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) { guard UIAccessibility.isVoiceOverRunning, canPostAccessbilityNotification(for: viewController) else { return } //TODO: - For Tabbar change: adding 1.5 sec delay to shift focus to the top. for Temp fix added to check on childern count @@ -208,7 +222,8 @@ extension AccessibilityHandler: MVMCorePresentationDelegateProtocol { previousAccessiblityElement = getFirstFocusedElementOnScreen() } else { let accessbilityElement = getAccessbilityFocusedElement() - post(notification: navigationController.children.count == 1 ? .controllerChanged : .layoutChanged, argument: accessbilityElement ?? getFirstFocusedElementOnScreen()) + let operationType: NavigationOperationType = navigationController.children.count == 1 ? .tab : .default //TODO: - need to identify the operationType + post(notification: operationType == .tab ? .controllerChanged : .layoutChanged, operationType: operationType, argument: accessbilityElement ?? getFirstFocusedElementOnScreen()) accessibilityId = nil } }