From 658ed16bbdbe9b08bf41cc346358a64d1d9f8a71 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 3 Sep 2019 15:14:12 -0400 Subject: [PATCH] accordion list item --- MVMCoreUI.xcodeproj/project.pbxproj | 4 ++ .../AccordionMoleculeTableViewCell.swift | 40 +++++++++++++++++++ .../Items/MoleculeTableViewCell.swift | 18 ++++++--- .../MVMCoreUIMoleculeMappingObject.m | 1 + .../OtherHandlers/MoleculeDelegateProtocol.h | 4 ++ .../Templates/MoleculeListTemplate.swift | 30 ++++++++++++++ 6 files changed, 91 insertions(+), 6 deletions(-) create mode 100644 MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 2913a9a6..9768fcf8 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -27,6 +27,7 @@ D224798C231450C8003FCCF9 /* HeadlineBodySwitch.swift in Sources */ = {isa = PBXBuildFile; fileRef = D224798B231450C8003FCCF9 /* HeadlineBodySwitch.swift */; }; D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */; }; D22479962316AF6E003FCCF9 /* HeadlineBodyTextButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479952316AF6D003FCCF9 /* HeadlineBodyTextButton.swift */; }; + D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */; }; D22D1F1A220341F60077CEC0 /* MVMCoreUICheckBox.h in Headers */ = {isa = PBXBuildFile; fileRef = D22D1F18220341F50077CEC0 /* MVMCoreUICheckBox.h */; settings = {ATTRIBUTES = (Public, ); }; }; D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */ = {isa = PBXBuildFile; fileRef = D22D1F19220341F50077CEC0 /* MVMCoreUICheckBox.m */; }; D22D1F1E220343560077CEC0 /* MVMCoreUICheckMarkView.h in Headers */ = {isa = PBXBuildFile; fileRef = D22D1F1C220343560077CEC0 /* MVMCoreUICheckMarkView.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -208,6 +209,7 @@ D224798B231450C8003FCCF9 /* HeadlineBodySwitch.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodySwitch.swift; sourceTree = ""; }; D22479932316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NSLayoutConstraintExtension.swift; sourceTree = ""; }; D22479952316AF6D003FCCF9 /* HeadlineBodyTextButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyTextButton.swift; sourceTree = ""; }; + D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccordionMoleculeTableViewCell.swift; sourceTree = ""; }; D22D1F18220341F50077CEC0 /* MVMCoreUICheckBox.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUICheckBox.h; sourceTree = ""; }; D22D1F19220341F50077CEC0 /* MVMCoreUICheckBox.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUICheckBox.m; sourceTree = ""; }; D22D1F1C220343560077CEC0 /* MVMCoreUICheckMarkView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUICheckMarkView.h; sourceTree = ""; }; @@ -448,6 +450,7 @@ children = ( D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */, D2E1FADC2268B25E00AEFD8C /* MoleculeTableViewCell.swift */, + D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */, ); path = Items; sourceTree = ""; @@ -994,6 +997,7 @@ DBC4391922442197001AB423 /* DashLine.swift in Sources */, D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */, D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */, + D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */, D22D1F1F220343560077CEC0 /* MVMCoreUICheckMarkView.m in Sources */, D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */, D29DF11721E6805F003B2FB9 /* UIColor+MFConvenience.m in Sources */, diff --git a/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift new file mode 100644 index 00000000..630dfb7d --- /dev/null +++ b/MVMCoreUI/Molecules/Items/AccordionMoleculeTableViewCell.swift @@ -0,0 +1,40 @@ +// +// AccordionMoleculeTableViewCell.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 8/30/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers public class AccordionMoleculeTableViewCell: MoleculeTableViewCell { + let accordionButton = createAccordionButton() + + static func createAccordionButton() -> MFCustomButton { + let accordionButton = MFCustomButton(type: .custom) + accordionButton.setTitle("+", for: .normal) + accordionButton.setTitleColor(.black, for: .normal) + accordionButton.frame = CGRect(x: 0, y: 0, width: 20, height: 20) + return accordionButton + } + + override public func setupView() { + customAccessoryView = true + super.setupView() + accessoryView = accordionButton + } + + public override func didSelectCell(atIndex indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + accordionButton.isSelected = !accordionButton.isSelected + accordionButton.setTitle(accordionButton.isSelected ? "-" : "+", for: .normal) + guard let molecules = json?.optionalArrayForKey(KeyMolecules) as? [[AnyHashable: Any]] else { + return + } + if accordionButton.isSelected { + delegateObject?.moleculeDelegate?.addMolecules?(molecules, senderIndexPath: indexPath) + } else { + delegateObject?.moleculeDelegate?.removeMolecules?(molecules, senderIndexPath: indexPath) + } + } +} diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index c1054e33..167e0ea8 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -32,6 +32,9 @@ import UIKit case Between = "between" } + /// For subclasses that want to use a custom accessory view. + open var customAccessoryView = false + // MARK: - Inits public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { super.init(style: style, reuseIdentifier: reuseIdentifier) @@ -103,10 +106,12 @@ import UIKit } // Add the caret if there is an action and it's not declared hidden. - if let _ = json?.optionalDictionaryForKey("actionMap"), !json!.boolForKey("hideArrow") { - addCaretViewAccessory() - } else { - accessoryView = nil + if !customAccessoryView { + if let _ = json?.optionalDictionaryForKey("actionMap"), !json!.boolForKey("hideArrow") { + addCaretViewAccessory() + } else { + accessoryView = nil + } } // override the separator @@ -152,9 +157,10 @@ import UIKit public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else { - return nil + return "\(self)<>" } - return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) + let moleculeName = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: molecule)?.name?(forReuse: molecule, delegateObject: delegateObject) ?? molecule.optionalStringForKey(KeyMoleculeName) ?? "" + return "\(self)<\(moleculeName)>" } public static func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index fe84278b..9175781b 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -43,6 +43,7 @@ @"progressBar": ProgressBar.class, @"checkbox": MVMCoreUICheckBox.class, @"listItem": MoleculeTableViewCell.class, + @"accordionListItem": AccordionMoleculeTableViewCell.class, @"switch": MVMCoreUISwitch.class, @"leftRightLabelView": LeftRightLabelView.class, @"actionDetailWithImage": ActionDetailWithImage.class, diff --git a/MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h b/MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h index fa91e0fc..cfa1504f 100644 --- a/MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h +++ b/MVMCoreUI/OtherHandlers/MoleculeDelegateProtocol.h @@ -16,4 +16,8 @@ /// Notifies the delegate that the molecule layout update. Should be called when the layout may change due to an async method. - (void)moleculeLayoutUpdated:(nonnull UIView *)molecule; +/// Asks the delegate to add or remove molecules. +- (void)addMolecules:(nonnull NSArray *)molecules senderIndexPath:(nonnull NSIndexPath *)indexPath; +- (void)removeMolecules:(nonnull NSArray *)molecules senderIndexPath:(nonnull NSIndexPath *)indexPath; + @end diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index abec1b01..7ad011b3 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -117,6 +117,36 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { } } + open override func addMolecules(_ molecules: [[AnyHashable: Any]], senderIndexPath indexPath: IndexPath) { + var indexPaths: [IndexPath] = [] + var moleculeList: [(identifier: String, class: AnyClass, molecule: [AnyHashable: Any])] = [] + for (index, molecule) in molecules.enumerated() { + if let info = getMoleculeInfo(with: molecule) { + moleculeList.append(info) + indexPaths.append(IndexPath(row: indexPath.row + 1 + index, section: 0)) + tableView?.register(info.class, forCellReuseIdentifier: info.identifier) + } + } + moleculesInfo?.insert(contentsOf: moleculeList, at: indexPath.row + 1) + tableView?.insertRows(at: indexPaths, with: .automatic) + } + + open override func removeMolecules(_ molecules: [[AnyHashable: Any]], senderIndexPath indexPath: IndexPath) { + guard let moleculesList = moleculesInfo else { + return + } + var indexPaths: [IndexPath] = [] + for (index, moleculeInfo) in moleculesList.enumerated() { + if molecules.contains(where: { (molecule) -> Bool in + return NSDictionary(dictionary: molecule).isEqual(to: moleculeInfo.molecule) + }) { + indexPaths.append(IndexPath(row: index, section: 0)) + moleculesInfo?.remove(at: index) + } + } + tableView?.deleteRows(at: indexPaths, with: .automatic) + } + // MARK: - Convenience /// Returns the (identifier, class) of the molecule for the given map. func getMoleculeInfo(with molecule: [AnyHashable: Any]?) -> (identifier: String, class: AnyClass, molecule: [AnyHashable: Any])? {