Merge branch 'feature/swiftified_textField' of gitlab.verizon.com:BPHV_MIPS/mvm_core_ui into feature/swiftified_textField
This commit is contained in:
commit
3163e9bb40
@ -67,6 +67,7 @@
|
|||||||
D260D7B222D65BDD007E7233 /* MVMCoreUIPageControl.m in Sources */ = {isa = PBXBuildFile; fileRef = D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */; };
|
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, ); }; };
|
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 */; };
|
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 */; };
|
D27CD40E2322EEAF00C1DC07 /* TabsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27CD40D2322EEAF00C1DC07 /* TabsTableViewCell.swift */; };
|
||||||
D27CD4102339057800C1DC07 /* EyebrowHeadlineBodyLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27CD40F2339057800C1DC07 /* EyebrowHeadlineBodyLink.swift */; };
|
D27CD4102339057800C1DC07 /* EyebrowHeadlineBodyLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = D27CD40F2339057800C1DC07 /* EyebrowHeadlineBodyLink.swift */; };
|
||||||
D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AAB3223FDDAE00C46919 /* MFLoadImageView.swift */; };
|
D282AAB4223FDDAE00C46919 /* MFLoadImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D282AAB3223FDDAE00C46919 /* MFLoadImageView.swift */; };
|
||||||
@ -256,6 +257,7 @@
|
|||||||
D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIPageControl.m; sourceTree = "<group>"; };
|
D260D7B022D65BDD007E7233 /* MVMCoreUIPageControl.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MVMCoreUIPageControl.m; sourceTree = "<group>"; };
|
||||||
D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIPagingProtocol.h; sourceTree = "<group>"; };
|
D260D7B522D68509007E7233 /* MVMCoreUIPagingProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIPagingProtocol.h; sourceTree = "<group>"; };
|
||||||
D274CA322236A78900B01B62 /* StandardFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardFooterView.swift; sourceTree = "<group>"; };
|
D274CA322236A78900B01B62 /* StandardFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StandardFooterView.swift; sourceTree = "<group>"; };
|
||||||
|
D2755D7A23689C7500485468 /* TableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewCell.swift; sourceTree = "<group>"; };
|
||||||
D27CD40D2322EEAF00C1DC07 /* TabsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsTableViewCell.swift; sourceTree = "<group>"; };
|
D27CD40D2322EEAF00C1DC07 /* TabsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TabsTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
D27CD40F2339057800C1DC07 /* EyebrowHeadlineBodyLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EyebrowHeadlineBodyLink.swift; sourceTree = "<group>"; };
|
D27CD40F2339057800C1DC07 /* EyebrowHeadlineBodyLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EyebrowHeadlineBodyLink.swift; sourceTree = "<group>"; };
|
||||||
D282AAB3223FDDAE00C46919 /* MFLoadImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MFLoadImageView.swift; sourceTree = "<group>"; };
|
D282AAB3223FDDAE00C46919 /* MFLoadImageView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MFLoadImageView.swift; sourceTree = "<group>"; };
|
||||||
@ -485,6 +487,7 @@
|
|||||||
D22479912316A9EF003FCCF9 /* Items */ = {
|
D22479912316A9EF003FCCF9 /* Items */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
D2755D7A23689C7500485468 /* TableViewCell.swift */,
|
||||||
01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */,
|
01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */,
|
||||||
D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */,
|
D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */,
|
||||||
D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */,
|
D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */,
|
||||||
@ -582,7 +585,6 @@
|
|||||||
D29DF10E21E67A77003B2FB9 /* Molecules */ = {
|
D29DF10E21E67A77003B2FB9 /* Molecules */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */,
|
|
||||||
D22479912316A9EF003FCCF9 /* Items */,
|
D22479912316A9EF003FCCF9 /* Items */,
|
||||||
D224798F2316A99F003FCCF9 /* LeftRightViews */,
|
D224798F2316A99F003FCCF9 /* LeftRightViews */,
|
||||||
D224798E2316A995003FCCF9 /* HorizontalCombinationViews */,
|
D224798E2316A995003FCCF9 /* HorizontalCombinationViews */,
|
||||||
@ -598,6 +600,7 @@
|
|||||||
D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */,
|
D29B770F22C281F400D6ACE0 /* ModuleMolecule.swift */,
|
||||||
D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */,
|
D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */,
|
||||||
0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */,
|
0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */,
|
||||||
|
017BEB372360C6AC0024EF95 /* RadioButtonLabel.swift */,
|
||||||
);
|
);
|
||||||
path = Molecules;
|
path = Molecules;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -1087,6 +1090,7 @@
|
|||||||
D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */,
|
D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */,
|
||||||
D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */,
|
D29DF2A221E7AF4E003B2FB9 /* MVMCoreUIUtility.m in Sources */,
|
||||||
D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */,
|
D29DF12B21E6851E003B2FB9 /* MVMCoreUITopAlertExpandableView.m in Sources */,
|
||||||
|
D2755D7B23689C7500485468 /* TableViewCell.swift in Sources */,
|
||||||
0A21DB85235E06EF00C160A2 /* MFTextField.m in Sources */,
|
0A21DB85235E06EF00C160A2 /* MFTextField.m in Sources */,
|
||||||
B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */,
|
B8200E152280C4CF007245F4 /* ProgressBar.swift in Sources */,
|
||||||
D29DF25421E6A177003B2FB9 /* MFMdnTextField.m in Sources */,
|
D29DF25421E6A177003B2FB9 /* MFMdnTextField.m in Sources */,
|
||||||
|
|||||||
@ -64,7 +64,7 @@ import UIKit
|
|||||||
primaryButton?.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
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
|
return 42
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -138,7 +138,7 @@ open class CaretButton: MFCustomButton, MVMCoreUIMoleculeViewProtocol, MVMCoreUI
|
|||||||
return UIStackView.Alignment.leading;
|
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
|
return 10
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -266,7 +266,7 @@ public typealias ActionBlock = () -> ()
|
|||||||
let length = attribute["length"] as? Int
|
let length = attribute["length"] as? Int
|
||||||
else { continue }
|
else { continue }
|
||||||
|
|
||||||
var range = NSRange(location: location, length: length)
|
let range = NSRange(location: location, length: length)
|
||||||
|
|
||||||
switch attributeType {
|
switch attributeType {
|
||||||
case "underline":
|
case "underline":
|
||||||
@ -278,17 +278,7 @@ public typealias ActionBlock = () -> ()
|
|||||||
|
|
||||||
case "color":
|
case "color":
|
||||||
if let colorHex = attribute.optionalStringForKey(KeyTextColor), !colorHex.isEmpty {
|
if let colorHex = attribute.optionalStringForKey(KeyTextColor), !colorHex.isEmpty {
|
||||||
// crash fix: removing attribute, even though it does not exists
|
attributedString.removeAttribute(.foregroundColor, range: range)
|
||||||
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.addAttribute(.foregroundColor, value: UIColor.mfGet(forHex: colorHex), range: range)
|
attributedString.addAttribute(.foregroundColor, value: UIColor.mfGet(forHex: colorHex), range: range)
|
||||||
}
|
}
|
||||||
case "image":
|
case "image":
|
||||||
@ -310,28 +300,8 @@ public typealias ActionBlock = () -> ()
|
|||||||
case "font":
|
case "font":
|
||||||
if let fontStyle = attribute.optionalStringForKey("style") {
|
if let fontStyle = attribute.optionalStringForKey("style") {
|
||||||
let styles = MFStyler.styleGetAttributedString("0", withStyle: fontStyle)
|
let styles = MFStyler.styleGetAttributedString("0", withStyle: fontStyle)
|
||||||
// crash fix: removing font attribute, even though it does not exists
|
attributedString.removeAttribute(.font, range: range)
|
||||||
let fontAttributesArray = attributedString.attributes(at: location, effectiveRange: &range).filter { (attribute) -> Bool in
|
attributedString.removeAttribute(.foregroundColor, range: range)
|
||||||
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.addAttributes(styles.attributes(at: 0, effectiveRange: nil), range: range)
|
attributedString.addAttributes(styles.attributes(at: 0, effectiveRange: nil), range: range)
|
||||||
} else {
|
} else {
|
||||||
let fontSize = attribute["size"] as? CGFloat
|
let fontSize = attribute["size"] as? CGFloat
|
||||||
@ -344,17 +314,7 @@ public typealias ActionBlock = () -> ()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let font = font {
|
if let font = font {
|
||||||
// crash fix: removing font attribute, even though it does not exists
|
attributedString.removeAttribute(.font, range: range)
|
||||||
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.addAttribute(.font, value: font, range: range)
|
attributedString.addAttribute(.font, value: font, range: range)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -215,7 +215,7 @@ import UIKit
|
|||||||
pinEdges(.all)
|
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
|
return json?.optionalCGFloatForKey("height") ?? 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -145,7 +145,8 @@ const CGFloat SwitchShakeIntensity = 2;
|
|||||||
|
|
||||||
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
|
- (void)setWithJSON:(NSDictionary *)json delegateObject:(MVMCoreUIDelegateObject *)delegateObject additionalData:(NSDictionary *)additionalData {
|
||||||
self.json = json;
|
self.json = json;
|
||||||
|
self.delegate = delegateObject;
|
||||||
|
|
||||||
[FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol];
|
[FormValidator setupValidationWithMolecule:self delegate:delegateObject.formValidationProtocol];
|
||||||
|
|
||||||
NSString *color = [json string:@"onTintColor"];
|
NSString *color = [json string:@"onTintColor"];
|
||||||
@ -169,8 +170,7 @@ const CGFloat SwitchShakeIntensity = 2;
|
|||||||
}
|
}
|
||||||
|
|
||||||
[self setState:[json boolForKey:@"state"] animated:false];
|
[self setState:[json boolForKey:@"state"] animated:false];
|
||||||
|
|
||||||
self.delegate = delegateObject;
|
|
||||||
NSDictionary *actionMap = [json dict:@"actionMap"];
|
NSDictionary *actionMap = [json dict:@"actionMap"];
|
||||||
if (actionMap) {
|
if (actionMap) {
|
||||||
[self addTarget:self action:@selector(addCustomAction) forControlEvents:UIControlEventTouchUpInside];
|
[self addTarget:self action:@selector(addCustomAction) forControlEvents:UIControlEventTouchUpInside];
|
||||||
|
|||||||
@ -73,7 +73,7 @@ import Foundation
|
|||||||
trackTintColor = UIColor.mfLightSilver()
|
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
|
return 8
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,47 +8,46 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
public class View: UIView {
|
@objcMembers open class View: UIView {
|
||||||
var json: [AnyHashable: Any]?
|
open var json: [AnyHashable: Any]?
|
||||||
|
|
||||||
private var initialSetupPerformed = false
|
private var initialSetupPerformed = false
|
||||||
|
|
||||||
public override init(frame: CGRect) {
|
public override init(frame: CGRect) {
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
initialSetup()
|
initialSetup()
|
||||||
}
|
}
|
||||||
|
|
||||||
init() {
|
public init() {
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
initialSetup()
|
initialSetup()
|
||||||
}
|
}
|
||||||
|
|
||||||
public required init?(coder: NSCoder) {
|
public required init?(coder: NSCoder) {
|
||||||
super.init(coder: coder)
|
super.init(coder: coder)
|
||||||
initialSetup()
|
initialSetup()
|
||||||
}
|
}
|
||||||
|
|
||||||
public func initialSetup() {
|
public func initialSetup() {
|
||||||
if !initialSetupPerformed {
|
if !initialSetupPerformed {
|
||||||
initialSetupPerformed = true
|
initialSetupPerformed = true
|
||||||
setupView()
|
setupView()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
extension View: MVMCoreViewProtocol {
|
extension View: MVMCoreViewProtocol {
|
||||||
public func updateView(_ size: CGFloat) {
|
open func updateView(_ size: CGFloat) {}
|
||||||
}
|
|
||||||
|
|
||||||
/// Will be called only once.
|
/// Will be called only once.
|
||||||
public func setupView() {
|
open func setupView() {
|
||||||
translatesAutoresizingMaskIntoConstraints = false
|
translatesAutoresizingMaskIntoConstraints = false
|
||||||
insetsLayoutMarginsFromSafeArea = false
|
insetsLayoutMarginsFromSafeArea = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension View: MVMCoreUIMoleculeViewProtocol {
|
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
|
self.json = json
|
||||||
|
|
||||||
if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) {
|
if let backgroundColorString = json?.optionalStringForKey(KeyBackgroundColor) {
|
||||||
@ -56,7 +55,7 @@ extension View: MVMCoreUIMoleculeViewProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func reset() {
|
open func reset() {
|
||||||
backgroundColor = .clear
|
backgroundColor = .clear
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -61,11 +61,6 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController {
|
|||||||
return nil
|
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.
|
/// can override to return a minimum fill space.
|
||||||
open func minimumFillSpace() -> CGFloat {
|
open func minimumFillSpace() -> CGFloat {
|
||||||
return 0
|
return 0
|
||||||
@ -159,7 +154,7 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController {
|
|||||||
bottomViewTopConstraint?.isActive = true
|
bottomViewTopConstraint?.isActive = true
|
||||||
bottomView.leftAnchor.constraint(equalTo: footerView.leftAnchor).isActive = true
|
bottomView.leftAnchor.constraint(equalTo: footerView.leftAnchor).isActive = true
|
||||||
footerView.rightAnchor.constraint(equalTo: bottomView.rightAnchor).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
|
self.footerView = footerView
|
||||||
showFooter(nil)
|
showFooter(nil)
|
||||||
}
|
}
|
||||||
@ -219,14 +214,16 @@ open class ThreeLayerTableViewController: MFProgrammaticTableViewController {
|
|||||||
/// Subclass for a top view.
|
/// Subclass for a top view.
|
||||||
open func viewForTop() -> UIView {
|
open func viewForTop() -> UIView {
|
||||||
let view = MVMCoreUICommonViewsUtility.commonView()
|
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
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Subclass for a bottom view.
|
/// Subclass for a bottom view.
|
||||||
open func viewForBottom() -> UIView {
|
open func viewForBottom() -> UIView {
|
||||||
|
// Default spacing is standard when no buttons.
|
||||||
let view = MVMCoreUICommonViewsUtility.commonView()
|
let view = MVMCoreUICommonViewsUtility.commonView()
|
||||||
view.heightAnchor.constraint(equalToConstant: 0).isActive = true
|
view.heightAnchor.constraint(equalToConstant: PaddingDefaultVerticalSpacing).isActive = true
|
||||||
return view
|
return view
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -91,7 +91,7 @@ import UIKit
|
|||||||
imageLoader.updateView(size)
|
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
|
return 197
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -82,7 +82,7 @@ import UIKit
|
|||||||
imageView.reset()
|
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
|
return 95
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -115,7 +115,7 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MVMCoreUIMoleculeVi
|
|||||||
backgroundColor = .white
|
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 {
|
guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,227 +8,24 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@objcMembers open class MoleculeTableViewCell: UITableViewCell, MVMCoreUIMoleculeViewProtocol, MoleculeListCellProtocol {
|
@objcMembers open class MoleculeTableViewCell: TableViewCell {
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - MVMCoreUIMoleculeViewProtocol
|
// MARK: - MVMCoreUIMoleculeViewProtocol
|
||||||
public func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
public override func setWithJSON(_ json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
self.json = json
|
super.setWithJSON(json, delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
|
||||||
style(with: json?.optionalStringForKey("style"))
|
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)
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func reset() {
|
public override class func estimatedHeight(forRow json: [AnyHashable: Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||||
molecule?.reset?()
|
|
||||||
updateViewHorizontalDefaults = true
|
|
||||||
styleStandard()
|
|
||||||
backgroundColor = .white
|
|
||||||
}
|
|
||||||
|
|
||||||
public static 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 {
|
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) else {
|
||||||
return 80
|
return 80
|
||||||
}
|
}
|
||||||
return max(2 * PaddingDefaultVerticalSpacing3, height)
|
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 {
|
guard let molecule = molecule?.optionalDictionaryForKey(KeyMolecule) else {
|
||||||
return "\(self)<>"
|
return "\(self)<>"
|
||||||
}
|
}
|
||||||
@ -236,87 +33,11 @@ import UIKit
|
|||||||
return "\(self)<\(moleculeName)>"
|
return "\(self)<\(moleculeName)>"
|
||||||
}
|
}
|
||||||
|
|
||||||
public static func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
public class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||||
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule),
|
guard let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule),
|
||||||
let theClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON) else {
|
let theClass = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return theClass.requiredModules?(moleculeJSON, delegateObject: delegateObject, error: error)
|
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
314
MVMCoreUI/Molecules/Items/TableViewCell.swift
Normal file
314
MVMCoreUI/Molecules/Items/TableViewCell.swift
Normal file
@ -0,0 +1,314 @@
|
|||||||
|
//
|
||||||
|
// 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, 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.
|
||||||
|
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
|
||||||
|
case allExceptTop
|
||||||
|
case allExceptBottom
|
||||||
|
case 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
|
||||||
|
|
||||||
|
guard let json = json else { return }
|
||||||
|
|
||||||
|
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 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()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import UIKit
|
import UIKit
|
||||||
|
|
||||||
@objcMembers public class TabsTableViewCell: MoleculeTableViewCell {
|
@objcMembers public class TabsTableViewCell: TableViewCell {
|
||||||
let tabs = TopTabbar(frame: .zero)
|
let tabs = TopTabbar(frame: .zero)
|
||||||
var delegateObject: MVMCoreUIDelegateObject?
|
var delegateObject: MVMCoreUIDelegateObject?
|
||||||
var previousTabIndex = 0
|
var previousTabIndex = 0
|
||||||
|
|||||||
@ -174,7 +174,7 @@ import UIKit
|
|||||||
bottomRightLabel.styleB3(true)
|
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
|
return 34
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,7 +19,7 @@ import UIKit
|
|||||||
mvmSwitch.updateView(size)
|
mvmSwitch.updateView(size)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func setupView() {
|
open override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
guard mvmSwitch.superview == nil else {
|
guard mvmSwitch.superview == nil else {
|
||||||
return
|
return
|
||||||
@ -41,18 +41,18 @@ import UIKit
|
|||||||
mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData)
|
mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData)
|
||||||
}
|
}
|
||||||
|
|
||||||
public override static func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
open override class func estimatedHeight(forRow json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?) -> CGFloat {
|
||||||
return 30
|
return 30
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func setAsMolecule() {
|
open override func setAsMolecule() {
|
||||||
super.setAsMolecule()
|
super.setAsMolecule()
|
||||||
headlineBody.setAsMolecule()
|
headlineBody.setAsMolecule()
|
||||||
(mvmSwitch as MVMCoreUIMoleculeViewProtocol).setAsMolecule?()
|
(mvmSwitch as MVMCoreUIMoleculeViewProtocol).setAsMolecule?()
|
||||||
headlineBody.styleListItem()
|
headlineBody.styleListItem()
|
||||||
}
|
}
|
||||||
|
|
||||||
public override func reset() {
|
open override func reset() {
|
||||||
super.reset()
|
super.reset()
|
||||||
headlineBody.reset()
|
headlineBody.reset()
|
||||||
(mvmSwitch as MVMCoreUIMoleculeViewProtocol).reset?()
|
(mvmSwitch as MVMCoreUIMoleculeViewProtocol).reset?()
|
||||||
|
|||||||
@ -41,7 +41,7 @@ import UIKit
|
|||||||
mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData)
|
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)
|
return HeadlineBodyTextButton.estimatedHeight(forRow: json, delegateObject: delegateObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -41,7 +41,7 @@ import UIKit
|
|||||||
mvmSwitch.setWithJSON(json?.optionalDictionaryForKey("switch"), delegateObject: delegateObject, additionalData: additionalData)
|
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)
|
return MVMCoreUISwitch.estimatedHeight(forRow: json, delegateObject: delegateObject)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -54,7 +54,7 @@ open class ModuleMolecule: ViewConstrainingView {
|
|||||||
moduleMolecule?.reset?()
|
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 {
|
guard let moduleName = json?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else {
|
||||||
// Critical error
|
// Critical error
|
||||||
return 0
|
return 0
|
||||||
@ -62,7 +62,7 @@ open class ModuleMolecule: ViewConstrainingView {
|
|||||||
return MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: module)?.estimatedHeight?(forRow: module, delegateObject: delegateObject) ?? 0
|
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 {
|
guard let moduleName = molecule?.optionalStringForKey("moduleName"), let module = delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) else {
|
||||||
// Critical error
|
// Critical error
|
||||||
return "moduleMolecule<>"
|
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)) + ">"
|
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<MVMCoreErrorObject?>?) -> [String]? {
|
public override class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||||
let moduleName = json?.optionalStringForKey("moduleName")
|
let moduleName = json?.optionalStringForKey("moduleName")
|
||||||
if moduleName == nil || delegateObject?.moleculeDelegate?.getModuleWithName(moduleName) == nil {
|
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)) {
|
if let errorObject = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess), code: CoreUIErrorCode.ErrorCodeModuleMolecule.rawValue, domain: ErrorDomainNative, location: String(describing: self)) {
|
||||||
|
|||||||
@ -26,7 +26,7 @@ open class StandardFooterView: ViewConstrainingView {
|
|||||||
(molecule as? MVMCoreUIViewConstrainingProtocol)?.shouldSetVerticalMargins?(false)
|
(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) {
|
if let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) {
|
||||||
return height + PaddingDefaultVerticalSpacing + PaddingDefaultVerticalSpacing
|
return height + PaddingDefaultVerticalSpacing + PaddingDefaultVerticalSpacing
|
||||||
}
|
}
|
||||||
|
|||||||
@ -62,7 +62,7 @@ public class StandardHeaderView: ViewConstrainingView {
|
|||||||
separatorView?.show()
|
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) {
|
if let moleculeJSON = json?.optionalDictionaryForKey(KeyMolecule), let height = MVMCoreUIMoleculeMappingObject.shared()?.getMoleculeClass(withJSON: moleculeJSON)?.estimatedHeight?(forRow: moleculeJSON, delegateObject: delegateObject) {
|
||||||
return height + PaddingDefaultVerticalSpacing + PaddingDefaultVerticalSpacing
|
return height + PaddingDefaultVerticalSpacing + PaddingDefaultVerticalSpacing
|
||||||
}
|
}
|
||||||
|
|||||||
@ -64,7 +64,7 @@ import UIKit
|
|||||||
body.styleB2(true)
|
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
|
return 65
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -136,7 +136,7 @@ open class HeadlineBody: ViewConstrainingView {
|
|||||||
stylePageHeader()
|
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
|
return 58
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -76,7 +76,7 @@ import UIKit
|
|||||||
textButton.reset()
|
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
|
return 60
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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.
|
// This will aggregate names of molecules to make an id.
|
||||||
guard let molecules = molecule?.optionalArrayForKey(KeyMolecules) else {
|
guard let molecules = molecule?.optionalArrayForKey(KeyMolecules) else {
|
||||||
return "stack<>"
|
return "stack<>"
|
||||||
@ -199,7 +199,7 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
return name
|
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 {
|
guard let items = json?.optionalArrayForKey(KeyMolecules) else {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@ -221,7 +221,7 @@ public class MoleculeStackView: ViewConstrainingView {
|
|||||||
return estimatedHeight
|
return estimatedHeight
|
||||||
}
|
}
|
||||||
|
|
||||||
public override static func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
public override class func requiredModules(_ json: [AnyHashable : Any]?, delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer<MVMCoreErrorObject?>?) -> [String]? {
|
||||||
guard let items = json?.optionalArrayForKey(KeyMolecules) else {
|
guard let items = json?.optionalArrayForKey(KeyMolecules) else {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,11 +42,6 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
|
|||||||
return molecule
|
return molecule
|
||||||
}
|
}
|
||||||
|
|
||||||
// for bottom gutter/free space
|
|
||||||
open override func spaceBelowBottomView() -> CGFloat? {
|
|
||||||
return PaddingDefaultVerticalSpacing
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func newDataBuildScreen() {
|
open override func newDataBuildScreen() {
|
||||||
super.newDataBuildScreen()
|
super.newDataBuildScreen()
|
||||||
setup()
|
setup()
|
||||||
@ -131,7 +126,7 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
|
|||||||
open override func addMolecules(_ molecules: [[AnyHashable : Any]], sender: UITableViewCell, animation: UITableView.RowAnimation) {
|
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.
|
// This dispatch is needed to fix a race condition that can occur if this function is called during the table setup.
|
||||||
DispatchQueue.main.async {
|
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] = []
|
var indexPaths: [IndexPath] = []
|
||||||
for molecule in molecules {
|
for molecule in molecules {
|
||||||
if let info = self.getMoleculeInfo(with: molecule) {
|
if let info = self.getMoleculeInfo(with: molecule) {
|
||||||
@ -158,23 +153,6 @@ open class MoleculeListTemplate: ThreeLayerTableViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.tableView?.deleteRows(at: indexPaths, with: animation)
|
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.updateViewConstraints()
|
||||||
self.view.layoutIfNeeded()
|
self.view.layoutIfNeeded()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,7 @@ static const CGFloat VertialShadowOffset = 6;
|
|||||||
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
UIView *view = [[UIView alloc] initWithFrame:CGRectZero];
|
||||||
view.translatesAutoresizingMaskIntoConstraints = NO;
|
view.translatesAutoresizingMaskIntoConstraints = NO;
|
||||||
view.backgroundColor = [UIColor clearColor];
|
view.backgroundColor = [UIColor clearColor];
|
||||||
|
view.directionalLayoutMargins = NSDirectionalEdgeInsetsZero;
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user