From 9c111471a802c9d60fce62b0900e3e0f35b7de21 Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Sat, 23 Sep 2023 17:32:36 +0530 Subject: [PATCH] added custom button rotor for molecular views --- .../Accessibility/AccessibilityHandler.swift | 55 +++++++++++++++++++ .../AccessibilityModelProtocol.swift | 18 ++++++ .../Protocols/MoleculeViewProtocol.swift | 4 +- MVMCoreUI/BaseClasses/Button.swift | 5 ++ 4 files changed, 80 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Accessibility/AccessibilityHandler.swift b/MVMCoreUI/Accessibility/AccessibilityHandler.swift index 0ed3348b..83b0347a 100644 --- a/MVMCoreUI/Accessibility/AccessibilityHandler.swift +++ b/MVMCoreUI/Accessibility/AccessibilityHandler.swift @@ -201,9 +201,12 @@ class AccessibilityHandlerBehavior: PageVisibilityBehavior { private var delegateObj: MVMCoreUIDelegateObject? private var anyCancellable: Set = [] + private var accessibilityButtons: [Any]? + private var currentRotorIndex: Int = 0 required public init(model: PageBehaviorModelProtocol, delegateObject: MVMCoreUIDelegateObject?) { } + //MARK: - PageVisibiltyBehaviour public func willShowPage(_ delegateObject: MVMCoreUIDelegateObject?) { updateAccessibilityViews(delegateObject) guard let controller = delegateObject?.moleculeDelegate as? UIViewController, @@ -229,6 +232,58 @@ 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 + }) ?? [] + 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 tabBarHidden = (delegateObj?.moleculeDelegate as? TabPageModelProtocol)?.tabBarHidden, !tabBarHidden { + accessibilityButtons?.append(contentsOf: (MVMCoreUISplitViewController.main()?.tabBar?.subviews ?? []).filter { $0.accessibilityTraits.contains(.button)}) + } + self.accessibilityButtons = accessibilityButtons?.compactMap { $0 } + currentViewController?.navigationController?.accessibilityCustomRotors = [createRotorForButtons()].compactMap { $0 } + } + + 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 + guard let self, let accessibilityButtons = self.accessibilityButtons else { return UIAccessibilityCustomRotorItemResult() } + if predicate.searchDirection == .next { + self.currentRotorIndex += 1 + if self.currentRotorIndex > accessibilityButtons.count { + self.currentRotorIndex = 1 + } + } else { + self.currentRotorIndex -= 1 + if self.currentRotorIndex <= 0 { + self.currentRotorIndex = accessibilityButtons.count + } + } + 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 + } + UIAccessibility.post(notification: .layoutChanged, argument: rotorElement) + return UIAccessibilityCustomRotorItemResult(targetElement: rotorElement as! NSObjectProtocol, targetRange: nil) + } + } + private func updateAccessibilityViews(_ delegateObject: MVMCoreUIDelegateObject?) { var accessibilityElements: [Any?] = [MVMCoreUISplitViewController.main()?.topAlertView] if let managerController = (delegateObject?.moleculeDelegate as? MVMCoreViewManagerViewControllerProtocol)?.manager as? SubNavManagerController { diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/AccessibilityModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/AccessibilityModelProtocol.swift index a7508e39..809334d8 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/AccessibilityModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/AccessibilityModelProtocol.swift @@ -12,6 +12,9 @@ import Foundation public protocol AccessibilityModelProtocol { var accessibilityIdentifier: String? { get set } + var accessibilityTraits: UIAccessibilityTraits? { get set } + var accessibilityText: String? { get set } + var accessibilityValue: String? { get set } } public extension AccessibilityModelProtocol { @@ -20,4 +23,19 @@ public extension AccessibilityModelProtocol { get { nil } set { } } + + var accessibilityTraits: UIAccessibilityTraits? { + get { nil } + set { } + } + + var accessibilityText: String? { + get { nil } + set { } + } + + var accessibilityValue: String? { + get { nil } + set { } + } } diff --git a/MVMCoreUI/Atomic/Protocols/MoleculeViewProtocol.swift b/MVMCoreUI/Atomic/Protocols/MoleculeViewProtocol.swift index dbd6b2df..3a6bc8f6 100644 --- a/MVMCoreUI/Atomic/Protocols/MoleculeViewProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/MoleculeViewProtocol.swift @@ -107,9 +107,9 @@ public protocol MoleculeViewModelProtocol: UIView { var moleculeModel: MoleculeModelProtocol? { get } } -extension MoleculeViewModelProtocol { +public extension MoleculeViewModelProtocol { - var moleculeModel: MoleculeModelProtocol? { + public var moleculeModel: MoleculeModelProtocol? { get { nil } } } diff --git a/MVMCoreUI/BaseClasses/Button.swift b/MVMCoreUI/BaseClasses/Button.swift index 15ea1e03..7450b716 100644 --- a/MVMCoreUI/BaseClasses/Button.swift +++ b/MVMCoreUI/BaseClasses/Button.swift @@ -161,3 +161,8 @@ extension Button: AppleGuidelinesProtocol { Self.acceptablyOutsideBounds(point: point, bounds: bounds) } } + +extension Button: MoleculeViewModelProtocol { + + public var moleculeModel: MoleculeModelProtocol? { model } +}