diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift index c2d9f14e..9ed1c849 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/CheckboxModel.swift @@ -6,10 +6,8 @@ // Copyright © 2020 Verizon Wireless. All rights reserved. // -import Foundation - -@objcMembers public class CheckboxModel: MoleculeModelProtocol, FormFieldProtocol { +@objcMembers public class CheckboxModel: MoleculeModelProtocol, SelectableModel, FormFieldProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -66,13 +64,25 @@ import Foundation case groupName case offAction } - + //-------------------------------------------------- - // MARK: - Methods + // MARK: - Form Validation //-------------------------------------------------- public func formFieldValue() -> AnyHashable? { checked } + //-------------------------------------------------- + // MARK: - Selectable Protocol + //-------------------------------------------------- + + public func select(as isSelected: Bool) { + checked = isSelected + } + + public var selectedValue: Bool { + checked + } + //-------------------------------------------------- // MARK: - Initializer //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Protocols/MoleculeDelegateProtocol.swift b/MVMCoreUI/Atomic/Protocols/MoleculeDelegateProtocol.swift index e61ea662..0435cf66 100644 --- a/MVMCoreUI/Atomic/Protocols/MoleculeDelegateProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/MoleculeDelegateProtocol.swift @@ -6,30 +6,34 @@ // Copyright © 2019 Verizon Wireless. All rights reserved. // -import Foundation public protocol MoleculeDelegateProtocol: AnyObject { - + func getRootMolecules() -> [MoleculeModelProtocol] /// returns a module for the corresponding module name. - func getModuleWithName(_ name: String?) -> [AnyHashable : Any]? + func getModuleWithName(_ name: String?) -> [AnyHashable: Any]? + func getModuleWithName(_ moleculeName: String) -> MoleculeModelProtocol? - + /// Notifies the delegate that the molecule layout update. Should be called when the layout may change due to an async method. Mainly used for list or collections. func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) //optional - + /// Asks the delegate to add or remove molecules. Mainly used for list or collections. func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? + func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) + func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) } extension MoleculeDelegateProtocol { - public func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) {} + public func moleculeLayoutUpdated(_ molecule: MoleculeViewProtocol) { } - public func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? { return nil } - public func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) {} - public func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) {} + public func getIndexPath(for molecule: ListItemModelProtocol & MoleculeModelProtocol) -> IndexPath? { nil } + + public func addMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], indexPath: IndexPath, animation: UITableView.RowAnimation) { } + + public func removeMolecules(_ molecules: [ListItemModelProtocol & MoleculeModelProtocol], animation: UITableView.RowAnimation) { } } diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index 9745b3f4..06efad05 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -507,7 +507,7 @@ import UIKit //-------------------------------------------------- open func getRootMolecules() -> [MoleculeModelProtocol] { - return model?.rootMolecules ?? [] + model?.rootMolecules ?? [] } open func getModuleWithName(_ name: String?) -> [AnyHashable: Any]? { diff --git a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift index 66720d1e..a197a4d7 100644 --- a/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift +++ b/MVMCoreUI/Behaviors/SelectAllBoxesBehavior.swift @@ -6,9 +6,13 @@ // Copyright © 2021 Verizon Wireless. All rights reserved. // +public protocol SelectableModel { + var selectedValue: Bool { get } + func select(as isSelected: Bool) +} public class SelectAllBoxesBehaviorModel: PageBehaviorModelProtocol { - public class var identifier: String { "selectAllBoxesBehavior" } + public class var identifier: String { "pageSelectAllBoxesBehavior" } public var shouldAllowMultipleInstances: Bool { false } public init() { } } @@ -16,9 +20,11 @@ public class SelectAllBoxesBehaviorModel: PageBehaviorModelProtocol { public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior { //-------------------------------------------------- - // MARK: - Active Model + // MARK: - Properties //-------------------------------------------------- + var didSelectAll = false + //-------------------------------------------------- // MARK: - Delegate //-------------------------------------------------- @@ -37,31 +43,44 @@ public class SelectAllBoxesBehavior: PageCustomActionHandlerBehavior { // MARK: - Custom Action //-------------------------------------------------- - // Either play or pause + // To select or deselect all controls adhereing to public func handleAction(type actionType: String?, information: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) -> Bool { - guard actionType == "selectAllBoxes" else { return false } + guard actionType == "selectAllBoxes", + let selectableModels: [SelectableModel] = delegate?.moleculeDelegate?.getRootMolecules().allMoleculesOfType(), + !selectableModels.isEmpty + else { return false } - let currentVC = MVMCoreUIUtility.getCurrentVisibleController() + didSelectAll.toggle() + let navButtonTitle: String? = (didSelectAll ? information!["deSelectAllTitle"] : information!["selectAllTitle"]) as? String - traverseAndSelectCheckboxes(view: currentVC.view) + for selectableModel in selectableModels { + if toSelect(model: selectableModel) || toDeselect(model: selectableModel) { + selectableModel.select(as: didSelectAll) + } + } + + MVMCoreDispatchUtility.performBlock(onMainThread: { + // TODO: move to protocol function instead + guard let controller = self.delegate?.moleculeDelegate as? ViewController else { return } + controller.handleNewDataAndUpdateUI() + + if MVMCoreUIUtility.getCurrentVisibleController() == controller { + // Update navigation bar if showing. + controller.navigationItem.rightBarButtonItem?.title = navButtonTitle + controller.manager?.refreshNavigationUI() + } + }) - // TODO: A) select all boxes and the change the nav button title to "deselect all" - // TODO: B) deselect all boxes and change nav nutton title to "select all" - return true } - private func traverseAndSelectCheckboxes(view: UIView) { - - if let checkbox = view as? Checkbox { - checkbox.isSelected = true - return - } - - for subview in view.subviews { - traverseAndSelectCheckboxes(view: subview) - } + func toSelect(model: SelectableModel) -> Bool { + didSelectAll && !model.selectedValue + } + + func toDeselect(model: SelectableModel) -> Bool { + !didSelectAll && model.selectedValue } }