updated operation type

This commit is contained in:
Krishna Kishore Bandaru 2023-07-21 12:43:15 +05:30
parent e77da88713
commit 646210f1a3

View File

@ -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 //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 { var delay: Double {
switch self { switch self {
case .controllerChanged, .webPageLoaded: case .controllerChanged:
return 1.5 return 1.5
case .webPageLoaded:
return 2.0
case .screenChanged, .layoutChanged: case .screenChanged, .layoutChanged:
return 0.0 return 0.0
default: default:
@ -44,35 +46,40 @@ public enum AccessibilityNotificationType: String, Codable {
} }
} }
public typealias ArgumentHandler = ((NavigationOperationType?) -> Any?)
public class AccessbilityOperation: MVMCoreOperation { public class AccessbilityOperation: MVMCoreOperation {
let argument: Any? private let operationType: NavigationOperationType
let notificationType: AccessibilityNotificationType private let argumentHandler: ArgumentHandler?
private let notificationType: AccessibilityNotificationType
private var timerSource: DispatchSourceTimer? private var timerSource: DispatchSourceTimer?
public init(notificationType: AccessibilityNotificationType, argument: Any?) { public init(notificationType: AccessibilityNotificationType, operationType: NavigationOperationType = .default, argumentHandler: ArgumentHandler?) {
self.notificationType = notificationType self.notificationType = notificationType
self.argument = argument self.argumentHandler = argumentHandler
self.operationType = operationType
} }
public override func main() { public override func main() {
Task { @MainActor in guard UIAccessibility.isVoiceOverRunning, !checkAndHandleForCancellation() else {
guard UIAccessibility.isVoiceOverRunning, !checkAndHandleForCancellation() else { stop()
stop() return
return }
} timerSource = DispatchSource.makeTimerSource()
timerSource = DispatchSource.makeTimerSource() timerSource?.setEventHandler {
timerSource?.setEventHandler { [weak self] in Task { @MainActor [weak self] in
if !(self?.isCancelled ?? false), let notification = self?.notificationType.accessibilityNotification { 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() self?.markAsFinished()
} else { } else {
self?.stop() self?.stop()
} }
} }
timerSource?.schedule(deadline: .now() + notificationType.delay)
timerSource?.activate()
} }
timerSource?.schedule(deadline: .now() + notificationType.delay)
timerSource?.activate()
} }
public func stop() { public func stop() {
@ -82,6 +89,8 @@ public class AccessbilityOperation: MVMCoreOperation {
} }
} }
public enum NavigationOperationType { case `default`, tab }
open class AccessibilityHandler { open class AccessibilityHandler {
public static func shared() -> Self? { 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 //Since foucs shifted to other elements cancelling existing focus shift notifications if any
NotificationCenter.default.publisher(for: UIAccessibility.elementFocusedNotification) NotificationCenter.default.publisher(for: UIAccessibility.elementFocusedNotification)
.sink { [weak self] notification in .sink { [weak self] notification in
print("testing \(UIAccessibility.focusedElement(using: .notificationVoiceOver))")
print("testing \(notification.userInfo)")
self?.cancelAllOperations() self?.cancelAllOperations()
}.store(in: &anyCancellable) }.store(in: &anyCancellable)
} }
private func registerForTopNotificationsChanges() { private func registerForTopNotificationsChanges() {
NotificationHandler.shared()?.onNotificationWillShow.sink { [weak self] (_, model) in NotificationHandler.shared()?.onNotificationWillShow
self?.hasTopNotitificationInPage = true .sink { [weak self] (_, model) in
self?.capturePreviousFocusElement(for: model.molecule) self?.hasTopNotitificationInPage = true
}.store(in: &anyCancellable) self?.capturePreviousFocusElement(for: model.molecule)
}.store(in: &anyCancellable)
NotificationHandler.shared()?.onNotificationShown NotificationHandler.shared()?.onNotificationShown
.sink { [weak self] (view, model) in .sink { [weak self] (view, model) in
self?.post(notification: .layoutChanged, argument: view) self?.post(notification: .layoutChanged, argument: view)
@ -147,7 +159,6 @@ open class AccessibilityHandler {
.sink { [weak self] (view, model) in .sink { [weak self] (view, model) in
self?.postAccessbilityToPrevElement(for: model.molecule) self?.postAccessbilityToPrevElement(for: model.molecule)
}.store(in: &anyCancellable) }.store(in: &anyCancellable)
print(anyCancellable)
} }
open func capturePreviousFocusElement(for model: MoleculeModelProtocol) { open func capturePreviousFocusElement(for model: MoleculeModelProtocol) {
@ -166,13 +177,15 @@ open class AccessibilityHandler {
accessibilityOperationQueue.cancelAllOperations() accessibilityOperationQueue.cancelAllOperations()
} }
open func post(webpageChanged type: AccessibilityNotificationType, argument: Any? = nil) { open func post(webpageChanged type: AccessibilityNotificationType) {
post(notification: type, argument: argument) 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 } 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) add(operation: accessbilityOperation)
} }
@ -187,16 +200,17 @@ open class AccessibilityHandler {
extension AccessibilityHandler: MVMCorePresentationDelegateProtocol { extension AccessibilityHandler: MVMCorePresentationDelegateProtocol {
public func navigationController(_ navigationController: UINavigationController, prepareDisplayFor viewController: UIViewController) { open func navigationController(_ navigationController: UINavigationController, prepareDisplayFor viewController: UIViewController) {
previousAccessiblityElement = nil previousAccessiblityElement = nil
delegate = viewController as? MVMCoreViewControllerProtocol delegate = viewController as? MVMCoreViewControllerProtocol
if let announcementText { if let announcementText {
let accessbilityOperation = AccessbilityOperation(notificationType: .announcement, argument: announcementText) let accessbilityOperation = AccessbilityOperation(notificationType: .announcement) { _ in announcementText }
add(operation: accessbilityOperation) add(operation: accessbilityOperation)
} }
} }
public func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) { @MainActor
open func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) {
guard UIAccessibility.isVoiceOverRunning, guard UIAccessibility.isVoiceOverRunning,
canPostAccessbilityNotification(for: viewController) else { return } 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 //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() previousAccessiblityElement = getFirstFocusedElementOnScreen()
} else { } else {
let accessbilityElement = getAccessbilityFocusedElement() 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 accessibilityId = nil
} }
} }