From a454d0e3bde57f81c8971e24093606eb337b404c Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Mon, 28 Oct 2019 09:31:20 -0400 Subject: [PATCH 01/13] Revert "Merge branch 'feature/mva_3_0' into 'develop'" This reverts merge request !162 --- MVMCoreUI/Atoms/Views/Label.swift | 50 ++----------------- MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h | 1 - MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m | 12 ----- .../ThreeLayerTableViewController.swift | 7 +-- .../SwitchMolecules/HeadlineBodySwitch.swift | 8 +-- .../MVMCoreUIMoleculeMappingObject.m | 4 +- .../Templates/MoleculeListTemplate.swift | 22 -------- 7 files changed, 12 insertions(+), 92 deletions(-) diff --git a/MVMCoreUI/Atoms/Views/Label.swift b/MVMCoreUI/Atoms/Views/Label.swift index 83a44659..109f2f97 100644 --- a/MVMCoreUI/Atoms/Views/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label.swift @@ -266,7 +266,7 @@ public typealias ActionBlock = () -> () let length = attribute["length"] as? Int else { continue } - var range = NSRange(location: location, length: length) + let range = NSRange(location: location, length: length) switch attributeType { case "underline": @@ -278,17 +278,7 @@ public typealias ActionBlock = () -> () case "color": if let colorHex = attribute.optionalStringForKey(KeyTextColor), !colorHex.isEmpty { - // crash fix: removing attribute, even though it does not exists - let foregroundColorAttributesArray = attributedString.attributes(at: location, effectiveRange: &range).filter { (attribute) -> Bool in - if attribute.key == .foregroundColor { - return true - } else { - return false - } - } - if foregroundColorAttributesArray.isEmpty == false { - attributedString.removeAttribute(.foregroundColor, range: range) - } + attributedString.removeAttribute(.foregroundColor, range: range) attributedString.addAttribute(.foregroundColor, value: UIColor.mfGet(forHex: colorHex), range: range) } case "image": @@ -310,28 +300,8 @@ public typealias ActionBlock = () -> () case "font": if let fontStyle = attribute.optionalStringForKey("style") { let styles = MFStyler.styleGetAttributedString("0", withStyle: fontStyle) - // crash fix: removing font attribute, even though it does not exists - let fontAttributesArray = attributedString.attributes(at: location, effectiveRange: &range).filter { (attribute) -> Bool in - if attribute.key == .font { - return true - } else { - return false - } - } - if fontAttributesArray.isEmpty == false { - attributedString.removeAttribute(.font, range: range) - } - // crash fix: removing attribute, even though it does not exists - let foregroundColorAttributesArray = attributedString.attributes(at: location, effectiveRange: &range).filter { (attribute) -> Bool in - if attribute.key == .foregroundColor { - return true - } else { - return false - } - } - if foregroundColorAttributesArray.isEmpty == false { - attributedString.removeAttribute(.foregroundColor, range: range) - } + attributedString.removeAttribute(.font, range: range) + attributedString.removeAttribute(.foregroundColor, range: range) attributedString.addAttributes(styles.attributes(at: 0, effectiveRange: nil), range: range) } else { let fontSize = attribute["size"] as? CGFloat @@ -344,17 +314,7 @@ public typealias ActionBlock = () -> () } if let font = font { - // crash fix: removing font attribute, even though it does not exists - let fontAttributesArray = attributedString.attributes(at: location, effectiveRange: &range).filter { (attribute) -> Bool in - if attribute.key == .font { - return true - } else { - return false - } - } - if fontAttributesArray.isEmpty == false { - attributedString.removeAttribute(.font, range: range) - } + attributedString.removeAttribute(.font, range: range) attributedString.addAttribute(.font, value: font, range: range) } } diff --git a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h index 256aabfa..32e98f2a 100644 --- a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h +++ b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h @@ -24,7 +24,6 @@ typedef void(^ValueChangeBlock)(void); @property (nonatomic) BOOL shouldTouchToSwitch; @property (nullable, copy, nonatomic) ValueChangeBlock valueChangedBlock; -@property (nullable, copy, nonatomic) ValueChangeBlock actionBlock; + (nonnull instancetype)mvmSwitchDefault; + (nonnull instancetype)mvmSwitchDefaultWithValueChangeBlock:(nullable ValueChangeBlock)block; diff --git a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m index a3bbea81..f994b320 100644 --- a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m +++ b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m @@ -169,18 +169,6 @@ const CGFloat SwitchShakeIntensity = 2; } [self setState:[json boolForKey:@"state"] animated:false]; - - self.delegate = delegateObject; - NSDictionary *actionMap = [json dict:@"actionMap"]; - if (actionMap) { - [self addTarget:self action:@selector(addCustomAction) forControlEvents:UIControlEventTouchUpInside]; - } -} - -- (void)addCustomAction { - if (self.actionBlock) { - self.actionBlock(); - } } + (CGFloat)estimatedHeightForRow:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject { diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index d698b728..d1bfa0db 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -61,11 +61,6 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { return nil } - /// Space between the bottom view and the table sections, nil to fill. nil default - open func spaceBelowBottomView() -> CGFloat? { - return nil - } - /// can override to return a minimum fill space. open func minimumFillSpace() -> CGFloat { return 0 @@ -159,7 +154,7 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { bottomViewTopConstraint?.isActive = true bottomView.leftAnchor.constraint(equalTo: footerView.leftAnchor).isActive = true footerView.rightAnchor.constraint(equalTo: bottomView.rightAnchor).isActive = true - footerView.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor, constant: spaceBelowBottomView() ?? 0).isActive = true + footerView.bottomAnchor.constraint(equalTo: bottomView.bottomAnchor).isActive = true self.footerView = footerView showFooter(nil) } diff --git a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift index f585c2da..d373ce87 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift @@ -8,9 +8,9 @@ import UIKit -@objcMembers open class HeadlineBodySwitch: ViewConstrainingView { - public let headlineBody = HeadlineBody(frame: .zero) - public let mvmSwitch = MVMCoreUISwitch.mvmSwitchDefault() +@objcMembers public class HeadlineBodySwitch: ViewConstrainingView { + let headlineBody = HeadlineBody(frame: .zero) + let mvmSwitch = MVMCoreUISwitch.mvmSwitchDefault() // MARK: - MVMCoreViewProtocol open override func updateView(_ size: CGFloat) { @@ -35,7 +35,7 @@ import UIKit } // MARK: - MVMCoreUIMoleculeViewProtocol - open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) headlineBody.setWithJSON(json?.optionalDictionaryForKey("headlineBody"), delegateObject: delegateObject, additionalData: additionalData) mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData) diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index e64f643f..4559e23b 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -27,7 +27,7 @@ dispatch_once(&onceToken, ^{ mapping = [@{ @"label": Label.class, - @"line": SeparatorView.class, + @"separator": SeparatorView.class, @"button": ButtonView.class, @"textButton": MFTextButton.class, @"header": StandardHeaderView.class, @@ -41,7 +41,7 @@ @"checkbox" : Checkbox.class, @"checkboxWithLabelView" : CheckboxWithLabelView.class, @"cornerLabels" : CornerLabels.class, - @"progressbar": ProgressBar.class, + @"progressBar": ProgressBar.class, @"multiProgressBar": MultiProgress.class, @"checkbox": MVMCoreUICheckBox.class, @"radioButton": RadioButton.class, diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index 9df9fbc2..b400f0a9 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -42,11 +42,6 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { return molecule } - // for bottom gutter/free space - open override func spaceBelowBottomView() -> CGFloat? { - return PaddingDefaultVerticalSpacing - } - open override func newDataBuildScreen() { super.newDataBuildScreen() setup() @@ -158,23 +153,6 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { } } self.tableView?.deleteRows(at: indexPaths, with: animation) - // crash fix - self.tableView?.reloadData() - self.updateViewConstraints() - self.view.layoutIfNeeded() - } - - public func removeListItem(_ molecule: [AnyHashable : Any], animation: UITableView.RowAnimation) { - var indexPaths: [IndexPath] = [] - if let removeIndex = moleculesInfo?.firstIndex(where: { (moleculeInfo) -> Bool in - return NSDictionary(dictionary: molecule).isEqual(to: moleculeInfo.molecule["molecule"] as? [AnyHashable : Any] ?? [:]) - }) { - moleculesInfo?.remove(at: removeIndex) - indexPaths.append(IndexPath(row: removeIndex + indexPaths.count, section: 0)) - } - self.tableView?.deleteRows(at: indexPaths, with: animation) - // crash fix - self.tableView?.reloadData() self.updateViewConstraints() self.view.layoutIfNeeded() } From d196aa3cef3fa3a018ad1178f0f512ad3776196a Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 29 Oct 2019 09:03:19 -0400 Subject: [PATCH 02/13] Design defects fix --- .../BaseControllers/ThreeLayerTableViewController.swift | 6 ++++-- MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m | 1 + 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index d1bfa0db..5045d5a4 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -214,14 +214,16 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController { /// Subclass for a top view. open func viewForTop() -> UIView { let view = MVMCoreUICommonViewsUtility.commonView() - view.heightAnchor.constraint(equalToConstant: 0).isActive = true + // Small height is needed to stop apple from adding padding for grouped tables when no header. + view.heightAnchor.constraint(equalToConstant: 1).isActive = true return view } /// Subclass for a bottom view. open func viewForBottom() -> UIView { + // Default spacing is standard when no buttons. let view = MVMCoreUICommonViewsUtility.commonView() - view.heightAnchor.constraint(equalToConstant: 0).isActive = true + view.heightAnchor.constraint(equalToConstant: PaddingDefaultVerticalSpacing).isActive = true return view } diff --git a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m index fd5c9b21..4a21b1a5 100644 --- a/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUICommonViewsUtility.m @@ -33,6 +33,7 @@ static const CGFloat VertialShadowOffset = 6; UIView *view = [[UIView alloc] initWithFrame:CGRectZero]; view.translatesAutoresizingMaskIntoConstraints = NO; view.backgroundColor = [UIColor clearColor]; + view.directionalLayoutMargins = NSDirectionalEdgeInsetsZero; return view; } From 48a940f1606b1a4283af6d1d64feb92089a55d08 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 29 Oct 2019 10:12:59 -0400 Subject: [PATCH 03/13] fix to typos --- MVMCoreUI/Atoms/Buttons/ButtonView.swift | 2 +- MVMCoreUI/Atoms/Buttons/CaretButton.swift | 2 +- MVMCoreUI/Atoms/Views/MFLoadImageView.swift | 2 +- MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h | 1 + MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m | 14 +++++++++++++- MVMCoreUI/Atoms/Views/ProgressBar.swift | 2 +- MVMCoreUI/Molecules/ActionDetailWithImage.swift | 2 +- .../ImageHeadlineBody.swift | 2 +- .../Molecules/Items/MoleculeTableViewCell.swift | 2 +- .../Molecules/LeftRightViews/CornerLabels.swift | 2 +- .../SwitchMolecules/HeadlineBodySwitch.swift | 2 +- .../HeadlineBodyTextButtonSwitch.swift | 2 +- .../SwitchMolecules/LabelSwitch.swift | 2 +- MVMCoreUI/Molecules/ModuleMolecule.swift | 2 +- MVMCoreUI/Molecules/StandardFooterView.swift | 2 +- MVMCoreUI/Molecules/StandardHeaderView.swift | 2 +- .../EyebrowHeadlineBodyLink.swift | 2 +- .../VerticalCombinationViews/HeadlineBody.swift | 2 +- .../HeadlineBodyTextButton.swift | 2 +- MVMCoreUI/Organisms/MoleculeStackView.swift | 2 +- .../OtherHandlers/MVMCoreUIMoleculeMappingObject.m | 2 +- 21 files changed, 33 insertions(+), 20 deletions(-) diff --git a/MVMCoreUI/Atoms/Buttons/ButtonView.swift b/MVMCoreUI/Atoms/Buttons/ButtonView.swift index 0fc0f3c3..088c4a00 100644 --- a/MVMCoreUI/Atoms/Buttons/ButtonView.swift +++ b/MVMCoreUI/Atoms/Buttons/ButtonView.swift @@ -64,7 +64,7 @@ import UIKit primaryButton?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) } - public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 42 } diff --git a/MVMCoreUI/Atoms/Buttons/CaretButton.swift b/MVMCoreUI/Atoms/Buttons/CaretButton.swift index 4ca750c6..b01d2758 100644 --- a/MVMCoreUI/Atoms/Buttons/CaretButton.swift +++ b/MVMCoreUI/Atoms/Buttons/CaretButton.swift @@ -140,7 +140,7 @@ open class CaretButton: MFCustomButton, MVMCoreUIMoleculeViewProtocol, MVMCoreUI return UIStackView.Alignment.leading; } - public static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 10 } } diff --git a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift index 21802b38..361c0aa2 100644 --- a/MVMCoreUI/Atoms/Views/MFLoadImageView.swift +++ b/MVMCoreUI/Atoms/Views/MFLoadImageView.swift @@ -215,7 +215,7 @@ import UIKit pinEdges(.all) } - public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return json?.optionalCGFloatForKey("height") ?? 0 } diff --git a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h index 32e98f2a..256aabfa 100644 --- a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h +++ b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.h @@ -24,6 +24,7 @@ typedef void(^ValueChangeBlock)(void); @property (nonatomic) BOOL shouldTouchToSwitch; @property (nullable, copy, nonatomic) ValueChangeBlock valueChangedBlock; +@property (nullable, copy, nonatomic) ValueChangeBlock actionBlock; + (nonnull instancetype)mvmSwitchDefault; + (nonnull instancetype)mvmSwitchDefaultWithValueChangeBlock:(nullable ValueChangeBlock)block; diff --git a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m index f994b320..d68ee31a 100644 --- a/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m +++ b/MVMCoreUI/Atoms/Views/MVMCoreUISwitch.m @@ -145,7 +145,8 @@ const CGFloat SwitchShakeIntensity = 2; - (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData { self.json = json; - + self.delegate = delegateObject; + [FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol]; NSString *color = [json string:@"onTintColor"]; @@ -169,6 +170,17 @@ const CGFloat SwitchShakeIntensity = 2; } [self setState:[json boolForKey:@"state"] animated:false]; + + NSDictionary *actionMap = [json dict:@"actionMap"]; + if (actionMap) { + [self addTarget:self action:@selector(addCustomAction) forControlEvents:UIControlEventTouchUpInside]; + } +} + +- (void)addCustomAction { + if (self.actionBlock) { + self.actionBlock(); + } } + (CGFloat)estimatedHeightForRow:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject { diff --git a/MVMCoreUI/Atoms/Views/ProgressBar.swift b/MVMCoreUI/Atoms/Views/ProgressBar.swift index a9333966..1aecd537 100644 --- a/MVMCoreUI/Atoms/Views/ProgressBar.swift +++ b/MVMCoreUI/Atoms/Views/ProgressBar.swift @@ -73,7 +73,7 @@ import Foundation trackTintColor = UIColor.mfLightSilver() } - public static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 8 } } diff --git a/MVMCoreUI/Molecules/ActionDetailWithImage.swift b/MVMCoreUI/Molecules/ActionDetailWithImage.swift index 86cee41b..4811f20d 100644 --- a/MVMCoreUI/Molecules/ActionDetailWithImage.swift +++ b/MVMCoreUI/Molecules/ActionDetailWithImage.swift @@ -91,7 +91,7 @@ import UIKit imageLoader.updateView(size) } - public override static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 197 } diff --git a/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBody.swift b/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBody.swift index aca450aa..6e10a1a0 100644 --- a/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBody.swift +++ b/MVMCoreUI/Molecules/HorizontalCombinationViews/ImageHeadlineBody.swift @@ -82,7 +82,7 @@ import UIKit imageView.reset() } - public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 95 } } diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index 2ae52775..404e63ec 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -221,7 +221,7 @@ import UIKit backgroundColor = .white } - public static func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) else { return 80 } diff --git a/MVMCoreUI/Molecules/LeftRightViews/CornerLabels.swift b/MVMCoreUI/Molecules/LeftRightViews/CornerLabels.swift index 06917608..9b7dc062 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/CornerLabels.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/CornerLabels.swift @@ -174,7 +174,7 @@ import UIKit bottomRightLabel.styleB3(true) } - public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 34 } } diff --git a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift index d373ce87..cbffccb2 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift @@ -41,7 +41,7 @@ import UIKit mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData) } - public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 30 } diff --git a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodyTextButtonSwitch.swift b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodyTextButtonSwitch.swift index 0f184544..b0cf6956 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodyTextButtonSwitch.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodyTextButtonSwitch.swift @@ -41,7 +41,7 @@ import UIKit mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData) } - public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return HeadlineBodyTextButton.estimatedHeight(forRow: json, delegateObject: delegateObject) } diff --git a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/LabelSwitch.swift b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/LabelSwitch.swift index d47cf44c..f60202b3 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/LabelSwitch.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/LabelSwitch.swift @@ -41,7 +41,7 @@ import UIKit mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData) } - public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return MVMCoreUISwitch.estimatedHeight(forRow: json, delegateObject: delegateObject) } diff --git a/MVMCoreUI/Molecules/ModuleMolecule.swift b/MVMCoreUI/Molecules/ModuleMolecule.swift index c993b0c2..1dc7297e 100644 --- a/MVMCoreUI/Molecules/ModuleMolecule.swift +++ b/MVMCoreUI/Molecules/ModuleMolecule.swift @@ -54,7 +54,7 @@ open class ModuleMolecule: ViewConstrainingView { moduleMolecule?.reset?() } - public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { guard let moduleName = json?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { // Critical error return 0 diff --git a/MVMCoreUI/Molecules/StandardFooterView.swift b/MVMCoreUI/Molecules/StandardFooterView.swift index 7734883e..7c9c9282 100644 --- a/MVMCoreUI/Molecules/StandardFooterView.swift +++ b/MVMCoreUI/Molecules/StandardFooterView.swift @@ -26,7 +26,7 @@ open class StandardFooterView: ViewConstrainingView { (molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(false) } - public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { if let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) { return height + PaddingDefaultVerticalSpacing + PaddingDefaultVerticalSpacing } diff --git a/MVMCoreUI/Molecules/StandardHeaderView.swift b/MVMCoreUI/Molecules/StandardHeaderView.swift index 12819313..d54bde87 100644 --- a/MVMCoreUI/Molecules/StandardHeaderView.swift +++ b/MVMCoreUI/Molecules/StandardHeaderView.swift @@ -62,7 +62,7 @@ public class StandardHeaderView: ViewConstrainingView { separatorView?.show() } - public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { if let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) { return height + PaddingDefaultVerticalSpacing + PaddingDefaultVerticalSpacing } diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift index 306cf690..a7d96a34 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/EyebrowHeadlineBodyLink.swift @@ -64,7 +64,7 @@ import UIKit body.styleB2(true) } - public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 65 } } diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift index e63eb2ba..d236fc37 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBody.swift @@ -136,7 +136,7 @@ open class HeadlineBody: ViewConstrainingView { stylePageHeader() } - public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 58 } } diff --git a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyTextButton.swift b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyTextButton.swift index 009189cb..7c24cff4 100644 --- a/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyTextButton.swift +++ b/MVMCoreUI/Molecules/VerticalCombinationViews/HeadlineBodyTextButton.swift @@ -76,7 +76,7 @@ import UIKit textButton.reset() } - public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 60 } } diff --git a/MVMCoreUI/Organisms/MoleculeStackView.swift b/MVMCoreUI/Organisms/MoleculeStackView.swift index 95855f52..bda3f25b 100644 --- a/MVMCoreUI/Organisms/MoleculeStackView.swift +++ b/MVMCoreUI/Organisms/MoleculeStackView.swift @@ -199,7 +199,7 @@ public class MoleculeStackView: ViewConstrainingView { return name } - public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { guard let items = json?.optionalArrayForKey(KeyMolecules) else { return 0 } diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 4559e23b..7bdaf8af 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -27,7 +27,7 @@ dispatch_once(&onceToken, ^{ mapping = [@{ @"label": Label.class, - @"separator": SeparatorView.class, + @"line": SeparatorView.class, @"button": ButtonView.class, @"textButton": MFTextButton.class, @"header": StandardHeaderView.class, From d4cacec3102511c10de3bd6db1e4462fcda0b77b Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 29 Oct 2019 12:05:37 -0400 Subject: [PATCH 04/13] list item separation --- MVMCoreUI.xcodeproj/project.pbxproj | 6 +- .../Items/MoleculeCollectionViewCell.swift | 2 +- .../Items/MoleculeTableViewCell.swift | 295 +---------------- MVMCoreUI/Molecules/Items/TableViewCell.swift | 312 ++++++++++++++++++ .../Molecules/Items/TabsTableViewCell.swift | 2 +- MVMCoreUI/Molecules/ModuleMolecule.swift | 4 +- MVMCoreUI/Organisms/MoleculeStackView.swift | 4 +- 7 files changed, 331 insertions(+), 294 deletions(-) create mode 100644 MVMCoreUI/Molecules/Items/TableViewCell.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 9c75e016..955d6cf1 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -185,6 +185,7 @@ D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */; }; D2B18B7F2360913400A9AEDC /* Control.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B7E2360913400A9AEDC /* Control.swift */; }; D2B18B812360945C00A9AEDC /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B802360945C00A9AEDC /* View.swift */; }; + D2B18B9A236883BA00A9AEDC /* TableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B99236883BA00A9AEDC /* TableViewCell.swift */; }; D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */; }; D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */; }; @@ -383,6 +384,7 @@ D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeCollectionViewCell.swift; sourceTree = ""; }; D2B18B7E2360913400A9AEDC /* Control.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Control.swift; sourceTree = ""; }; D2B18B802360945C00A9AEDC /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; +\ D2B18B99236883BA00A9AEDC /* TableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewCell.swift; sourceTree = ""; }; D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageHeadlineBody.swift; sourceTree = ""; }; D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewControllerMappingObject.h; sourceTree = ""; }; D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = ""; }; @@ -473,6 +475,7 @@ D22479912316A9EF003FCCF9 /* Items */ = { isa = PBXGroup; children = ( + D2B18B99236883BA00A9AEDC /* TableViewCell.swift */, 01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */, D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */, D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */, @@ -570,7 +573,6 @@ D29DF10E21E67A77003B2FB9 /* Molecules */ = { isa = PBXGroup; children = ( - 017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */, D22479912316A9EF003FCCF9 /* Items */, D224798F2316A99F003FCCF9 /* LeftRightViews */, D224798E2316A995003FCCF9 /* HorizontalCombinationViews */, @@ -586,6 +588,7 @@ D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */, D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */, 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */, + 017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */, ); path = Molecules; sourceTree = ""; @@ -1104,6 +1107,7 @@ D2A6390122CBB1820052ED1F /* Carousel.swift in Sources */, D29DF2C721E7BF57003B2FB9 /* MFTabBarInteractor.m in Sources */, D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */, + D2B18B9A236883BA00A9AEDC /* TableViewCell.swift in Sources */, D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */, D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */, D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */, diff --git a/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift index 685d2e7a..75249f7d 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeCollectionViewCell.swift @@ -115,7 +115,7 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi backgroundColor = .white } - public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { + public class func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else { return nil } diff --git a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift index 404e63ec..4769b7e5 100644 --- a/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/MoleculeTableViewCell.swift @@ -8,227 +8,24 @@ import UIKit -@objcMembers open class MoleculeTableViewCell: UITableViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol { - - open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)? - open var json: [AnyHashable: Any]? - - // In updateView, will set padding to default. - open var updateViewHorizontalDefaults = true - - // For the accessory view convenience. - public var caretView: CaretView? - private var caretViewWidthSizeObject: MFSizeObject? - private var caretViewHeightSizeObject: MFSizeObject? - - // For separation between cells. - public var topSeparatorView: SeparatorView? - public var bottomSeparatorView: SeparatorView? - public enum SeparatorFrequency: String { - case All = "all" - case AllExceptTop = "allExceptTop" - case AllExceptBottom = "allExceptBottom" - case Between = "between" - } - - /// For subclasses that want to use a custom accessory view. - open var customAccessoryView = false - - public var topMarginPadding: CGFloat = 24 - public var bottomMarginPadding: CGFloat = 24 - - // MARK: - Styling - func style(with styleString: String?) { - guard let styleString = styleString else { - return - } - switch styleString { - case "standard": - styleStandard() - case "header": - styleHeader() - case "none": - styleNone() - default: break - } - } - - open override func layoutSubviews() { - super.layoutSubviews() - - // Ensures accessory view aligns to the center y derived from the - if let center = heroAccessoryCenter { - accessoryView?.center.y = center.y - } - } - - var heroAccessoryCenter: CGPoint? - - func styleStandard() { - topMarginPadding = 24 - bottomMarginPadding = 24 - bottomSeparatorView?.show() - bottomSeparatorView?.setAsLight() - } - - func styleHeader() { - topMarginPadding = 48 - bottomMarginPadding = 16 - bottomSeparatorView?.show() - bottomSeparatorView?.setAsRegular() - } - - func styleNone() { - topMarginPadding = 0 - bottomMarginPadding = 0 - bottomSeparatorView?.hide() - } - - public func willDisplay() { - - alignAccessoryToHero() - } - - // MARK: - Inits - public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - setupView() - } - - public required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - setupView() - } - - // MARK: - MFViewProtocol - public func updateView(_ size: CGFloat) { - MFStyler.setMarginsFor(self, size: size, defaultHorizontal: updateViewHorizontalDefaults, top: topMarginPadding, bottom: bottomMarginPadding) - if accessoryView != nil { - // Smaller left margin if accessory view. - var margin = directionalLayoutMargins - margin.trailing = 16 - contentView.directionalLayoutMargins = margin - } else { - contentView.directionalLayoutMargins = directionalLayoutMargins - } - topSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading) - bottomSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading) - - molecule?.updateView(size) - if let _ = accessoryView, let caretView = caretView, let widthObject = caretViewWidthSizeObject, let heightObject = caretViewHeightSizeObject { - caretView.frame = CGRect(x: 0, y: 0, width: widthObject.getValueBased(onSize: size), height: heightObject.getValueBased(onSize: size)) - } - topSeparatorView?.updateView(size) - bottomSeparatorView?.updateView(size) - } - - public func setupView() { - selectionStyle = .none - insetsLayoutMarginsFromSafeArea = false - contentView.insetsLayoutMarginsFromSafeArea = false - contentView.preservesSuperviewLayoutMargins = false - } - - /// NOTE: Should only be called when displayed or about to be displayed. - public func alignAccessoryToHero() { - - // Layout call required to force draw in memory to get dimensions of subviews. - layoutIfNeeded() - guard let heroLabel = findHeroLabel(views: contentView.subviews), let hero = heroLabel.hero else { return } - let rect = Label.boundingRect(forCharacterRange: NSRange(location: hero, length: 1), in: heroLabel) - accessoryView?.center.y = contentView.convert(UIView(frame: rect).center, from: heroLabel).y - heroAccessoryCenter = accessoryView?.center - } - - /// Traverses the view hierarchy for a 🦸‍♂️heroic Label. - private func findHeroLabel(views: [UIView]) -> Label? { - - if views.isEmpty { - return nil - } - - var queue = [UIView]() - - for view in views { - // Only one Label will have a hero in a table cell. - if let label = view as? Label, label.hero != nil { - return label - } - queue.append(contentsOf: view.subviews) - } - - return findHeroLabel(views: queue) - } +@objcMembers open class MoleculeTableViewCell: TableViewCell { // MARK: - MVMCoreUIMoleculeViewProtocol - public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - self.json = json + public override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - style(with: json?.optionalStringForKey("style")) - - if let useHorizontalMargins = json?.optionalBoolForKey("useHorizontalMargins") { - updateViewHorizontalDefaults = useHorizontalMargins - } - - if (json?.optionalBoolForKey("useVerticalMargins") ?? true) == false { - topMarginPadding = 0 - bottomMarginPadding = 0 - } - - if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) { - backgroundColor = UIColor.mfGet(forHex: backgroundColorString) - } - - // Add the caret if there is an action and it's not declared hidden. - if !customAccessoryView { - if let _ = json?.optionalDictionaryForKey("actionMap"), !json!.boolForKey("hideArrow") { - addCaretViewAccessory() - } else { - accessoryView = nil - } - } - - // override the separator - if let separator = json?.optionalDictionaryForKey("separator") { - addSeparatorsIfNeeded() - bottomSeparatorView?.setWithJSON(separator, delegateObject: delegateObject, additionalData: additionalData) - } - - guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { return } - - if molecule == nil { - if let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) { - contentView.addSubview(moleculeView) - let standardConstraints = (moleculeView as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true - NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: moleculeView, useMargins: standardConstraints).values)) - molecule = moleculeView - } - } else { - molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) - } - - // This molecule will by default handle margins. - if let castView = molecule as? MVMCoreUIViewConstrainingProtocol { - castView.shouldSetHorizontalMargins?(false) - castView.shouldSetVerticalMargins?(false) - } + guard molecule == nil, let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule), let moleculeView = MVMCoreUIMoleculeMappingObject.shared()?.createMolecule(forJSON: moleculeJSON, delegateObject: delegateObject, constrainIfNeeded: true) else { return } + addMolecule(moleculeView) } - public func reset() { - molecule?.reset?() - updateViewHorizontalDefaults = true - styleStandard() - backgroundColor = .white - } - - public class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + public override class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) else { return 80 } return max(2 * PaddingDefaultVerticalSpacing3, height) } - public static func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { + public override class func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else { return "\(self)<>" } @@ -236,87 +33,11 @@ import UIKit return "\(self)<\(moleculeName)>" } - public static func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { + public class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let theClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON) else { return nil } return theClass.requiredModules?(moleculeJSON, delegateObject: delegateObject, error: error) } - - // MARK: - Arrow - /// Adds the standard mvm style caret to the accessory view - @objc public func addCaretViewAccessory() { - guard accessoryView == nil else { return } - let width: CGFloat = 6 - let height: CGFloat = 10 - caretView = CaretView(lineThickness: CaretView.thin) - caretView?.frame = CGRect(x: 0, y: 0, width: width, height: height) - caretViewWidthSizeObject = MFSizeObject(standardSize: width, standardiPadPortraitSize: 9) - caretViewHeightSizeObject = MFSizeObject(standardSize: height, standardiPadPortraitSize: 16) - accessoryView = caretView - } - - // MARK: - MoleculeListCellProtocol - /// For when the separator between cells shows using json and frequency. Default is type: standard, frequency: allExceptTop. - public func setSeparatorWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, indexPath: IndexPath) { - addSeparatorsIfNeeded() - if let json = json { - topSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - bottomSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) - if let separatorFrequencyString = json.optionalStringForKey("frequency"), let separatorFrequency = SeparatorFrequency(rawValue: separatorFrequencyString) { - setSeparatorFrequency(separatorFrequency, indexPath: indexPath) - } - } else { - topSeparatorView?.hide() - bottomSeparatorView?.setAsLight() - setSeparatorFrequency(MoleculeTableViewCell.SeparatorFrequency.AllExceptTop, indexPath: indexPath) - } - } - - public func didSelectCell(atIndex indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { - if let actionMap = json?.optionalDictionaryForKey("actionMap") { - MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) - } - } - - // MARK: - Separator - func addSeparatorsIfNeeded() { - if topSeparatorView == nil { - topSeparatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionTop) - topSeparatorView?.hide() - } - if bottomSeparatorView == nil { - bottomSeparatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionBot) - bottomSeparatorView?.hide() - } - } - - /// For when the separator between cells shows. - public func setSeparatorFrequency(_ separatorFrequency: SeparatorFrequency, indexPath: IndexPath) { - switch separatorFrequency { - case .All: - if indexPath.row == 0 { - topSeparatorView?.show() - } else { - topSeparatorView?.hide() - } - bottomSeparatorView?.show() - case .AllExceptBottom: - topSeparatorView?.show() - bottomSeparatorView?.hide() - case .Between: - if indexPath.row == 0 { - topSeparatorView?.hide() - } else { - topSeparatorView?.show() - } - bottomSeparatorView?.hide() - case .AllExceptTop: - fallthrough - default: - topSeparatorView?.hide() - bottomSeparatorView?.show() - } - } } diff --git a/MVMCoreUI/Molecules/Items/TableViewCell.swift b/MVMCoreUI/Molecules/Items/TableViewCell.swift new file mode 100644 index 00000000..4386dc85 --- /dev/null +++ b/MVMCoreUI/Molecules/Items/TableViewCell.swift @@ -0,0 +1,312 @@ +// +// TableViewCell.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 10/29/19. +// Copyright © 2019 Verizon Wireless. All rights reserved. +// + +import UIKit + +@objcMembers open class TableViewCell: UITableViewCell { + open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)? + open var json: [AnyHashable: Any]? + + // In updateView, will set padding to default. + open var updateViewHorizontalDefaults = true + + // For the accessory view convenience. + private var caretView: CaretView? + private var caretViewWidthSizeObject: MFSizeObject? + private var caretViewHeightSizeObject: MFSizeObject? + + // For separation between cells. + public var topSeparatorView: SeparatorView? + public var bottomSeparatorView: SeparatorView? + public enum SeparatorFrequency: String { + case All = "all" + case AllExceptTop = "allExceptTop" + case AllExceptBottom = "allExceptBottom" + case Between = "between" + } + + /// For subclasses that want to use a custom accessory view. + open var customAccessoryView = false + + open var topMarginPadding: CGFloat = 24 + open var bottomMarginPadding: CGFloat = 24 + + private var heroAccessoryCenter: CGPoint? + + // MARK: - Styling + open func style(with styleString: String?) { + guard let styleString = styleString else { + return + } + switch styleString { + case "standard": + styleStandard() + case "header": + styleHeader() + case "none": + styleNone() + default: break + } + } + + open func styleStandard() { + topMarginPadding = 24 + bottomMarginPadding = 24 + bottomSeparatorView?.show() + bottomSeparatorView?.setAsLight() + } + + open func styleHeader() { + topMarginPadding = 48 + bottomMarginPadding = 16 + bottomSeparatorView?.show() + bottomSeparatorView?.setAsRegular() + } + + open func styleNone() { + topMarginPadding = 0 + bottomMarginPadding = 0 + bottomSeparatorView?.hide() + } + + /// Adds the molecule to the view. + open func addMolecule(_ molecule: UIView & MVMCoreUIMoleculeViewProtocol) { + contentView.addSubview(molecule) + let standardConstraints = (molecule as? MVMCoreUIViewConstrainingProtocol)?.useStandardConstraints?() ?? true + NSLayoutConstraint.activate(Array(NSLayoutConstraint.pinView(toSuperview: molecule, useMargins: standardConstraints).values)) + + // This molecule will by default handle margins. + if let castView = molecule as? MVMCoreUIViewConstrainingProtocol { + castView.shouldSetHorizontalMargins?(false) + castView.shouldSetVerticalMargins?(false) + } + self.molecule = molecule + } + + open override func layoutSubviews() { + super.layoutSubviews() + + // Ensures accessory view aligns to the center y derived from the + if let center = heroAccessoryCenter { + accessoryView?.center.y = center.y + } + } + + // MARK: - Inits + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + super.init(style: style, reuseIdentifier: reuseIdentifier) + setupView() + } + + public required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + setupView() + } + + // MARK: - MFViewProtocol + public func updateView(_ size: CGFloat) { + MFStyler.setMarginsFor(self, size: size, defaultHorizontal: updateViewHorizontalDefaults, top: topMarginPadding, bottom: bottomMarginPadding) + if accessoryView != nil { + // Smaller left margin if accessory view. + var margin = directionalLayoutMargins + margin.trailing = 16 + contentView.directionalLayoutMargins = margin + } else { + contentView.directionalLayoutMargins = directionalLayoutMargins + } + topSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading) + bottomSeparatorView?.setLeftAndRightPinConstant(directionalLayoutMargins.leading) + + molecule?.updateView(size) + if let _ = accessoryView, let caretView = caretView, let widthObject = caretViewWidthSizeObject, let heightObject = caretViewHeightSizeObject { + caretView.frame = CGRect(x: 0, y: 0, width: widthObject.getValueBased(onSize: size), height: heightObject.getValueBased(onSize: size)) + } + topSeparatorView?.updateView(size) + bottomSeparatorView?.updateView(size) + } + + public func setupView() { + selectionStyle = .none + insetsLayoutMarginsFromSafeArea = false + contentView.insetsLayoutMarginsFromSafeArea = false + contentView.preservesSuperviewLayoutMargins = false + } + + // MARK: - MVMCoreUIMoleculeViewProtocol + public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + self.json = json + + style(with: json?.optionalStringForKey("style")) + + if let useHorizontalMargins = json?.optionalBoolForKey("useHorizontalMargins") { + updateViewHorizontalDefaults = useHorizontalMargins + } + + if (json?.optionalBoolForKey("useVerticalMargins") ?? true) == false { + topMarginPadding = 0 + bottomMarginPadding = 0 + } + + if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) { + backgroundColor = UIColor.mfGet(forHex: backgroundColorString) + } + + // Add the caret if there is an action and it's not declared hidden. + if !customAccessoryView { + if let _ = json?.optionalDictionaryForKey("actionMap"), !json!.boolForKey("hideArrow") { + addCaretViewAccessory() + } else { + accessoryView = nil + } + } + + // override the separator + if let separator = json?.optionalDictionaryForKey("separator") { + addSeparatorsIfNeeded() + bottomSeparatorView?.setWithJSON(separator, delegateObject: delegateObject, additionalData: additionalData) + } + + guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { return } + molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) + + // This molecule will by default handle margins. + if let castView = molecule as? MVMCoreUIViewConstrainingProtocol { + castView.shouldSetHorizontalMargins?(false) + castView.shouldSetVerticalMargins?(false) + } + } + + public func reset() { + molecule?.reset?() + updateViewHorizontalDefaults = true + styleStandard() + backgroundColor = .white + } + + public class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) else { + return 80 + } + return max(2 * PaddingDefaultVerticalSpacing3, height) + } + + public class func name(forReuse molecule: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { + return molecule?.optionalStringForKey(KeyMoleculeName) ?? "" + } + + // MARK: - Arrow + /// Adds the standard mvm style caret to the accessory view + @objc public func addCaretViewAccessory() { + guard accessoryView == nil else { return } + let width: CGFloat = 6 + let height: CGFloat = 10 + caretView = CaretView(lineThickness: CaretView.thin) + caretView?.frame = CGRect(x: 0, y: 0, width: width, height: height) + caretViewWidthSizeObject = MFSizeObject(standardSize: width, standardiPadPortraitSize: 9) + caretViewHeightSizeObject = MFSizeObject(standardSize: height, standardiPadPortraitSize: 16) + accessoryView = caretView + } + + /// NOTE: Should only be called when displayed or about to be displayed. + public func alignAccessoryToHero() { + + // Layout call required to force draw in memory to get dimensions of subviews. + layoutIfNeeded() + guard let heroLabel = findHeroLabel(views: contentView.subviews), let hero = heroLabel.hero else { return } + let rect = Label.boundingRect(forCharacterRange: NSRange(location: hero, length: 1), in: heroLabel) + accessoryView?.center.y = contentView.convert(UIView(frame: rect).center, from: heroLabel).y + heroAccessoryCenter = accessoryView?.center + } + + /// Traverses the view hierarchy for a 🦸‍♂️heroic Label. + private func findHeroLabel(views: [UIView]) -> Label? { + + if views.isEmpty { + return nil + } + + var queue = [UIView]() + + for view in views { + // Only one Label will have a hero in a table cell. + if let label = view as? Label, label.hero != nil { + return label + } + queue.append(contentsOf: view.subviews) + } + + return findHeroLabel(views: queue) + } + + // MARK: - MoleculeListCellProtocol + /// For when the separator between cells shows using json and frequency. Default is type: standard, frequency: allExceptTop. + public func setSeparatorWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?, indexPath: IndexPath) { + addSeparatorsIfNeeded() + if let json = json { + topSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + bottomSeparatorView?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) + if let separatorFrequencyString = json.optionalStringForKey("frequency"), let separatorFrequency = SeparatorFrequency(rawValue: separatorFrequencyString) { + setSeparatorFrequency(separatorFrequency, indexPath: indexPath) + } + } else { + topSeparatorView?.hide() + bottomSeparatorView?.setAsLight() + setSeparatorFrequency(TableViewCell.SeparatorFrequency.AllExceptTop, indexPath: indexPath) + } + } + + public func didSelectCell(atIndex indexPath: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + if let actionMap = json?.optionalDictionaryForKey("actionMap") { + MVMCoreActionHandler.shared()?.handleAction(with: actionMap, additionalData: additionalData, delegateObject: delegateObject) + } + } + + public func willDisplay() { + alignAccessoryToHero() + } + + // MARK: - Separator + open func addSeparatorsIfNeeded() { + if topSeparatorView == nil { + topSeparatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionTop) + topSeparatorView?.hide() + } + if bottomSeparatorView == nil { + bottomSeparatorView = SeparatorView.separatorAdd(to: self, position: SeparatorPositionBot) + bottomSeparatorView?.hide() + } + } + + /// For when the separator between cells shows. + public func setSeparatorFrequency(_ separatorFrequency: SeparatorFrequency, indexPath: IndexPath) { + switch separatorFrequency { + case .All: + if indexPath.row == 0 { + topSeparatorView?.show() + } else { + topSeparatorView?.hide() + } + bottomSeparatorView?.show() + case .AllExceptBottom: + topSeparatorView?.show() + bottomSeparatorView?.hide() + case .Between: + if indexPath.row == 0 { + topSeparatorView?.hide() + } else { + topSeparatorView?.show() + } + bottomSeparatorView?.hide() + case .AllExceptTop: + fallthrough + default: + topSeparatorView?.hide() + bottomSeparatorView?.show() + } + } +} diff --git a/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift b/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift index 1c509a8f..1a1796cd 100644 --- a/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/TabsTableViewCell.swift @@ -8,7 +8,7 @@ import UIKit -@objcMembers public class TabsTableViewCell: MoleculeTableViewCell { +@objcMembers public class TabsTableViewCell: TableViewCell { let tabs = TopTabbar(frame: .zero) var delegateObject: MVMCoreUIDelegateObject? var previousTabIndex = 0 diff --git a/MVMCoreUI/Molecules/ModuleMolecule.swift b/MVMCoreUI/Molecules/ModuleMolecule.swift index 1dc7297e..77acc007 100644 --- a/MVMCoreUI/Molecules/ModuleMolecule.swift +++ b/MVMCoreUI/Molecules/ModuleMolecule.swift @@ -62,7 +62,7 @@ open class ModuleMolecule: ViewConstrainingView { return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.estimatedHeight?(forRow: module, delegateObject: delegateObject) ?? 0 } - public override static func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { + public override class func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { guard let moduleName = molecule?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else { // Critical error return "moduleMolecule<>" @@ -70,7 +70,7 @@ open class ModuleMolecule: ViewConstrainingView { return "moduleMolecule<" + (MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.name?(forReuse: module, delegateObject: delegateObject) ?? module.stringForkey(KeyMoleculeName)) + ">" } - public override static func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { + public override class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { let moduleName = json?.optionalStringForKey("moduleName") if moduleName == nil || delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) == nil { if let errorObject = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess), code: CoreUIErrorCode.ErrorCodeModuleMolecule.rawValue, domain: ErrorDomainNative, location: String(describing: self)) { diff --git a/MVMCoreUI/Organisms/MoleculeStackView.swift b/MVMCoreUI/Organisms/MoleculeStackView.swift index bda3f25b..cafe21b0 100644 --- a/MVMCoreUI/Organisms/MoleculeStackView.swift +++ b/MVMCoreUI/Organisms/MoleculeStackView.swift @@ -184,7 +184,7 @@ public class MoleculeStackView: ViewConstrainingView { } } - public override static func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { + public override class func name(forReuse molecule: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> String? { // This will aggregate names of molecules to make an id. guard let molecules = molecule?.optionalArrayForKey(KeyMolecules) else { return "stack<>" @@ -221,7 +221,7 @@ public class MoleculeStackView: ViewConstrainingView { return estimatedHeight } - public override static func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { + public override class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { guard let items = json?.optionalArrayForKey(KeyMolecules) else { return nil } From 77a11a69d5eb3a08b141d49e8a1ff63a577704a2 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 29 Oct 2019 12:12:58 -0400 Subject: [PATCH 05/13] Fix for project file --- MVMCoreUI.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 955d6cf1..a0ef1271 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -50,6 +50,7 @@ D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */ = {isa = PBXBuildFile; fileRef = D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */; }; D260D7B622D68514007E7233 /* MVMCoreUIPagingProtocol.h in Headers */ = {isa = PBXBuildFile; fileRef = D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */; settings = {ATTRIBUTES = (Public, ); }; }; D274CA332236A78900B01B62 /* StandardFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D274CA322236A78900B01B62 /* StandardFooterView.swift */; }; + D2755D7B23689C7500485468 /* TableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2755D7A23689C7500485468 /* TableViewCell.swift */; }; D27CD40E2322EEAF00C1DC07 /* TabsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27CD40D2322EEAF00C1DC07 /* TabsTableViewCell.swift */; }; D27CD4102339057800C1DC07 /* EyebrowHeadlineBodyLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27CD40F2339057800C1DC07 /* EyebrowHeadlineBodyLink.swift */; }; D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AAB3223FDDAE00C46919 /* MFLoadImageView.swift */; }; @@ -185,7 +186,6 @@ D2A6390522CBCE160052ED1F /* MoleculeCollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */; }; D2B18B7F2360913400A9AEDC /* Control.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B7E2360913400A9AEDC /* Control.swift */; }; D2B18B812360945C00A9AEDC /* View.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B802360945C00A9AEDC /* View.swift */; }; - D2B18B9A236883BA00A9AEDC /* TableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B18B99236883BA00A9AEDC /* TableViewCell.swift */; }; D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */; }; D2C5001821F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h in Headers */ = {isa = PBXBuildFile; fileRef = D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */; settings = {ATTRIBUTES = (Public, ); }; }; D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */ = {isa = PBXBuildFile; fileRef = D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */; }; @@ -245,6 +245,7 @@ D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIPageControl.m; sourceTree = ""; }; D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIPagingProtocol.h; sourceTree = ""; }; D274CA322236A78900B01B62 /* StandardFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardFooterView.swift; sourceTree = ""; }; + D2755D7A23689C7500485468 /* TableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewCell.swift; sourceTree = ""; }; D27CD40D2322EEAF00C1DC07 /* TabsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsTableViewCell.swift; sourceTree = ""; }; D27CD40F2339057800C1DC07 /* EyebrowHeadlineBodyLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EyebrowHeadlineBodyLink.swift; sourceTree = ""; }; D282AAB3223FDDAE00C46919 /* MFLoadImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MFLoadImageView.swift; sourceTree = ""; }; @@ -384,7 +385,6 @@ D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeCollectionViewCell.swift; sourceTree = ""; }; D2B18B7E2360913400A9AEDC /* Control.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Control.swift; sourceTree = ""; }; D2B18B802360945C00A9AEDC /* View.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = View.swift; sourceTree = ""; }; -\ D2B18B99236883BA00A9AEDC /* TableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableViewCell.swift; sourceTree = ""; }; D2B1E3E422F37D6A0065F95C /* ImageHeadlineBody.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageHeadlineBody.swift; sourceTree = ""; }; D2C5001621F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIViewControllerMappingObject.h; sourceTree = ""; }; D2C5001721F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIViewControllerMappingObject.m; sourceTree = ""; }; @@ -475,7 +475,7 @@ D22479912316A9EF003FCCF9 /* Items */ = { isa = PBXGroup; children = ( - D2B18B99236883BA00A9AEDC /* TableViewCell.swift */, + D2755D7A23689C7500485468 /* TableViewCell.swift */, 01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */, D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */, D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */, @@ -1071,6 +1071,7 @@ D29DF24D21E6A177003B2FB9 /* MFTextField.m in Sources */, D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */, D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */, + D2755D7B23689C7500485468 /* TableViewCell.swift in Sources */, D29DF25421E6A177003B2FB9 /* MFMdnTextField.m in Sources */, D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */, D2A514672213885800345BFB /* StandardHeaderView.swift in Sources */, @@ -1107,7 +1108,6 @@ D2A6390122CBB1820052ED1F /* Carousel.swift in Sources */, D29DF2C721E7BF57003B2FB9 /* MFTabBarInteractor.m in Sources */, D29DF29521E7ADB8003B2FB9 /* ProgrammaticScrollViewController.m in Sources */, - D2B18B9A236883BA00A9AEDC /* TableViewCell.swift in Sources */, D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */, D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */, D2E1FAE12268E81D00AEFD8C /* MoleculeListTemplate.swift in Sources */, From 75ea4d60f0b5c359a24237596add0903a8094a88 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 29 Oct 2019 12:18:20 -0400 Subject: [PATCH 06/13] commit missed protocol --- MVMCoreUI/Molecules/Items/TableViewCell.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Molecules/Items/TableViewCell.swift b/MVMCoreUI/Molecules/Items/TableViewCell.swift index 4386dc85..77e2c57f 100644 --- a/MVMCoreUI/Molecules/Items/TableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/TableViewCell.swift @@ -8,7 +8,7 @@ import UIKit -@objcMembers open class TableViewCell: UITableViewCell { +@objcMembers open class TableViewCell: UITableViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol { open var molecule: (UIView & MVMCoreUIMoleculeViewProtocol)? open var json: [AnyHashable: Any]? From e5c0191b18b3b7418c89c3ee1f84dadf909245c4 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 29 Oct 2019 12:30:45 -0400 Subject: [PATCH 07/13] fix to check --- MVMCoreUI/Templates/MoleculeListTemplate.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Templates/MoleculeListTemplate.swift index b400f0a9..ea2913c2 100644 --- a/MVMCoreUI/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Templates/MoleculeListTemplate.swift @@ -126,7 +126,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController { open override func addMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) { // This dispatch is needed to fix a race condition that can occur if this function is called during the table setup. DispatchQueue.main.async { - guard let cell = sender as? MoleculeTableViewCell, let indexPath = self.tableView?.indexPath(for: cell) else { return } + guard let indexPath = self.tableView?.indexPath(for: sender) else { return } var indexPaths: [IndexPath] = [] for molecule in molecules { if let info = self.getMoleculeInfo(with: molecule) { From 26dac186dc4a069a2247e10228f1428a39ab4ed0 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 29 Oct 2019 13:13:35 -0400 Subject: [PATCH 08/13] undo undo --- .../SwitchMolecules/HeadlineBodySwitch.swift | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift index cbffccb2..79110460 100644 --- a/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift +++ b/MVMCoreUI/Molecules/LeftRightViews/SwitchMolecules/HeadlineBodySwitch.swift @@ -8,9 +8,9 @@ import UIKit -@objcMembers public class HeadlineBodySwitch: ViewConstrainingView { - let headlineBody = HeadlineBody(frame: .zero) - let mvmSwitch = MVMCoreUISwitch.mvmSwitchDefault() +@objcMembers open class HeadlineBodySwitch: ViewConstrainingView { + public let headlineBody = HeadlineBody(frame: .zero) + public let mvmSwitch = MVMCoreUISwitch.mvmSwitchDefault() // MARK: - MVMCoreViewProtocol open override func updateView(_ size: CGFloat) { @@ -19,7 +19,7 @@ import UIKit mvmSwitch.updateView(size) } - public override func setupView() { + open override func setupView() { super.setupView() guard mvmSwitch.superview == nil else { return @@ -35,24 +35,24 @@ import UIKit } // MARK: - MVMCoreUIMoleculeViewProtocol - public override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + open override func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData) headlineBody.setWithJSON(json?.optionalDictionaryForKey("headlineBody"), delegateObject: delegateObject, additionalData: additionalData) mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData) } - public override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + open override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { return 30 } - public override func setAsMolecule() { + open override func setAsMolecule() { super.setAsMolecule() headlineBody.setAsMolecule() (mvmSwitch as MVMCoreUIMoleculeViewProtocol).setAsMolecule?() headlineBody.styleListItem() } - public override func reset() { + open override func reset() { super.reset() headlineBody.reset() (mvmSwitch as MVMCoreUIMoleculeViewProtocol).reset?() From 7e810ec334d231b67f5a08ed50bebb24eca875ae Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 29 Oct 2019 13:17:40 -0400 Subject: [PATCH 09/13] undo undo --- MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m index 7bdaf8af..e64f643f 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIMoleculeMappingObject.m @@ -41,7 +41,7 @@ @"checkbox" : Checkbox.class, @"checkboxWithLabelView" : CheckboxWithLabelView.class, @"cornerLabels" : CornerLabels.class, - @"progressBar": ProgressBar.class, + @"progressbar": ProgressBar.class, @"multiProgressBar": MultiProgress.class, @"checkbox": MVMCoreUICheckBox.class, @"radioButton": RadioButton.class, From 59be22c0e0146bfaff2a4e8a759a7aa3c21ced2c Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 29 Oct 2019 13:47:49 -0400 Subject: [PATCH 10/13] enum clean --- MVMCoreUI/Molecules/Items/TableViewCell.swift | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/MVMCoreUI/Molecules/Items/TableViewCell.swift b/MVMCoreUI/Molecules/Items/TableViewCell.swift index 77e2c57f..e8cfc179 100644 --- a/MVMCoreUI/Molecules/Items/TableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/TableViewCell.swift @@ -24,10 +24,10 @@ import UIKit public var topSeparatorView: SeparatorView? public var bottomSeparatorView: SeparatorView? public enum SeparatorFrequency: String { - case All = "all" - case AllExceptTop = "allExceptTop" - case AllExceptBottom = "allExceptBottom" - case Between = "between" + case all + case allExceptTop + case allExceptBottom + case between } /// For subclasses that want to use a custom accessory view. @@ -256,7 +256,7 @@ import UIKit } else { topSeparatorView?.hide() bottomSeparatorView?.setAsLight() - setSeparatorFrequency(TableViewCell.SeparatorFrequency.AllExceptTop, indexPath: indexPath) + setSeparatorFrequency(TableViewCell.SeparatorFrequency.allExceptTop, indexPath: indexPath) } } @@ -285,24 +285,24 @@ import UIKit /// For when the separator between cells shows. public func setSeparatorFrequency(_ separatorFrequency: SeparatorFrequency, indexPath: IndexPath) { switch separatorFrequency { - case .All: + case .all: if indexPath.row == 0 { topSeparatorView?.show() } else { topSeparatorView?.hide() } bottomSeparatorView?.show() - case .AllExceptBottom: + case .allExceptBottom: topSeparatorView?.show() bottomSeparatorView?.hide() - case .Between: + case .between: if indexPath.row == 0 { topSeparatorView?.hide() } else { topSeparatorView?.show() } bottomSeparatorView?.hide() - case .AllExceptTop: + case .allExceptTop: fallthrough default: topSeparatorView?.hide() From d901ded4c12a1e91ad56864b035fd0f136ef0734 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 29 Oct 2019 13:56:19 -0400 Subject: [PATCH 11/13] open view up! --- MVMCoreUI/BaseClasses/View.swift | 49 ++++++++++++++++---------------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/MVMCoreUI/BaseClasses/View.swift b/MVMCoreUI/BaseClasses/View.swift index 735243df..d470c539 100644 --- a/MVMCoreUI/BaseClasses/View.swift +++ b/MVMCoreUI/BaseClasses/View.swift @@ -8,47 +8,46 @@ import UIKit -public class View: UIView { - var json: [AnyHashable: Any]? +open class View: UIView { + open var json: [AnyHashable: Any]? private var initialSetupPerformed = false public override init(frame: CGRect) { - super.init(frame: .zero) - initialSetup() - } + super.init(frame: .zero) + initialSetup() + } - init() { - super.init(frame: .zero) - initialSetup() - } - - public required init?(coder: NSCoder) { - super.init(coder: coder) - initialSetup() - } - - public func initialSetup() { - if !initialSetupPerformed { - initialSetupPerformed = true - setupView() - } + init() { + super.init(frame: .zero) + initialSetup() + } + + public required init?(coder: NSCoder) { + super.init(coder: coder) + initialSetup() + } + + public func initialSetup() { + if !initialSetupPerformed { + initialSetupPerformed = true + setupView() } } +} extension View: MVMCoreViewProtocol { - public func updateView(_ size: CGFloat) { - } + open func updateView(_ size: CGFloat) {} /// Will be called only once. - public func setupView() { + open func setupView() { translatesAutoresizingMaskIntoConstraints = false insetsLayoutMarginsFromSafeArea = false } } extension View: MVMCoreUIMoleculeViewProtocol { - public func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { + open func setWithJSON(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { self.json = json if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) { @@ -56,7 +55,7 @@ extension View: MVMCoreUIMoleculeViewProtocol { } } - public func reset() { + open func reset() { backgroundColor = .clear } } From e98a0ce76bde5d00cd6a1c1d00da1dac0d2b15b8 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 29 Oct 2019 15:23:44 -0400 Subject: [PATCH 12/13] update pr comments --- MVMCoreUI/BaseClasses/View.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/BaseClasses/View.swift b/MVMCoreUI/BaseClasses/View.swift index d470c539..bc6e7634 100644 --- a/MVMCoreUI/BaseClasses/View.swift +++ b/MVMCoreUI/BaseClasses/View.swift @@ -8,7 +8,7 @@ import UIKit -open class View: UIView { +@objcMembers open class View: UIView { open var json: [AnyHashable: Any]? private var initialSetupPerformed = false @@ -18,7 +18,7 @@ open class View: UIView { initialSetup() } - init() { + public init() { super.init(frame: .zero) initialSetup() } From 2fab14d946404e49d310b6da8b7df091536050f8 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 29 Oct 2019 15:26:43 -0400 Subject: [PATCH 13/13] kevin comment --- MVMCoreUI/Molecules/Items/TableViewCell.swift | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/Molecules/Items/TableViewCell.swift b/MVMCoreUI/Molecules/Items/TableViewCell.swift index e8cfc179..cc531d75 100644 --- a/MVMCoreUI/Molecules/Items/TableViewCell.swift +++ b/MVMCoreUI/Molecules/Items/TableViewCell.swift @@ -141,24 +141,26 @@ import UIKit public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { self.json = json - style(with: json?.optionalStringForKey("style")) + guard let json = json else { return } - if let useHorizontalMargins = json?.optionalBoolForKey("useHorizontalMargins") { + style(with: json.optionalStringForKey("style")) + + if let useHorizontalMargins = json.optionalBoolForKey("useHorizontalMargins") { updateViewHorizontalDefaults = useHorizontalMargins } - if (json?.optionalBoolForKey("useVerticalMargins") ?? true) == false { + if (json.optionalBoolForKey("useVerticalMargins") ?? true) == false { topMarginPadding = 0 bottomMarginPadding = 0 } - if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) { + if let backgroundColorString = json.optionalStringForKey(KeyBackgroundColor) { backgroundColor = UIColor.mfGet(forHex: backgroundColorString) } // Add the caret if there is an action and it's not declared hidden. if !customAccessoryView { - if let _ = json?.optionalDictionaryForKey("actionMap"), !json!.boolForKey("hideArrow") { + if let _ = json.optionalDictionaryForKey("actionMap"), !json.boolForKey("hideArrow") { addCaretViewAccessory() } else { accessoryView = nil @@ -166,12 +168,12 @@ import UIKit } // override the separator - if let separator = json?.optionalDictionaryForKey("separator") { + if let separator = json.optionalDictionaryForKey("separator") { addSeparatorsIfNeeded() bottomSeparatorView?.setWithJSON(separator, delegateObject: delegateObject, additionalData: additionalData) } - guard let json = json, let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { return } + guard let moleculeJSON = json.optionalDictionaryForKey(KeyMolecule) else { return } molecule?.setWithJSON(moleculeJSON, delegateObject: delegateObject, additionalData: additionalData) // This molecule will by default handle margins.