diff --git a/MVMCoreUI/Accessibility/AccessibilityHandler.swift b/MVMCoreUI/Accessibility/AccessibilityHandler.swift index 83b0347a..d609aecd 100644 --- a/MVMCoreUI/Accessibility/AccessibilityHandler.swift +++ b/MVMCoreUI/Accessibility/AccessibilityHandler.swift @@ -224,6 +224,7 @@ class AccessibilityHandlerBehavior: PageVisibilityBehavior { ///https://oneconfluence.verizon.com/display/MFD/Accessibility+-+Focus+Retain func onPageShown(_ delegateObject: MVMCoreUIDelegateObject?) { updateAccessibilityViews(delegateObject) //To track FAB & HAB elements on UI + identifyAndPrepareForButtonRotor() guard let accessibilityElement = AccessibilityHandler.shared()?.getPreDefinedFocusedElementIfAny() else { return } if AccessibilityHandler.shared()?.hasTopNotitificationInPage ?? false { AccessibilityHandler.shared()?.previousAccessiblityElement = accessibilityElement @@ -234,24 +235,15 @@ class AccessibilityHandlerBehavior: PageVisibilityBehavior { //MARK: - Private Methods private func identifyAndPrepareForButtonRotor() { - let currentViewController = ((delegateObj?.moleculeDelegate as? MVMCoreViewManagerViewControllerProtocol)?.manager as? SubNavManagerController) ?? (delegateObj?.moleculeDelegate as? UIViewController) - var rotorElements: [(model: MoleculeModelProtocol, indexPath: IndexPath)] = [] - var currentIndexPath: IndexPath? - rotorElements = (currentViewController as? MoleculeListTemplate)?.templateModel?.reduceDepthFirstTraverse(options: .parentFirst, depth: 0, initialResult: rotorElements, nextPartialResult: { result, model, depth in - if let listModel = model as? (ListItemModelProtocol & MoleculeModelProtocol), let indexPath = (currentViewController as? MoleculeListTemplate)?.getIndexPath(for: listModel) { currentIndexPath = indexPath - } - var result = result - if (model.accessibilityTraits?.contains(.button) ?? false), let currentIndexPath { - result.append((model, currentIndexPath)) - } - return result - }) ?? [] + let currentViewController = ((delegateObj?.moleculeDelegate as? MVMCoreViewManagerViewControllerProtocol)?.manager as? SubNavManagerController) ?? (delegateObj?.moleculeDelegate as? ViewController) var accessibilityButtons: [Any?]? = currentViewController?.navigationItem.leftBarButtonItems ?? [] accessibilityButtons?.append(contentsOf: currentViewController?.navigationItem.rightBarButtonItems ?? []) if let tabs = (currentViewController as? SubNavManagerController)?.tabs { accessibilityButtons?.append(contentsOf: tabs.subviews.filter { $0.accessibilityTraits.contains(.button) }) } - accessibilityButtons?.append(contentsOf: rotorElements) + if let rotorElements = getRotorButtonsBasedOn(template: currentViewController) { + accessibilityButtons?.append(contentsOf: rotorElements) + } if let tabBarHidden = (delegateObj?.moleculeDelegate as? TabPageModelProtocol)?.tabBarHidden, !tabBarHidden { accessibilityButtons?.append(contentsOf: (MVMCoreUISplitViewController.main()?.tabBar?.subviews ?? []).filter { $0.accessibilityTraits.contains(.button)}) } @@ -259,6 +251,29 @@ class AccessibilityHandlerBehavior: PageVisibilityBehavior { currentViewController?.navigationController?.accessibilityCustomRotors = [createRotorForButtons()].compactMap { $0 } } + private func getRotorButtonsBasedOn(template: ViewController?) -> [Any]? { + if let currentViewController = template as? MoleculeListTemplate, let templateModel = currentViewController.templateModel { //List templates + var rotorElements: [(model: MoleculeModelProtocol, indexPath: IndexPath)] = [] + var currentIndexPath: IndexPath? + rotorElements = templateModel.reduceDepthFirstTraverse(options: .parentFirst, depth: 0, initialResult: rotorElements, nextPartialResult: { result, model, depth in + if let listModel = model as? (ListItemModelProtocol & MoleculeModelProtocol), let indexPath = currentViewController.getIndexPath(for: listModel) { + currentIndexPath = indexPath + } + var result = result + if (model.accessibilityTraits?.contains(.button) ?? false), let currentIndexPath { + result.append((model, currentIndexPath)) + } + return result + }) + let headerViewElements = currentViewController.tableView.tableHeaderView?.getMoleculeViews { (subView: MoleculeViewProtocol) in subView.accessibilityTraits.contains(.button) } as? [Any] ?? [] + let footerViewElements = currentViewController.tableView.tableFooterView?.getMoleculeViews { (subView: MoleculeViewProtocol) in subView.accessibilityTraits.contains(.button) } as? [Any] ?? [] + return headerViewElements + (rotorElements as [Any]) + footerViewElements + } else if let currentViewController = template as? MoleculeStackTemplate { //Stack templates + return currentViewController.view?.getMoleculeViews { (subView: MoleculeViewProtocol) in subView.accessibilityTraits.contains(.button) } + } + return nil + } + private func createRotorForButtons() -> UIAccessibilityCustomRotor? { guard let accessibilityButtons, !accessibilityButtons.isEmpty, let tableView = (delegateObj?.moleculeListDelegate as? MoleculeListTemplate)?.tableView else { return nil } return UIAccessibilityCustomRotor(name: "Buttons") { [weak self] predicate in @@ -277,7 +292,7 @@ class AccessibilityHandlerBehavior: PageVisibilityBehavior { var rotorElement = accessibilityButtons[self.currentRotorIndex - 1] if let element = rotorElement as? (model: MoleculeModelProtocol, indexPath: IndexPath) { tableView.scrollToRow(at: element.indexPath, at: .middle, animated: false) - rotorElement = tableView.cellForRow(at: element.indexPath)?.getMoleculeViews { (subView: MoleculeViewProtocol) in subView.accessibilityTraits.contains(.button) }.filter { ($0 as? MoleculeViewModelProtocol)?.moleculeModel?.id == element.model.id } as Any + rotorElement = tableView.cellForRow(at: element.indexPath)?.getMoleculeViews { (subView: MoleculeViewProtocol) in subView.accessibilityTraits.contains(.button) }.filter { ($0 as? MoleculeViewModelProtocol)?.moleculeModel?.id == element.model.id }.first as Any } UIAccessibility.post(notification: .layoutChanged, argument: rotorElement) return UIAccessibilityCustomRotorItemResult(targetElement: rotorElement as! NSObjectProtocol, targetRange: nil)