From 25e0651eee8f20cc51f9fd2e5a888d0229db52e6 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 11 Mar 2020 12:07:20 -0400 Subject: [PATCH 01/62] images and links and stuff --- .../Atoms/Buttons/Link/ExternalLink.swift | 6 +++--- MVMCoreUI/Atoms/Views/Label/Label.swift | 19 +++++++------------ 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/MVMCoreUI/Atoms/Buttons/Link/ExternalLink.swift b/MVMCoreUI/Atoms/Buttons/Link/ExternalLink.swift index 3cd601b6..c311b435 100644 --- a/MVMCoreUI/Atoms/Buttons/Link/ExternalLink.swift +++ b/MVMCoreUI/Atoms/Buttons/Link/ExternalLink.swift @@ -47,11 +47,11 @@ open class ExternalLink: Link { trailingAnchor.constraint(greaterThanOrEqualTo: exportIcon.trailingAnchor).isActive = true if let titleLabel = titleLabel { - let dimension = round(0.6 * titleLabel.font.pointSize) + let dimension = titleLabel.font.pointSize exportIcon.heightAnchor.constraint(equalToConstant: dimension).isActive = true exportIcon.widthAnchor.constraint(equalToConstant: dimension).isActive = true - exportIcon.leadingAnchor.constraint(equalTo: titleLabel.trailingAnchor, constant: PaddingOne).isActive = true - exportIcon.bottomAnchor.constraint(equalTo: titleLabel.lastBaselineAnchor).isActive = true + exportIcon.leadingAnchor.constraint(equalTo: titleLabel.trailingAnchor, constant: 4).isActive = true + exportIcon.bottomAnchor.constraint(equalTo: titleLabel.lastBaselineAnchor, constant: 3).isActive = true } } } diff --git a/MVMCoreUI/Atoms/Views/Label/Label.swift b/MVMCoreUI/Atoms/Views/Label/Label.swift index c7e72204..3a7d1f93 100644 --- a/MVMCoreUI/Atoms/Views/Label/Label.swift +++ b/MVMCoreUI/Atoms/Views/Label/Label.swift @@ -755,7 +755,7 @@ public typealias ActionBlock = () -> () */ static func getTextAttachmentImage(name: String = "externalLink", dimension: CGFloat) -> NSTextAttachment { - let dimension = round(dimension * 0.8) +// let dimension = round(dimension * 0.8) let imageAttachment = NSTextAttachment() imageAttachment.image = MVMCoreUIUtility.imageNamed(name) @@ -766,23 +766,18 @@ public typealias ActionBlock = () -> () static func getTextAttachmentFrom(url: String, dimension: CGFloat, label: Label) -> NSTextAttachment { - let dimension = round(dimension * 0.8) - let imageAttachment = NSTextAttachment() imageAttachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension) DispatchQueue.global(qos: .default).async { - - guard let url = URL(string: url), - let data = try? Data(contentsOf: url) - else { return } - - DispatchQueue.main.sync { - imageAttachment.image = UIImage(data: data) - label.setNeedsDisplay() + MVMCoreCache.shared()?.getImage(url, useWidth: false, widthForS7: 0, useHeight: false, heightForS7: 0, localFallbackImageName: nil) { image, data, _ in + + DispatchQueue.main.sync { + imageAttachment.image = image + label.setNeedsDisplay() + } } } - return imageAttachment } From f750fd129ca607e034577862b10b6af59ec812c8 Mon Sep 17 00:00:00 2001 From: Kruthika KP <> Date: Mon, 23 Mar 2020 11:19:40 +0530 Subject: [PATCH 02/62] MF-19186 : List -Three Column - Data Usage - Divider - Initial Commit --- MVMCoreUI.xcodeproj/project.pbxproj | 8 +++ .../ListThreeColumnDataUsageDivider.swift | 61 +++++++++++++++++++ ...ListThreeColumnDataUsageDividerModel.swift | 51 ++++++++++++++++ .../OtherHandlers/MoleculeObjectMapping.swift | 1 + 4 files changed, 121 insertions(+) create mode 100644 MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift create mode 100644 MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDividerModel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index f17d7906..1887955b 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -131,6 +131,8 @@ 8D070BB2241B56AD0099AC56 /* ListRightVariableTotalData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */; }; 8D084AD02410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */; }; 8D084AD22410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D084AD12410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift */; }; + 8D21E4B924247D1600ACAF24 /* ListThreeColumnDataUsageDividerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D21E4B824247D1600ACAF24 /* ListThreeColumnDataUsageDividerModel.swift */; }; + 8D21E4BB2424887800ACAF24 /* ListThreeColumnDataUsageDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D21E4BA2424887800ACAF24 /* ListThreeColumnDataUsageDivider.swift */; }; 8D24041123E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D24041023E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift */; }; 8D24041523E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D24041423E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift */; }; 8D448E5524050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D448E5424050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift */; }; @@ -516,6 +518,8 @@ 8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableTotalData.swift; sourceTree = ""; }; 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextBodyTextModel.swift; sourceTree = ""; }; 8D084AD12410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextBodyText.swift; sourceTree = ""; }; + 8D21E4B824247D1600ACAF24 /* ListThreeColumnDataUsageDividerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnDataUsageDividerModel.swift; sourceTree = ""; }; + 8D21E4BA2424887800ACAF24 /* ListThreeColumnDataUsageDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnDataUsageDivider.swift; sourceTree = ""; }; 8D24041023E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconWithRightCaret.swift; sourceTree = ""; }; 8D24041423E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconWithRightCaretModel.swift; sourceTree = ""; }; 8D448E5424050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextAllTextAndLinksModel.swift; sourceTree = ""; }; @@ -1227,6 +1231,8 @@ children = ( 5248BFEB23F12E350059236A /* ListThreeColumnPlanDataDividerModel.swift */, 5248BFEA23F12E350059236A /* ListThreeColumnPlanDataDivider.swift */, + 8D21E4B824247D1600ACAF24 /* ListThreeColumnDataUsageDividerModel.swift */, + 8D21E4BA2424887800ACAF24 /* ListThreeColumnDataUsageDivider.swift */, ); path = ThreeColumn; sourceTree = ""; @@ -1890,6 +1896,7 @@ D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */, 0116A4E5228B19640094F3ED /* RadioButtonSelectionHelper.swift in Sources */, 017BEB48236230DB0024EF95 /* MoleculeViewProtocol.swift in Sources */, + 8D21E4B924247D1600ACAF24 /* ListThreeColumnDataUsageDividerModel.swift in Sources */, D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */, D27CD40E2322EEAF00C1DC07 /* TabsTableViewCell.swift in Sources */, D224799B231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift in Sources */, @@ -1983,6 +1990,7 @@ D28A838323CCBD3F00DFE4FC /* CircleProgressModel.swift in Sources */, D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */, DBEFFA04225A829700230692 /* Label.swift in Sources */, + 8D21E4BB2424887800ACAF24 /* ListThreeColumnDataUsageDivider.swift in Sources */, D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */, 0A7EF85F23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift in Sources */, 011D959B240451E3000E3791 /* RuleRequiredModel.swift in Sources */, diff --git a/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift new file mode 100644 index 00000000..c4944e3e --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift @@ -0,0 +1,61 @@ +// +// ListThreeColumnDataUsageDivider.swift +// MVMCoreUI +// +// Created by Kruthika KP on 20/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers open class ListThreeColumnDataUsageDivider: TableViewCell { + + //----------------------------------------------------- + // MARK: - Outlets + //------------------------------------------------------- + public let leftLabel = Label.createLabelBoldBodySmall(true) + public let centerLabel = Label.createLabelBoldBodySmall(true) + public let rightLabel = Label.createLabelBoldBodySmall(true) + var stack: Stack + + //------------------------------------------------------ + // MARK: - Initializers + //------------------------------------------------------ + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + stack = Stack.createStack(with: [(view: leftLabel, model: StackItemModel(percent: 33, horizontalAlignment: .leading)), + (view: centerLabel, model: StackItemModel(percent: 33, horizontalAlignment: .center)), + (view: rightLabel, model: StackItemModel(percent: 34, horizontalAlignment: .center))], + axis: .horizontal) + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open override func setupView() { + super.setupView() + addMolecule(stack) + stack.restack() + } + + // MARK: - ModelMoleculeViewProtocol + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListThreeColumnDataUsageDividerModel else { return } + leftLabel.set(with: model.leftLabel, delegateObject, additionalData) + centerLabel.set(with: model.centerLabel, delegateObject, additionalData) + rightLabel.set(with: model.rightLabel, delegateObject, additionalData) + } + + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return 121 + } + + open override func reset() { + super.reset() + leftLabel.styleBoldBodySmall(true) + centerLabel.styleBoldBodySmall(true) + rightLabel.styleBoldBodySmall(true) + } +} diff --git a/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDividerModel.swift b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDividerModel.swift new file mode 100644 index 00000000..f57bdf01 --- /dev/null +++ b/MVMCoreUI/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDividerModel.swift @@ -0,0 +1,51 @@ +// +// ListThreeColumnDataUsageDividerModel.swift +// MVMCoreUI +// +// Created by Kruthika KP on 20/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class ListThreeColumnDataUsageDividerModel: ListItemModel, MoleculeModelProtocol { + public static var identifier: String = "list3CDataUsgDiv" + public let leftLabel: LabelModel + public let centerLabel: LabelModel + public let rightLabel: LabelModel + + public init(leftLabel: LabelModel, centerLabel: LabelModel, rightLabel: LabelModel) { + self.leftLabel = leftLabel + self.centerLabel = centerLabel + self.rightLabel = rightLabel + super.init() + } + + override public func setDefaults() { + super.setDefaults() + style = "tallDivider" + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case leftLabel + case centerLabel + case rightLabel + } + + required init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + leftLabel = try typeContainer.decode(LabelModel.self, forKey: .leftLabel) + centerLabel = try typeContainer.decode(LabelModel.self, forKey: .centerLabel) + rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel) + try super.init(from:decoder) + } + + public override func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(leftLabel, forKey: .leftLabel) + try container.encode(centerLabel, forKey: .centerLabel) + try container.encode(rightLabel, forKey: .rightLabel) + } +} diff --git a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift index f2bf9e78..a33e298e 100644 --- a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift +++ b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift @@ -117,6 +117,7 @@ import Foundation MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListOneColumnTextWithWhitespaceDividerShort.self, viewModelClass: ListOneColumnTextWithWhitespaceDividerShortModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListOneColumnTextWithWhitespaceDividerTall.self, viewModelClass: ListOneColumnTextWithWhitespaceDividerTallModel.self) MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListOneColumnFullWidthTextDividerSubsection.self, viewModelClass: ListOneColumnFullWidthTextDividerSubsectionModel.self) + MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListThreeColumnDataUsageDivider.self, viewModelClass: ListThreeColumnDataUsageDividerModel.self) // Designed Headers MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: HeadersH2NoButtonsBodyText.self, viewModelClass: HeadersH2NoButtonsBodyTextModel.self) From 29465f82815c76c51d5704e538e80cecd7d7517a Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 1 Apr 2020 14:18:51 -0400 Subject: [PATCH 03/62] refresh styler --- MVMCoreUI.xcodeproj/project.pbxproj | 4 + MVMCoreUI/Styles/Styler.swift | 1207 +++++++++++++++++++++++++++ 2 files changed, 1211 insertions(+) create mode 100644 MVMCoreUI/Styles/Styler.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 7ae72de5..3f13e17b 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -87,6 +87,7 @@ 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */; }; 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */; }; + 0A6682AA2435125F00AD3CA1 /* Styler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682A92435125F00AD3CA1 /* Styler.swift */; }; 0A69F611241BDEA700F7231B /* RuleAnyRequiredModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */; }; 0A6BF4722360C56C0028F841 /* BaseDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */; }; 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; }; @@ -472,6 +473,7 @@ 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.swift"; sourceTree = ""; }; 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = ""; }; 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesProtocol.swift; sourceTree = ""; }; + 0A6682A92435125F00AD3CA1 /* Styler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Styler.swift; sourceTree = ""; }; 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyRequiredModel.swift; sourceTree = ""; }; 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseDropdownEntryField.swift; sourceTree = ""; }; 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = ""; }; @@ -1466,6 +1468,7 @@ children = ( D29DF13821E68636003B2FB9 /* MFStyler.h */, D29DF13921E68637003B2FB9 /* MFStyler.m */, + 0A6682A92435125F00AD3CA1 /* Styler.swift */, ); path = Styles; sourceTree = ""; @@ -2210,6 +2213,7 @@ 011D95AD2406BB57000E3791 /* FormHolderProtocol.swift in Sources */, 01509D932327ECFB00EF99AA /* ProgressBar.swift in Sources */, D260106523D0CEA700764D80 /* StackModel.swift in Sources */, + 0A6682AA2435125F00AD3CA1 /* Styler.swift in Sources */, D29770F521F7C6D600B2F0D0 /* TopLabelsAndBottomButtonsViewController.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift new file mode 100644 index 00000000..f5b90149 --- /dev/null +++ b/MVMCoreUI/Styles/Styler.swift @@ -0,0 +1,1207 @@ +// +// Styler.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 4/1/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation +import MVMCore + +public protocol VogueProtocol { + +} + +public protocol VogueViewProtocol { + +} + +public protocol VogueTextProtocol: VogueProtocol { + func styleFont(_ font: UIFont) + func styleTextColor(_ textColor: UIColor) +} + + +struct Padding { + + static let One: CGFloat = 6 + static let Two: CGFloat = 12 + static let Three: CGFloat = 18 + static let Four: CGFloat = 24 + static let Five: CGFloat = 30 + static let Six: CGFloat = 36 + static let Seven: CGFloat = 42 + static let Eight: CGFloat = 48 + static let Nine: CGFloat = 54 + static let Ten: CGFloat = 60 + + static let TableCellParagraphSpace: CGFloat = 3 + static let FooterLabelParagraphSpace: CGFloat = 4 + static let WebViewInset: CGFloat = 8 + static let HeightTableSeperatorHeight: CGFloat = 1 + static let MFHeightForSwitch: CGFloat = 22 + static let MFWidthForSwitch: CGFloat = 42 + static let DisableOppacity: CGFloat = 0.5 + static let PaymentMethodViewHeightWidthMultiplier: CGFloat = 0.55 + static let MinCellHeight: CGFloat = 96 + static let HeightIphone5: CGFloat = 568 + static let DefaultOptionCellHeight: CGFloat = 120 + static let PromoViewHeight: CGFloat = 41.9 + static let BetweenFields: CGFloat = 24 + static let LabelWithInternalButtonLineSpace: CGFloat = 2 + static let PrimaryButtonTop: CGFloat = 36 + + struct Default { + static let Standard: CGFloat = 24 + static let HorizontalSpacing: CGFloat = 32 + static let VerticalSpacing: CGFloat = 32 + static let VerticalSpacing3: CGFloat = 24 + } + + struct Horizontal { + static let HeadlineWhiteView: CGFloat = 60 + static let Large: CGFloat = 72 + static let BetweenRelatedItems: CGFloat = 16 + } + + struct Vertical { + static let WhiteGrayView: CGFloat = 72 + static let HeadlineAlternate: CGFloat = 48 + } +} + + +public class Styler { + + enum MFViewBorder: Int { + case top + case left + case bottom + case right + } + + enum MFTimeFormatUnit: Int { + case mfTimeFormatColon = 0 //!{days} : {hour} : {minutes} : {seconds} + case mfTimeFormatNormal = 1 // will end with days hours minutes seconds, when left days less than 2, it will change to 'day' + } + + //-------------------------------------------------- + // MARK: - Enum + //-------------------------------------------------- + + public enum Style: String { + case H1 + case H2 + case H3 + case H32 + case B1 + case B2 + case B3 + case B20 + + func font(_ genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 0 + + switch self { + case .H1: + size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 40 + return MFFonts.mfFont75Bd(size) + + case .H2: + size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 25 + return MFFonts.mfFont75Bd(size) + + case .H3: + size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 18 + return MFFonts.mfFont75Bd(size) + + case .H32: + size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 32 + return MFFonts.mfFont75Bd(size) + + case .B1: + size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 13 + return MFFonts.mfFont75Bd(size) + + case .B2: + size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 13 + return MFFonts.mfFont55Rg(size) + + case .B3: + size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 11 + return MFFonts.mfFont55Rg(size) + + case .B20: + size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 20 + return MFFonts.mfFont55Rg(size) + } + } + } + + public enum Tier { + case primary + case secondary + case ternary + case quaternary + } + + //-------------------------------------------------- + // MARK: - Functions + //-------------------------------------------------- + + class func splitTextFieldWidth() -> CGFloat { + return splitTextFieldWidth(forViewWidth: MVMCoreUISplitViewController.getDetailViewWidth()) + } + + class func splitTextFieldWidth(forViewWidth width: CGFloat) -> CGFloat { + return (width - CGFloat(PaddingOne)) / 2 - defaultHorizontalPaddingForApplicationWidth() + } + + class func sizeObjectGeneric(forCurrentDevice size: CGFloat) -> MFSizeObject? { + + let sizeObject = MFSizeObject(standardSize: size, standardiPadPortraitSize: size * 1.3) + sizeObject?.addLargerThanCustomSize(size * 1.4, forThreshold: MFSizeStandardiPadLandscapeThreshold) + sizeObject?.addLargerThanCustomSize(size * 1.5, forThreshold: MFSizeiPadProLandscapeThreshold) + return sizeObject + } + + class func sizeFontGeneric(forCurrentDevice size: CGFloat) -> CGFloat { + return sizeObjectGeneric(forCurrentDevice: size)?.getValueBasedOnApplicationWidth() ?? 0 + } + + //-------------------------------------------------- + // MARK: - Spacing + //-------------------------------------------------- + + class func defaultHorizontalPaddingForApplicationWidth() -> CGFloat { + return MFSizeObject(scalingStandardSize: PaddingDefaultHorizontalSpacing)?.getValueBasedOnApplicationWidth() ?? 0 + } + + class func defaultVerticalPaddingForApplicationWidth() -> CGFloat { + return MFSizeObject(scalingStandardSize: PaddingDefaultVerticalSpacing)?.getValueBasedOnApplicationWidth() ?? 0 + } + + class func defaultHorizontalPadding(forSize size: CGFloat) -> CGFloat { + return MFSizeObject(scalingStandardSize: PaddingDefaultHorizontalSpacing)?.getValueBased(onSize: size) ?? 0 + } + + class func defaultVerticalPadding(forSize size: CGFloat) -> CGFloat { + return MFSizeObject(scalingStandardSize: PaddingDefaultVerticalSpacing)?.getValueBased(onSize: size) ?? 0 + } + + class func setDefaultMarginsFor(_ view: UIView?, size: CGFloat) { + setDefaultMarginsFor(view, size: size, horizontal: true, vertical: false) + } + + class func setDefaultMarginsFor(_ view: UIView?, size: CGFloat, horizontal: Bool, vertical: Bool) { + + let horizontalPadding: CGFloat = horizontal ? defaultHorizontalPadding(forSize: size) : 0 + let verticalPadding: CGFloat = vertical ? PaddingDefaultVerticalSpacing3 : 0 + + DispatchQueue.main.async { + MVMCoreUIUtility.setMarginsFor(view, leading: horizontalPadding, top: verticalPadding, trailing: horizontalPadding, bottom: verticalPadding) + } + } + + class func setMarginsFor(_ view: UIView?, size: CGFloat, defaultHorizontal horizontal: Bool, top: CGFloat, bottom: CGFloat) { + + let horizontalPadding: CGFloat = horizontal ? defaultHorizontalPadding(forSize: size) : 0 + + DispatchQueue.main.async { + MVMCoreUIUtility.setMarginsFor(view, leading: horizontalPadding, top: top, trailing: horizontalPadding, bottom: bottom) + } + } + + //-------------------------------------------------- + // MARK: - Fonts + //-------------------------------------------------- + + class func fontH1(_ genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 40 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func fontH2(_ genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 25 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func fontH3(_ genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 18 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func fontH32(_ genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 32 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func fontB1(_ genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 13 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func fontB2(_ genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 13 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont55Rg(size) + } + + class func fontB3(_ genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 11 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont55Rg(size) + } + + class func fontB20(_ genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 20 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont55Rg(size) + } + + //-------------------------------------------------- + // MARK: - Styles + //-------------------------------------------------- + + class func styleLabel(_ label: VogueTextProtocol, withStyle style: Style, genericScaling: Bool) { + + switch style { + case .H1: + styleLabelH1(label, genericScaling: genericScaling) + + case .H2: + styleLabelH2(label, genericScaling: genericScaling) + + case .H3: + styleLabelH3(label, genericScaling: genericScaling) + + case .H32: + styleLabelH32(label, genericScaling: genericScaling) + + case .B1: + styleLabelB1(label, genericScaling: genericScaling) + + case .B2: + styleLabelB2(label, genericScaling: genericScaling) + + case .B3: + styleLabelB3(label, genericScaling: genericScaling) + + case .B20: + styleLabelB20(label, genericScaling: genericScaling) + } + } + + class func styleLabel(_ label: UILabel, withStyle style: Style) { + styleLabel(label, withStyle: style, genericScaling: true) + } + + class func styleLabelH1(_ label: VogueTextProtocol, genericScaling: Bool = true) { + + label.styleTextColor(.black) + + if let h1 = fontH1(genericScaling) { + label.styleFont(h1) + } + } + + class func styleLabelH2(_ label: VogueTextProtocol, genericScaling: Bool = true) { + + label.styleTextColor(.black) + + if let h2 = fontH2(genericScaling) { + label.styleFont(h2) + } + } + + class func styleLabelH3(_ label: VogueTextProtocol, genericScaling: Bool = true) { + + label.styleTextColor(.black) + + if let h3 = fontH3(genericScaling) { + label.styleFont(h3) + } + } + + class func styleLabelH32(_ label: VogueTextProtocol, genericScaling: Bool = true) { + + label.styleTextColor(.black) + + if let h32 = fontH32(genericScaling) { + label.styleFont(h32) + } + } + + class func styleLabelB1(_ label: VogueTextProtocol, genericScaling: Bool = true) { + + label.styleTextColor(.black) + + if let b1 = fontB1(genericScaling) { + label.styleFont(b1) + } + } + + class func styleLabelB2(_ label: VogueTextProtocol, genericScaling: Bool = true) { + + label.styleTextColor(.black) + + if let b2 = fontB2(genericScaling) { + label.styleFont(b2) + } + } + + class func styleLabelB2(_ label: UILabel, size: CGFloat, genericScaling: Bool = true) { + label.font = fontForBody(withSize: size, genericScaling: genericScaling) + } + + class func styleLabelB3(_ label: VogueTextProtocol, genericScaling: Bool = true) { + + label.styleTextColor(.mfBackgroundGray()) + + if let b3 = fontB3(genericScaling) { + label.styleFont(b3) + } + } + + class func styleLabelB20(_ label: VogueTextProtocol, genericScaling: Bool = true) { + + label.styleTextColor(.black) + + if let b20 = fontB20(genericScaling) { + label.styleFont(b20) + } + } + + class func styleLabelTextStyle2(_ label: VogueTextProtocol, genericScaling: Bool = true) { + + label.styleTextColor(.mfBattleshipGrey()) + + if let b2 = fontB2(genericScaling) { + label.styleFont(b2) + } + } + + class func fontForBody(withSize size: CGFloat, genericScaling: Bool) -> UIFont? { + + var size = size + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont55Rg(size) + } + + class func fontForBody(withSize size: CGFloat, forWidth width: CGFloat) -> UIFont? { + + let size = sizeObjectGeneric(forCurrentDevice: size)?.getValueBased(onSize: width) ?? size + + return MFFonts.mfFont55Rg(size) + } + + //-------------------------------------------------- + // MARK: - 1.0 Fonts + //-------------------------------------------------- + + class func font(forPlan genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 100 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func font(forBiggerHeadLine genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 48 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func font(forHeadlineSmall genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 15 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func font(forHeadlineSmall2 genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 16 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func fontForHeadlineSmall2(forWidth size: CGFloat) -> UIFont? { + + var pointSize: CGFloat = 16 + pointSize = Styler.sizeObjectGeneric(forCurrentDevice: pointSize)!.getValueBased(onSize: size) + + return MFFonts.mfFont75Bd(pointSize) + } + + class func fontB1(forWidth size: CGFloat) -> UIFont? { + + var pointSize: CGFloat = 13 + pointSize = Styler.sizeObjectGeneric(forCurrentDevice: pointSize)!.getValueBased(onSize: size) + + return MFFonts.mfFont75Bd(pointSize) + } + + //-------------------------------------------------- + // MARK: - 1.0 Styles + //-------------------------------------------------- + + class func styleFeedCardTitleLabel(_ label: UILabel) { + + label.font = Styler.fontForFeedCardTitle() + label.textColor = .black + } + + class func styleFeedCardTagLabel(_ label: UILabel) { + + label.font = Styler.fontB3() + label.textColor = .mfBrownishGrey() + } + + class func styleStandardSeparatorView(_ view: UIView) { + + view.backgroundColor = .mfBackgroundGray() + } + + class func styleLabelHeadlineSmall(_ label: UILabel, genericScaling: Bool) { + + label.font = Styler.font(forHeadlineSmall: genericScaling) + label.textColor = .black + } + + class func styleFeedCardTitleLabel(_ label: UILabel, genericScaling: Bool) { + + label.font = Styler.font(forFeedCardTitle: genericScaling) + label.textColor = UIColor.black + } + + class func styleFeedCardTagLabel(_ label: UILabel, genericScaling: Bool) { + + label.font = Styler.fontB3(genericScaling) + label.textColor = UIColor.mfBrownishGrey() + } + + class func fontB2(forWidth size: CGFloat) -> UIFont? { + + var pointSize: CGFloat = 13 + + pointSize = Styler.sizeObjectGeneric(forCurrentDevice: pointSize)!.getValueBased(onSize: size) + + return MFFonts.mfFont55Rg(pointSize) + } + + class func fontforChatText(_ genericScaling: Bool = false) -> UIFont? { + + var size: CGFloat = 14 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont55Rg(size) + } + + class func font(forAccountLandingGreeting genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 16 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont55Rg(size) + } + + class func font(forProgressBarBottomLabel genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 10 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont55Rg(size) + } + + class func font(forFeedCardTitle genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 16 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func font(forPrimaryButton genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 14 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func fontForPrimaryButton(forWidth size: CGFloat) -> UIFont? { + + var pointSize: CGFloat = 14 + pointSize = Styler.sizeObjectGeneric(forCurrentDevice: pointSize)!.getValueBased(onSize: size) + return MFFonts.mfFont75Bd(pointSize) + } + + class func font(forSmallButton genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 11 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func fontForSmallButton(forWidth size: CGFloat) -> UIFont? { + + var pointSize: CGFloat = 11 + pointSize = Styler.sizeObjectGeneric(forCurrentDevice: pointSize)!.getValueBased(onSize: size) + + return MFFonts.mfFont75Bd(pointSize) + } + + class func font(forTextField genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 16 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont55Rg(size) + } + + class func font(forTextFieldUnderLabel genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 12 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont55Rg(size) + } + + class func fontForUnreadMessage(onSupport genericScaling: Bool = false) -> UIFont? { + + var size: CGFloat = 10 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func font5GMessage(_ genericScaling: Bool) -> UIFont? { + + var size: CGFloat = 16 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont55Rg(size) + } + + class func font5GMessage() -> UIFont? { + return font5GMessage(true) + } + + class func font(forHeadlineAlternative genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 24 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont55Rg(size) + } + + class func fontForHeadlineAlternative(forWidth size: CGFloat) -> UIFont? { + + var pointSize: CGFloat = 24 + pointSize = Styler.sizeObjectGeneric(forCurrentDevice: pointSize)!.getValueBased(onSize: size) + + return MFFonts.mfFont55Rg(pointSize) + } + + class func fontH255(_ genericScaling: Bool) -> UIFont? { + + var size: CGFloat = 25 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont55Rg(size) + } + + class func font(forLargeLoyaltyHeaderTitle genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 60 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func font(forLoyaltyTitleSmall genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 42 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func font(forLoyaltyMessage genericScaling: Bool = true) -> UIFont? { + + var size: CGFloat = 20 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont55Rg(size) + } + + class func font(forPtPCard genericScaling: Bool) -> UIFont? { + + var size: CGFloat = 22 + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func fontForLabelWithTopLeftCircle(withSize size: CGFloat, genericScaling: Bool) -> UIFont? { + + var size = size + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFont75Bd(size) + } + + class func fontOcratxtWitSize(_ size: CGFloat, genericScaling: Bool) -> UIFont? { + + var size = size + + if genericScaling { + size = sizeFontGeneric(forCurrentDevice: size) + } + + return MFFonts.mfFontOcratxt(size) + } + + class func boldFont(forScaledSize size: CGFloat) -> UIFont { + return MFFonts.mfFont75Bd(sizeFontGeneric(forCurrentDevice: size))! + } + + class func regularFont(forScaledSize size: CGFloat) -> UIFont { + return MFFonts.mfFont55Rg(sizeFontGeneric(forCurrentDevice: size))! + } + + //-------------------------------------------------- + // MARK: - 1.0 Attributed Strings Style + //-------------------------------------------------- + + class func styleGetAttributedString(_ string: String?, withStyle style: String?) -> NSAttributedString { + return styleGetAttributedString(string, withStyle: Styler.Style(rawValue: style!)!, genericScaling: true) + } + + class func styleGetAttributedString(_ string: String?, withStyle style: Style, genericScaling: Bool) -> NSAttributedString { + + switch style { + case .H1: + return styleGetH1AttributedString(string, genericScaling: genericScaling) + + case .H2: + return styleGetH2AttributedString(string, genericScaling: genericScaling) + + case .H3: + return styleGetH3AttributedString(string, genericScaling: genericScaling) + + case .H32: + return styleGetH32AttributedString(string, genericScaling: genericScaling) + + case .B1: + return styleGetB1AttributedString(string, genericScaling: genericScaling) + + case .B2: + return styleGetB2AttributedString(string, genericScaling: genericScaling) + + case .B3: + return styleGetB3AttributedString(string, genericScaling: genericScaling) + + case .B20: + return styleGetB20AttributedString(string, genericScaling: genericScaling) + } + } + + class func styleGetAttributedString(_ string: String?, font: UIFont, color: UIColor) -> NSAttributedString { + + var attributedString: NSAttributedString? = nil + + if let string = string, !string.isEmpty { + attributedString = NSAttributedString(string: string, attributes: [NSAttributedString.Key.font: font, + NSAttributedString.Key.foregroundColor: color]) + } else { + attributedString = NSAttributedString(string: "") + } + + return attributedString! + } + + class func styleGetH1AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { + return styleGetAttributedString(string, font: fontH1(genericScaling)!, color: .black) + } + + class func styleGetH2AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { + return styleGetAttributedString(string, font: fontH2(genericScaling)!, color: .black) + } + + class func styleGetH3AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { + return styleGetAttributedString(string, font: fontH3(genericScaling)!, color: .black) + } + + class func styleGetH32AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { + return styleGetAttributedString(string, font: fontH32(genericScaling)!, color: .black) + } + + class func styleGetB1AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { + return styleGetAttributedString(string, font: fontB1(genericScaling)!, color: .black) + } + + class func styleGetB2AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { + return styleGetAttributedString(string, font: fontB2(genericScaling)!, color: .black) + } + + class func styleGetB3AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { + return styleGetAttributedString(string, font: fontB3(genericScaling)!, color: .mfBattleshipGrey()) + } + + class func styleGetB20AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { + return styleGetAttributedString(string, font: fontB20(genericScaling)!, color: .black) + } + + class func styleGetTopAlignedAttributeString(withLeftStringRightTop left: String?, center: String, rightString right: String?, withCenterStringFontSize fontSize: CGFloat, andColor color: UIColor) -> NSAttributedString { + + var left = left ?? "" + var center = center + var right = right ?? "" + + let text = "\(left)\(center)\(right)" + let attribs = [NSAttributedString.Key.foregroundColor: color] + var attributedText = NSMutableAttributedString(string: text, attributes: attribs) + + let centerRange = (text as NSString).range(of: center) + let centerFont = MFFonts.mfFont75Bd(fontSize) + let centerHeight = centerFont?.capHeight ?? 0.0 + attributedText.addAttributes([NSAttributedString.Key.font: MFFonts.mfFont75Bd(fontSize) as Any], range: centerRange) + + let leftRange = (text as NSString).range(of: left) + let leftFont = MFFonts.mfFont75Bd(fontSize * 0.34) + let leftHeight = leftFont?.capHeight ?? 0.0 + + if let leftFont = leftFont { + attributedText.addAttributes([NSAttributedString.Key.font: leftFont, + NSAttributedString.Key.baselineOffset: NSNumber(value: Float(centerHeight - leftHeight))], range: leftRange) + } + + let rightRange = NSRange(location: centerRange.location + centerRange.length, length: right.count ) + let rightFont = MFFonts.mfFont75Bd(fontSize * 0.34) + + let offset = Float((centerFont?.pointSize ?? 0.0) - (centerFont?.capHeight ?? 0.0) + (rightFont?.pointSize ?? 0.0) / 2) + + if let rightFont = rightFont { + attributedText.addAttributes([NSAttributedString.Key.font: rightFont, + NSAttributedString.Key.baselineOffset: offset], + range: rightRange) + } + + return attributedText + } + + class func styleGetAlignCenteredAttrituedString(_ string: inout NSMutableAttributedString?) { + + if let string = string, string.length > 0 { + let paragraphStyle = NSMutableParagraphStyle() + paragraphStyle.alignment = .center + string.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: string.length)) + } + } + + class func styleGetBoldString(with inputFont: UIFont?, from inputString: String?) -> NSAttributedString? { + + let openingRange = (inputString as NSString?)?.range(of: "{") + let closingRange = (inputString as NSString?)?.range(of: "}") + let attrString = NSMutableAttributedString(string: inputString ?? "") + + if openingRange?.location != NSNotFound && closingRange?.location != NSNotFound { + let boldLength = (closingRange?.location ?? 0) - (openingRange?.location ?? 0) + if let inputFont = inputFont { + attrString.setAttributes([NSAttributedString.Key.font: inputFont], range: NSRange(location: openingRange?.location ?? 0, length: boldLength)) + } + + if let closingRange = closingRange { + attrString.replaceCharacters(in: closingRange, with: "") + } + + if let openingRange = openingRange { + attrString.replaceCharacters(in: openingRange, with: "") + } + } + + return attrString + } + + //-------------------------------------------------- + // MARK: - Gradient Colors + //-------------------------------------------------- + + class func gradientSpecialTicketGold() -> [AnyHashable] { + return [UIColor(red: 0.72, green: 0.6, blue: 0.33, alpha: 1), + UIColor(red: 1, green: 0.85, blue: 0.52, alpha: 1), + UIColor(red: 1, green: 0.85, blue: 0.52, alpha: 1), + UIColor(red: 1, green: 0.85, blue: 0.52, alpha: 1), + UIColor(red: 0.6, green: 0.42, blue: 0.07, alpha: 1)] + } + + class func gradientSpecialTicketGoldCGColor() -> [AnyHashable] { + return [UIColor(red: 0.72, green: 0.6, blue: 0.33, alpha: 1).cgColor, + UIColor(red: 1, green: 0.85, blue: 0.52, alpha: 1).cgColor, + UIColor(red: 1, green: 0.85, blue: 0.52, alpha: 1).cgColor, + UIColor(red: 1, green: 0.85, blue: 0.52, alpha: 1).cgColor, + UIColor(red: 0.6, green: 0.42, blue: 0.07, alpha: 1).cgColor].compactMap { $0 } + } + + class func styleGetLowCaseSpace(_ inputString: String?) -> String? { + + if (inputString?.count ?? 0) > 0 { + let trimmedString = inputString?.lowercased().trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) + return trimmedString + } + + return "" + } + + class func labelStrokeAttributes(_ color: UIColor?) -> [AnyHashable : Any]? { + + guard let color = color else { return nil } + + return [NSAttributedString.Key.strokeColor: color, + NSAttributedString.Key.strokeWidth: -1.0] + } + + class func mfStyleBlackPageControl(_ pageControl: UIPageControl?) { + + pageControl?.pageIndicatorTintColor = .mfLighterGray() + pageControl?.currentPageIndicatorTintColor = .black + } + + //-------------------------------------------------- + // MARK: - Custom Styling Views + //-------------------------------------------------- + + class func styleView(_ view: UIView, show border: MFViewBorder, with color: UIColor?, borderLineWidth: CGFloat, borderLineLength borderLineLengh: CGFloat) { + + let borderLine = UIView(frame: .zero) + borderLine.translatesAutoresizingMaskIntoConstraints = false + view.addSubview(borderLine) + + switch border { + case .top: + NSLayoutConstraint.constraintPinSubview(borderLine, pinTop: true, pinBottom: false, pinLeft: false, pinRight: false) + NSLayoutConstraint.constraintPinView(borderLine, heightConstraint: true, heightConstant: borderLineWidth, widthConstraint: true, widthConstant: borderLineLengh) + NSLayoutConstraint.constraintPinSubview(borderLine, pinCenterX: true, pinCenterY: false) + + case .left: + NSLayoutConstraint.constraintPinSubview(borderLine, pinTop: false, pinBottom: false, pinLeft: true, pinRight: false) + NSLayoutConstraint.constraintPinView(borderLine, heightConstraint: true, heightConstant: borderLineLengh, widthConstraint: true, widthConstant: borderLineWidth) + NSLayoutConstraint.constraintPinSubview(borderLine, pinCenterX: false, pinCenterY: true) + + case .bottom: + NSLayoutConstraint.constraintPinSubview(borderLine, pinTop: false, pinBottom: true, pinLeft: false, pinRight: false) + NSLayoutConstraint.constraintPinView(borderLine, heightConstraint: true, heightConstant: borderLineWidth, widthConstraint: true, widthConstant: borderLineLengh) + NSLayoutConstraint.constraintPinSubview(borderLine, pinCenterX: true, pinCenterY: false) + + case .right: + NSLayoutConstraint.constraintPinSubview(borderLine, pinTop: false, pinBottom: false, pinLeft: false, pinRight: true) + NSLayoutConstraint.constraintPinView(borderLine, heightConstraint: true, heightConstant: borderLineLengh, widthConstraint: true, widthConstant: borderLineWidth) + NSLayoutConstraint.constraintPinSubview(borderLine, pinCenterX: false, pinCenterY: true) + + default: + break + } + + borderLine.backgroundColor = color + } + + class func mfStylePageControl(_ pageControl: UIPageControl?) { + + pageControl?.pageIndicatorTintColor = .mfLighterGray() + pageControl?.currentPageIndicatorTintColor = .mfRed() + } + + class func styleTextField(_ textField: UITextField) { + + textField.font = fontForTextField() + // As per AKQA + /* If the length of the text field exceeds the amount of space, the size of the text drops down. + So, the entire line of copy can be read. + 16 point font size is the lowest recommended size. + */ + textField.minimumFontSize = 16 + textField.adjustsFontSizeToFitWidth = true // default is NO. if YES, text will shrink to minFontSize along baseline + } + /* + class func setGradientTo(_ label: UILabel, withColors colors: [AnyHashable]) { + + var textSize: CGSize? = nil + + if let font = UIFont(name: label.font.fontName, size: label.font.lineHeight) { + textSize = label.text?.size(withAttributes: [NSAttributedString.Key.baselineOffset: 0, + NSAttributedString.Key.font: font]) + } + + let width = (textSize?.width ?? 0.0) > 1024 ? 1024 : textSize?.width ?? 0.0 // max 1024 due to Core Graphics limitations + let height = (textSize?.height ?? 0.0) > 1024 ? 1024 : textSize?.height ?? 0.0 // max 1024 due to Core Graphics limitations + + // create a new bitmap image context + UIGraphicsBeginImageContext(CGSize(width: width, height: height)) + + let context = UIGraphicsGetCurrentContext() + + // push context to make it current (need to do this manually because we are not drawing in a UIView) + if let context = context { + UIGraphicsPushContext(context) + } + + var glossGradient: CGGradient? + var rgbColorspace: CGColorSpace? + let num_locations = colors.count + var locations = [CGFloat](repeating: 0.0, count: colors.count) + let components = [CGFloat](repeating: 0.0, count: colors.count * 4) + var componentIndex = 0 + + for i in 0.. UIImage? { + + UIGraphicsBeginImageContextWithOptions(image?.size ?? CGSize.zero, _: true, _: 1.0) + let imageRect = CGRect(x: 0, y: 0, width: image?.size.width ?? 0.0, height: image?.size.height ?? 0.0) + + // Draw the image with the luminosity blend mode. + // On top of a white background, this will give a black and white image. + image?.draw(in: imageRect, blendMode: .luminosity, alpha: 1.0) + + // Get the resulting image. + let filteredImage = UIGraphicsGetImageFromCurrentImageContext() + UIGraphicsEndImageContext() + + return filteredImage + } + /* + class func getCountTime(_ leftTime: Int, timeformat timeFormat: String?, time timeUnit: MFTimeFormatUnit, timeSuffix suffix: String?) -> String? { + + var seconds = leftTime % 60 + var minutes = (leftTime / 60) % 60 + var hours = (leftTime / 3600) % 24 + let days = leftTime / 86400 + + guard let times = timeFormat?.components(separatedBy: ":") else { return nil } + var timeString = "" + + if times.contains("DD") { + timeString += String(format: "%02ld", days) + + if timeUnit == .mfTimeFormatNormal { + let dayKey = (days <= 1) ? "CountDownDay" : "CountDownDays" + let dayUnit = MVMCoreUIUtility.hardcodedString(withKey: dayKey) + timeString += dayUnit! + + } else if timeUnit == MFTimeFormatColon && times?.last != "DD" { + timeString += " : " + } + + if times.last != "DD" && suffix != nil { + timeString += suffix ?? "" + } + } + + if times.contains("HH") { + if !times.contains("DD") { + hours = leftTime / 3600 + } + + timeString += String(format: "%02d", hours) + + if timeUnit == .mfTimeFormatNormal { + let hourKey = (hours <= 1) ? "CountDownHour" : "CountDownHours" + let hourUnit = MVMCoreUIUtility.hardcodedString(withKey: hourKey)! + timeString += hourUnit + + } else if timeUnit == MFTimeFormatColon && times?.last != "HH" { + timeString += " : " + } + + if times.last != "HH" && suffix != nil { + timeString += suffix ?? "" + } + } + + if times.contains("MM") { + if !times.contains("HH") { + if !times.contains("DD") { + minutes = leftTime / 60 + } else { + minutes = (leftTime - days * 86400) / 60 + } + } + + timeString += String(format: "%02d", minutes) + + if times.contains("SS") { + if !times.contains("MM") { + if !times.contains("HH") { + if !times.contains("DD") { + seconds = leftTime + } else { + seconds = leftTime % 86400 + } + } else { + seconds = leftTime % 3600 + } + } + + timeString += String(format: "%02d", seconds) + + if timeUnit == .mfTimeFormatNormal { + let secondKey = (seconds <= 1) ? "CountDownSec" : "CountDownSecs" + let secondUnit = MVMCoreUIUtility.hardcodedString(withKey: secondKey) + timeString += secondUnit! + } + } + return timeString + } + } + */ +} From 1957f4d354a6bf6cb8d31764edc5a0a1942fbe38 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 1 Apr 2020 14:47:47 -0400 Subject: [PATCH 04/62] pulling in new changes --- MVMCoreUI/Styles/Styler.swift | 318 ++++++++++++++++++++++++++++++++++ 1 file changed, 318 insertions(+) diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift index f5b90149..0a38e6f0 100644 --- a/MVMCoreUI/Styles/Styler.swift +++ b/MVMCoreUI/Styles/Styler.swift @@ -214,6 +214,170 @@ public class Styler { } } + //-------------------------------------------------- + // MARK: - 3.0 fonts + //-------------------------------------------------- + + class func getMVA3FontSize(_ size: CGFloat, bold isBold: Bool) -> UIFont { + if isBold { + if size >= 15 { + return MFFonts.mfFontDSBold(size) + } else { + return MFFonts.mfFontTXBold(size) + } + } else { + if size >= 15 { + return MFFonts.mfFontDSRegular(size) + } else { + return MFFonts.mfFontTXRegular(size) + } + } + } + + class func fontTitle2XLarge(_ genericScaling: Bool) -> UIFont { + var size: CGFloat = 36 + if genericScaling { + size = self.sizeFontGeneric(forCurrentDevice: size) + } + return self.getMVA3FontSize(size, bold: true) + } + + class func fontTitle2XLarge() -> UIFont { + return self.fontTitle2XLarge(true) + } + + class func fontTitleXLarge(_ genericScaling: Bool) -> UIFont { + var size: CGFloat = 32 + if genericScaling { + size = self.sizeFontGeneric(forCurrentDevice: size) + } + return self.getMVA3FontSize(size, bold: true) + } + + class func fontTitleXLarge() -> UIFont { + return self.fontTitleXLarge(true) + } + + class func fontBoldTitleLarge(_ genericScaling: Bool) -> UIFont { + var size: CGFloat = 24 + if genericScaling { + size = self.sizeFontGeneric(forCurrentDevice: size) + } + return self.getMVA3FontSize(size, bold: true) + } + + class func fontBoldTitleLarge() -> UIFont { + return self.fontBoldTitleLarge(true) + } + + class func fontRegularTitleLarge(_ genericScaling: Bool) -> UIFont { + var size: CGFloat = 24 + if genericScaling { + size = self.sizeFontGeneric(forCurrentDevice: size) + } + return self.getMVA3FontSize(size, bold: false) + } + + class func fontRegularTitleLarge() -> UIFont { + return self.fontRegularTitleLarge(true) + } + + class func fontBoldTitleMedium(_ genericScaling: Bool) -> UIFont { + var size: CGFloat = 20 + if genericScaling { + size = self.sizeFontGeneric(forCurrentDevice: size) + } + return self.getMVA3FontSize(size, bold: true) + } + + class func fontBoldTitleMedium() -> UIFont { + return self.fontBoldTitleMedium(true) + } + + class func fontRegularTitleMedium(_ genericScaling: Bool) -> UIFont { + var size: CGFloat = 20 + if genericScaling { + size = self.sizeFontGeneric(forCurrentDevice: size) + } + return self.getMVA3FontSize(size, bold: false) + } + + class func fontRegularTitleMedium() -> UIFont { + return self.fontRegularTitleMedium(true) + } + + class func fontBoldBodyLarge(_ genericScaling: Bool) -> UIFont { + var size: CGFloat = 16 + if genericScaling { + size = self.sizeFontGeneric(forCurrentDevice: size) + } + return self.getMVA3FontSize(size, bold: true) + } + + class func fontBoldBodyLarge() -> UIFont { + return self.fontBoldBodyLarge(true) + } + + class func fontRegularBodyLarge(_ genericScaling: Bool) -> UIFont { + var size: CGFloat = 16 + if genericScaling { + size = self.sizeFontGeneric(forCurrentDevice: size) + } + return self.getMVA3FontSize(size, bold: false) + } + + class func fontRegularBodyLarge() -> UIFont { + return self.fontRegularBodyLarge(true) + } + + class func fontBoldBodySmall(_ genericScaling: Bool) -> UIFont { + var size: CGFloat = 13 + if genericScaling { + size = self.sizeFontGeneric(forCurrentDevice: size) + } + return self.getMVA3FontSize(size, bold: true) + } + + class func fontBoldBodySmall() -> UIFont { + return self.fontBoldBodySmall(true) + } + + class func fontRegularBodySmall(_ genericScaling: Bool) -> UIFont { + var size: CGFloat = 13 + if genericScaling { + size = self.sizeFontGeneric(forCurrentDevice: size) + } + return self.getMVA3FontSize(size, bold: false) + } + + class func fontRegularBodySmall() -> UIFont { + return self.fontRegularBodySmall(true) + } + + class func fontBoldMicro(_ genericScaling: Bool) -> UIFont { + var size: CGFloat = 11 + if genericScaling { + size = self.sizeFontGeneric(forCurrentDevice: size) + } + return self.getMVA3FontSize(size, bold: true) + } + + class func fontBoldMicro() -> UIFont { + return self.fontBoldMicro(true) + } + + class func fontRegularMicro(_ genericScaling: Bool) -> UIFont { + var size: CGFloat = 11 + if genericScaling { + size = self.sizeFontGeneric(forCurrentDevice: size) + } + return self.getMVA3FontSize(size, bold: false) + } + + class func fontRegularMicro() -> UIFont { + return self.fontRegularMicro(true) + } + //-------------------------------------------------- // MARK: - Fonts //-------------------------------------------------- @@ -306,6 +470,160 @@ public class Styler { return MFFonts.mfFont55Rg(size) } + //-------------------------------------------------- + // MARK: - 3.0 Styles + //-------------------------------------------------- + + class func styleLabelTitle2XLarge(_ label: UILabel, genericScaling: Bool) { + label.font = MFStyler.fontTitle2XLarge(genericScaling) + label.textColor = UIColor.black + } + + class func styleLabelTitle2XLarge(_ label: UILabel) { + self.styleLabelTitle2XLarge(label, genericScaling: true) + } + + class func styleLabelTitleXLarge(_ label: UILabel, genericScaling: Bool) { + label.font = MFStyler.fontTitleXLarge(genericScaling) + label.textColor = UIColor.black + } + + class func styleLabelTitleXLarge(_ label: UILabel) { + self.styleLabelTitleXLarge(label, genericScaling: true) + } + + class func styleLabelBoldTitleLarge(_ label: UILabel, genericScaling: Bool) { + label.font = MFStyler.fontBoldTitleLarge(genericScaling) + label.textColor = UIColor.black + } + + class func styleLabelBoldTitleLarge(_ label: UILabel) { + self.styleLabelBoldTitleLarge(label, genericScaling: true) + } + + class func styleLabelRegularTitleLarge(_ label: UILabel, genericScaling: Bool) { + label.font = MFStyler.fontRegularTitleLarge(genericScaling) + label.textColor = UIColor.black + } + + class func styleLabelRegularTitleLarge(_ label: UILabel) { + self.styleLabelBoldTitleLarge(label, genericScaling: true) + } + + class func styleLabelBoldTitleMedium(_ label: UILabel, genericScaling: Bool) { + label.font = MFStyler.fontBoldTitleMedium(genericScaling) + label.textColor = UIColor.black + } + + class func styleLabelBoldTitleMedium(_ label: UILabel) { + self.styleLabelBoldTitleMedium(label, genericScaling: true) + } + + class func styleLabelRegularTitleMedium(_ label: UILabel, genericScaling: Bool) { + label.font = MFStyler.fontRegularTitleMedium(genericScaling) + label.textColor = UIColor.black + } + + class func styleLabelRegularTitleMedium(_ label: UILabel) { + self.styleLabelRegularTitleMedium(label, genericScaling: true) + } + + class func styleLabelBoldBodyLarge(_ label: UILabel, genericScaling: Bool) { + label.font = MFStyler.fontBoldBodyLarge(genericScaling) + label.textColor = UIColor.black + } + + class func styleLabelBoldBodyLarge(_ label: UILabel) { + self.styleLabelBoldBodyLarge(label, genericScaling: true) + } + + class func styleLabelRegularBodyLarge(_ label: UILabel, genericScaling: Bool) { + label.font = MFStyler.fontRegularBodyLarge(genericScaling) + label.textColor = UIColor.black + } + + class func styleLabelRegularBodyLarge(_ label: UILabel) { + self.styleLabelRegularBodyLarge(label, genericScaling: true) + } + + class func styleLabelBoldBodySmall(_ label: UILabel, genericScaling: Bool) { + label.font = MFStyler.fontBoldBodySmall(genericScaling) + label.textColor = UIColor.black + } + + class func styleLabelBoldBodySmall(_ label: UILabel) { + self.styleLabelBoldBodySmall(label, genericScaling: true) + } + + class func styleLabelRegularBodySmall(_ label: UILabel, genericScaling: Bool) { + label.font = MFStyler.fontRegularBodySmall(genericScaling) + label.textColor = UIColor.black + } + + class func styleLabelRegularBodySmall(_ label: UILabel) { + self.styleLabelRegularBodySmall(label, genericScaling: true) + } + + class func styleLabelBoldMicro(_ label: UILabel, genericScaling: Bool) { + label.font = MFStyler.fontBoldMicro(genericScaling) + label.textColor = UIColor.black + } + + class func styleLabelBoldMicro(_ label: UILabel) { + self.styleLabelBoldMicro(label, genericScaling: true) + } + + class func styleLabelRegularMicro(_ label: UILabel, genericScaling: Bool) { + label.font = MFStyler.fontRegularMicro(genericScaling) + label.textColor = UIColor.black + } + + class func styleLabelRegularMicro(_ label: UILabel) { + self.styleLabelRegularMicro(label, genericScaling: true) + } + + class func styleMVA3Label(_ label: UILabel, withStyle style: String?, genericScaling: Bool) -> Bool { + if (style == "Title2XLarge") { + self.styleLabelTitle2XLarge(label, genericScaling: genericScaling) + return true + } else if (style == "TitleXLarge") { + self.styleLabelTitleXLarge(label, genericScaling: genericScaling) + return true + } else if (style == "BoldTitleLarge") { + self.styleLabelBoldTitleLarge(label, genericScaling: genericScaling) + return true + } else if (style == "RegularTitleLarge") { + self.styleLabelRegularTitleLarge(label, genericScaling: genericScaling) + return true + } else if (style == "BoldTitleMedium") { + self.styleLabelBoldTitleMedium(label, genericScaling: genericScaling) + return true + } else if (style == "RegularTitleMedium") { + self.styleLabelRegularTitleMedium(label, genericScaling: genericScaling) + return true + } else if (style == "BoldBodyLarge") { + self.styleLabelBoldBodyLarge(label, genericScaling: genericScaling) + return true + } else if (style == "RegularBodyLarge") { + self.styleLabelRegularBodyLarge(label, genericScaling: genericScaling) + return true + } else if (style == "BoldBodySmall") { + self.styleLabelBoldBodySmall(label, genericScaling: genericScaling) + return true + } else if (style == "RegularBodySmall") { + self.styleLabelRegularBodySmall(label, genericScaling: genericScaling) + return true + } else if (style == "BoldMicro") { + self.styleLabelBoldMicro(label, genericScaling: genericScaling) + return true + } else if (style == "RegularMicro") { + self.styleLabelRegularMicro(label, genericScaling: genericScaling) + return true + } else { + return false + } + } + //-------------------------------------------------- // MARK: - Styles //-------------------------------------------------- From a8e411472fe65c1208a9b474abb75d62f72eea49 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 1 Apr 2020 16:40:58 -0400 Subject: [PATCH 05/62] dramatic alteration --- MVMCoreUI.xcodeproj/project.pbxproj | 4 + MVMCoreUI/Styles/Padding.swift | 74 ++ MVMCoreUI/Styles/Styler.swift | 1407 ++------------------------- 3 files changed, 169 insertions(+), 1316 deletions(-) create mode 100644 MVMCoreUI/Styles/Padding.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 3f13e17b..ddb3307c 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -88,6 +88,7 @@ 0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */; }; 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */; }; 0A6682AA2435125F00AD3CA1 /* Styler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682A92435125F00AD3CA1 /* Styler.swift */; }; + 0A6682AC243531C300AD3CA1 /* Padding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682AB243531C300AD3CA1 /* Padding.swift */; }; 0A69F611241BDEA700F7231B /* RuleAnyRequiredModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */; }; 0A6BF4722360C56C0028F841 /* BaseDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */; }; 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; }; @@ -474,6 +475,7 @@ 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = ""; }; 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesProtocol.swift; sourceTree = ""; }; 0A6682A92435125F00AD3CA1 /* Styler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Styler.swift; sourceTree = ""; }; + 0A6682AB243531C300AD3CA1 /* Padding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Padding.swift; sourceTree = ""; }; 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyRequiredModel.swift; sourceTree = ""; }; 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseDropdownEntryField.swift; sourceTree = ""; }; 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = ""; }; @@ -1469,6 +1471,7 @@ D29DF13821E68636003B2FB9 /* MFStyler.h */, D29DF13921E68637003B2FB9 /* MFStyler.m */, 0A6682A92435125F00AD3CA1 /* Styler.swift */, + 0A6682AB243531C300AD3CA1 /* Padding.swift */, ); path = Styles; sourceTree = ""; @@ -2051,6 +2054,7 @@ 0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */, D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */, 01EB368F23609801006832FA /* LabelModel.swift in Sources */, + 0A6682AC243531C300AD3CA1 /* Padding.swift in Sources */, 942C378E2412F5B60066E45E /* ModalMoleculeStackTemplate.swift in Sources */, 8D4687E4242E2DF300802879 /* ListFourColumnDataUsageListItem.swift in Sources */, 01F2A03223A4498200D954D8 /* CaretLinkModel.swift in Sources */, diff --git a/MVMCoreUI/Styles/Padding.swift b/MVMCoreUI/Styles/Padding.swift new file mode 100644 index 00000000..bdd65837 --- /dev/null +++ b/MVMCoreUI/Styles/Padding.swift @@ -0,0 +1,74 @@ +// +// Padding.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 4/1/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + + +public struct Padding { + + public static let One: CGFloat = 6 + public static let Two: CGFloat = 12 + public static let Three: CGFloat = 18 + public static let Four: CGFloat = 24 + public static let Five: CGFloat = 30 + public static let Six: CGFloat = 36 + public static let Seven: CGFloat = 42 + public static let Eight: CGFloat = 48 + public static let Nine: CGFloat = 54 + public static let Ten: CGFloat = 60 + + public static let TableCellParagraphSpace: CGFloat = 3 + public static let FooterLabelParagraphSpace: CGFloat = 4 + public static let WebViewInset: CGFloat = 8 + public static let HeightTableSeperatorHeight: CGFloat = 1 + public static let MFHeightForSwitch: CGFloat = 22 + public static let MFWidthForSwitch: CGFloat = 42 + public static let DisableOppacity: CGFloat = 0.5 + public static let PaymentMethodViewHeightWidthMultiplier: CGFloat = 0.55 + public static let MinCellHeight: CGFloat = 96 + public static let HeightIphone5: CGFloat = 568 + public static let DefaultOptionCellHeight: CGFloat = 120 + public static let PromoViewHeight: CGFloat = 41.9 + public static let BetweenFields: CGFloat = 24 + public static let LabelWithInternalButtonLineSpace: CGFloat = 2 + public static let PrimaryButtonTop: CGFloat = 36 + + public struct Default { + public static let Standard: CGFloat = 24 + public static let HorizontalSpacing: CGFloat = 32 + public static let VerticalSpacing: CGFloat = 32 + public static let VerticalSpacing3: CGFloat = 24 + + public static var HorizontalPaddingForApplicationWidth: CGFloat { + return MFSizeObject(scalingStandardSize: PaddingDefaultHorizontalSpacing)?.getValueBasedOnApplicationWidth() ?? 0 + } + + public static var VerticalPaddingForApplicationWidth: CGFloat { + return MFSizeObject(scalingStandardSize: PaddingDefaultVerticalSpacing)?.getValueBasedOnApplicationWidth() ?? 0 + } + + public static func horizontalPadding(forSize size: CGFloat) -> CGFloat { + return MFSizeObject(scalingStandardSize: PaddingDefaultHorizontalSpacing)?.getValueBased(onSize: size) ?? 0 + } + + public static func verticalPadding(forSize size: CGFloat) -> CGFloat { + return MFSizeObject(scalingStandardSize: PaddingDefaultVerticalSpacing)?.getValueBased(onSize: size) ?? 0 + } + } + + public struct Horizontal { + public static let HeadlineWhiteView: CGFloat = 60 + public static let Large: CGFloat = 72 + public static let BetweenRelatedItems: CGFloat = 16 + } + + public struct Vertical { + public static let WhiteGrayView: CGFloat = 72 + public static let HeadlineAlternate: CGFloat = 48 + } +} diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift index 0a38e6f0..a43bc47a 100644 --- a/MVMCoreUI/Styles/Styler.swift +++ b/MVMCoreUI/Styles/Styler.swift @@ -9,6 +9,7 @@ import Foundation import MVMCore + public protocol VogueProtocol { } @@ -23,56 +24,13 @@ public protocol VogueTextProtocol: VogueProtocol { } -struct Padding { - - static let One: CGFloat = 6 - static let Two: CGFloat = 12 - static let Three: CGFloat = 18 - static let Four: CGFloat = 24 - static let Five: CGFloat = 30 - static let Six: CGFloat = 36 - static let Seven: CGFloat = 42 - static let Eight: CGFloat = 48 - static let Nine: CGFloat = 54 - static let Ten: CGFloat = 60 - - static let TableCellParagraphSpace: CGFloat = 3 - static let FooterLabelParagraphSpace: CGFloat = 4 - static let WebViewInset: CGFloat = 8 - static let HeightTableSeperatorHeight: CGFloat = 1 - static let MFHeightForSwitch: CGFloat = 22 - static let MFWidthForSwitch: CGFloat = 42 - static let DisableOppacity: CGFloat = 0.5 - static let PaymentMethodViewHeightWidthMultiplier: CGFloat = 0.55 - static let MinCellHeight: CGFloat = 96 - static let HeightIphone5: CGFloat = 568 - static let DefaultOptionCellHeight: CGFloat = 120 - static let PromoViewHeight: CGFloat = 41.9 - static let BetweenFields: CGFloat = 24 - static let LabelWithInternalButtonLineSpace: CGFloat = 2 - static let PrimaryButtonTop: CGFloat = 36 - - struct Default { - static let Standard: CGFloat = 24 - static let HorizontalSpacing: CGFloat = 32 - static let VerticalSpacing: CGFloat = 32 - static let VerticalSpacing3: CGFloat = 24 - } - - struct Horizontal { - static let HeadlineWhiteView: CGFloat = 60 - static let Large: CGFloat = 72 - static let BetweenRelatedItems: CGFloat = 16 - } - - struct Vertical { - static let WhiteGrayView: CGFloat = 72 - static let HeadlineAlternate: CGFloat = 48 - } -} -public class Styler { +open class Styler { + + //-------------------------------------------------- + // MARK: - Enums + //-------------------------------------------------- enum MFViewBorder: Int { case top @@ -81,63 +39,81 @@ public class Styler { case right } - enum MFTimeFormatUnit: Int { - case mfTimeFormatColon = 0 //!{days} : {hour} : {minutes} : {seconds} - case mfTimeFormatNormal = 1 // will end with days hours minutes seconds, when left days less than 2, it will change to 'day' - } - - //-------------------------------------------------- - // MARK: - Enum - //-------------------------------------------------- - - public enum Style: String { - case H1 - case H2 - case H3 - case H32 - case B1 - case B2 - case B3 - case B20 + public enum FontStyle: String { + case Title2XLarge + case TitleXLarge + case BoldTitleLarge + case RegularTitleLarge + case BoldTitleMedium + case RegularTitleMedium + case BoldBodyLarge + case RegularBodyLarge + case BoldBodySmall + case RegularBodySmall + case BoldMicro + case RegularMicro - func font(_ genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 0 + func pointSize() -> CGFloat { + switch self { + case .Title2XLarge: + return 36 + + case .TitleXLarge: + return 32 + + case .BoldTitleLarge, + .RegularTitleLarge: + return 24 + + case .BoldTitleMedium, + .RegularTitleMedium: + return 20 + + case .BoldBodyLarge, + .RegularBodyLarge: + return 16 + + case .BoldBodySmall, + .RegularBodySmall: + return 13 + + case .BoldMicro, .RegularMicro: + return 11 + } + } + + func isBold() -> Bool { switch self { - case .H1: - size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 40 - return MFFonts.mfFont75Bd(size) + case .Title2XLarge, + .TitleXLarge, + .RegularTitleLarge, + .RegularTitleMedium, + .RegularBodyLarge, + .RegularBodySmall, + .RegularMicro: + return false - case .H2: - size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 25 - return MFFonts.mfFont75Bd(size) - - case .H3: - size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 18 - return MFFonts.mfFont75Bd(size) - - case .H32: - size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 32 - return MFFonts.mfFont75Bd(size) - - case .B1: - size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 13 - return MFFonts.mfFont75Bd(size) - - case .B2: - size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 13 - return MFFonts.mfFont55Rg(size) - - case .B3: - size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 11 - return MFFonts.mfFont55Rg(size) - - case .B20: - size = genericScaling ? sizeFontGeneric(forCurrentDevice: size) : 20 - return MFFonts.mfFont55Rg(size) + case .BoldTitleLarge, + .BoldTitleMedium, + .BoldBodyLarge, + .BoldBodySmall, + .BoldMicro: + return true } } + + func getFont(_ genericScaling: Bool = true) -> UIFont? { + + let size = genericScaling ? sizeFontGeneric(forCurrentDevice: pointSize()) : pointSize() + return getMVA3FontSize(size, bold: isBold()) + } + + func styleLabel(_ label: UILabel, genericScaling: Bool = true) { + + label.font = getFont(genericScaling) + label.textColor = .black + } } public enum Tier { @@ -156,7 +132,7 @@ public class Styler { } class func splitTextFieldWidth(forViewWidth width: CGFloat) -> CGFloat { - return (width - CGFloat(PaddingOne)) / 2 - defaultHorizontalPaddingForApplicationWidth() + return (width - CGFloat(PaddingOne)) / 2 - Padding.Default.HorizontalPaddingForApplicationWidth } class func sizeObjectGeneric(forCurrentDevice size: CGFloat) -> MFSizeObject? { @@ -175,29 +151,9 @@ public class Styler { // MARK: - Spacing //-------------------------------------------------- - class func defaultHorizontalPaddingForApplicationWidth() -> CGFloat { - return MFSizeObject(scalingStandardSize: PaddingDefaultHorizontalSpacing)?.getValueBasedOnApplicationWidth() ?? 0 - } - - class func defaultVerticalPaddingForApplicationWidth() -> CGFloat { - return MFSizeObject(scalingStandardSize: PaddingDefaultVerticalSpacing)?.getValueBasedOnApplicationWidth() ?? 0 - } - - class func defaultHorizontalPadding(forSize size: CGFloat) -> CGFloat { - return MFSizeObject(scalingStandardSize: PaddingDefaultHorizontalSpacing)?.getValueBased(onSize: size) ?? 0 - } - - class func defaultVerticalPadding(forSize size: CGFloat) -> CGFloat { - return MFSizeObject(scalingStandardSize: PaddingDefaultVerticalSpacing)?.getValueBased(onSize: size) ?? 0 - } - - class func setDefaultMarginsFor(_ view: UIView?, size: CGFloat) { - setDefaultMarginsFor(view, size: size, horizontal: true, vertical: false) - } - - class func setDefaultMarginsFor(_ view: UIView?, size: CGFloat, horizontal: Bool, vertical: Bool) { + class func setDefaultMarginsFor(_ view: UIView?, size: CGFloat, horizontal: Bool = true, vertical: Bool = false) { - let horizontalPadding: CGFloat = horizontal ? defaultHorizontalPadding(forSize: size) : 0 + let horizontalPadding: CGFloat = horizontal ? Padding.Default.horizontalPadding(forSize: size) : 0 let verticalPadding: CGFloat = vertical ? PaddingDefaultVerticalSpacing3 : 0 DispatchQueue.main.async { @@ -207,7 +163,7 @@ public class Styler { class func setMarginsFor(_ view: UIView?, size: CGFloat, defaultHorizontal horizontal: Bool, top: CGFloat, bottom: CGFloat) { - let horizontalPadding: CGFloat = horizontal ? defaultHorizontalPadding(forSize: size) : 0 + let horizontalPadding: CGFloat = horizontal ? Padding.Default.horizontalPadding(forSize: size) : 0 DispatchQueue.main.async { MVMCoreUIUtility.setMarginsFor(view, leading: horizontalPadding, top: top, trailing: horizontalPadding, bottom: bottom) @@ -219,1023 +175,27 @@ public class Styler { //-------------------------------------------------- class func getMVA3FontSize(_ size: CGFloat, bold isBold: Bool) -> UIFont { + if isBold { - if size >= 15 { - return MFFonts.mfFontDSBold(size) - } else { - return MFFonts.mfFontTXBold(size) - } + return size >= 15 ? MFFonts.mfFontDSBold(size) : MFFonts.mfFontTXBold(size) + } else { - if size >= 15 { - return MFFonts.mfFontDSRegular(size) - } else { - return MFFonts.mfFontTXRegular(size) - } + return size >= 15 ? MFFonts.mfFontDSRegular(size) : MFFonts.mfFontTXRegular(size) } } - class func fontTitle2XLarge(_ genericScaling: Bool) -> UIFont { - var size: CGFloat = 36 - if genericScaling { - size = self.sizeFontGeneric(forCurrentDevice: size) - } - return self.getMVA3FontSize(size, bold: true) - } - - class func fontTitle2XLarge() -> UIFont { - return self.fontTitle2XLarge(true) - } - - class func fontTitleXLarge(_ genericScaling: Bool) -> UIFont { - var size: CGFloat = 32 - if genericScaling { - size = self.sizeFontGeneric(forCurrentDevice: size) - } - return self.getMVA3FontSize(size, bold: true) - } - - class func fontTitleXLarge() -> UIFont { - return self.fontTitleXLarge(true) - } - - class func fontBoldTitleLarge(_ genericScaling: Bool) -> UIFont { - var size: CGFloat = 24 - if genericScaling { - size = self.sizeFontGeneric(forCurrentDevice: size) - } - return self.getMVA3FontSize(size, bold: true) - } - - class func fontBoldTitleLarge() -> UIFont { - return self.fontBoldTitleLarge(true) - } - - class func fontRegularTitleLarge(_ genericScaling: Bool) -> UIFont { - var size: CGFloat = 24 - if genericScaling { - size = self.sizeFontGeneric(forCurrentDevice: size) - } - return self.getMVA3FontSize(size, bold: false) - } - - class func fontRegularTitleLarge() -> UIFont { - return self.fontRegularTitleLarge(true) - } - - class func fontBoldTitleMedium(_ genericScaling: Bool) -> UIFont { - var size: CGFloat = 20 - if genericScaling { - size = self.sizeFontGeneric(forCurrentDevice: size) - } - return self.getMVA3FontSize(size, bold: true) - } - - class func fontBoldTitleMedium() -> UIFont { - return self.fontBoldTitleMedium(true) - } - - class func fontRegularTitleMedium(_ genericScaling: Bool) -> UIFont { - var size: CGFloat = 20 - if genericScaling { - size = self.sizeFontGeneric(forCurrentDevice: size) - } - return self.getMVA3FontSize(size, bold: false) - } - - class func fontRegularTitleMedium() -> UIFont { - return self.fontRegularTitleMedium(true) - } - - class func fontBoldBodyLarge(_ genericScaling: Bool) -> UIFont { - var size: CGFloat = 16 - if genericScaling { - size = self.sizeFontGeneric(forCurrentDevice: size) - } - return self.getMVA3FontSize(size, bold: true) - } - - class func fontBoldBodyLarge() -> UIFont { - return self.fontBoldBodyLarge(true) - } - - class func fontRegularBodyLarge(_ genericScaling: Bool) -> UIFont { - var size: CGFloat = 16 - if genericScaling { - size = self.sizeFontGeneric(forCurrentDevice: size) - } - return self.getMVA3FontSize(size, bold: false) - } - - class func fontRegularBodyLarge() -> UIFont { - return self.fontRegularBodyLarge(true) - } - - class func fontBoldBodySmall(_ genericScaling: Bool) -> UIFont { - var size: CGFloat = 13 - if genericScaling { - size = self.sizeFontGeneric(forCurrentDevice: size) - } - return self.getMVA3FontSize(size, bold: true) - } - - class func fontBoldBodySmall() -> UIFont { - return self.fontBoldBodySmall(true) - } - - class func fontRegularBodySmall(_ genericScaling: Bool) -> UIFont { - var size: CGFloat = 13 - if genericScaling { - size = self.sizeFontGeneric(forCurrentDevice: size) - } - return self.getMVA3FontSize(size, bold: false) - } - - class func fontRegularBodySmall() -> UIFont { - return self.fontRegularBodySmall(true) - } - - class func fontBoldMicro(_ genericScaling: Bool) -> UIFont { - var size: CGFloat = 11 - if genericScaling { - size = self.sizeFontGeneric(forCurrentDevice: size) - } - return self.getMVA3FontSize(size, bold: true) - } - - class func fontBoldMicro() -> UIFont { - return self.fontBoldMicro(true) - } - - class func fontRegularMicro(_ genericScaling: Bool) -> UIFont { - var size: CGFloat = 11 - if genericScaling { - size = self.sizeFontGeneric(forCurrentDevice: size) - } - return self.getMVA3FontSize(size, bold: false) - } - - class func fontRegularMicro() -> UIFont { - return self.fontRegularMicro(true) - } - - //-------------------------------------------------- - // MARK: - Fonts - //-------------------------------------------------- - - class func fontH1(_ genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 40 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func fontH2(_ genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 25 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func fontH3(_ genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 18 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func fontH32(_ genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 32 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func fontB1(_ genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 13 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func fontB2(_ genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 13 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont55Rg(size) - } - - class func fontB3(_ genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 11 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont55Rg(size) - } - - class func fontB20(_ genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 20 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont55Rg(size) - } - - //-------------------------------------------------- - // MARK: - 3.0 Styles - //-------------------------------------------------- - - class func styleLabelTitle2XLarge(_ label: UILabel, genericScaling: Bool) { - label.font = MFStyler.fontTitle2XLarge(genericScaling) - label.textColor = UIColor.black - } - - class func styleLabelTitle2XLarge(_ label: UILabel) { - self.styleLabelTitle2XLarge(label, genericScaling: true) - } - - class func styleLabelTitleXLarge(_ label: UILabel, genericScaling: Bool) { - label.font = MFStyler.fontTitleXLarge(genericScaling) - label.textColor = UIColor.black - } - - class func styleLabelTitleXLarge(_ label: UILabel) { - self.styleLabelTitleXLarge(label, genericScaling: true) - } - - class func styleLabelBoldTitleLarge(_ label: UILabel, genericScaling: Bool) { - label.font = MFStyler.fontBoldTitleLarge(genericScaling) - label.textColor = UIColor.black - } - - class func styleLabelBoldTitleLarge(_ label: UILabel) { - self.styleLabelBoldTitleLarge(label, genericScaling: true) - } - - class func styleLabelRegularTitleLarge(_ label: UILabel, genericScaling: Bool) { - label.font = MFStyler.fontRegularTitleLarge(genericScaling) - label.textColor = UIColor.black - } - - class func styleLabelRegularTitleLarge(_ label: UILabel) { - self.styleLabelBoldTitleLarge(label, genericScaling: true) - } - - class func styleLabelBoldTitleMedium(_ label: UILabel, genericScaling: Bool) { - label.font = MFStyler.fontBoldTitleMedium(genericScaling) - label.textColor = UIColor.black - } - - class func styleLabelBoldTitleMedium(_ label: UILabel) { - self.styleLabelBoldTitleMedium(label, genericScaling: true) - } - - class func styleLabelRegularTitleMedium(_ label: UILabel, genericScaling: Bool) { - label.font = MFStyler.fontRegularTitleMedium(genericScaling) - label.textColor = UIColor.black - } - - class func styleLabelRegularTitleMedium(_ label: UILabel) { - self.styleLabelRegularTitleMedium(label, genericScaling: true) - } - - class func styleLabelBoldBodyLarge(_ label: UILabel, genericScaling: Bool) { - label.font = MFStyler.fontBoldBodyLarge(genericScaling) - label.textColor = UIColor.black - } - - class func styleLabelBoldBodyLarge(_ label: UILabel) { - self.styleLabelBoldBodyLarge(label, genericScaling: true) - } - - class func styleLabelRegularBodyLarge(_ label: UILabel, genericScaling: Bool) { - label.font = MFStyler.fontRegularBodyLarge(genericScaling) - label.textColor = UIColor.black - } - - class func styleLabelRegularBodyLarge(_ label: UILabel) { - self.styleLabelRegularBodyLarge(label, genericScaling: true) - } - - class func styleLabelBoldBodySmall(_ label: UILabel, genericScaling: Bool) { - label.font = MFStyler.fontBoldBodySmall(genericScaling) - label.textColor = UIColor.black - } - - class func styleLabelBoldBodySmall(_ label: UILabel) { - self.styleLabelBoldBodySmall(label, genericScaling: true) - } - - class func styleLabelRegularBodySmall(_ label: UILabel, genericScaling: Bool) { - label.font = MFStyler.fontRegularBodySmall(genericScaling) - label.textColor = UIColor.black - } - - class func styleLabelRegularBodySmall(_ label: UILabel) { - self.styleLabelRegularBodySmall(label, genericScaling: true) - } - - class func styleLabelBoldMicro(_ label: UILabel, genericScaling: Bool) { - label.font = MFStyler.fontBoldMicro(genericScaling) - label.textColor = UIColor.black - } - - class func styleLabelBoldMicro(_ label: UILabel) { - self.styleLabelBoldMicro(label, genericScaling: true) - } - - class func styleLabelRegularMicro(_ label: UILabel, genericScaling: Bool) { - label.font = MFStyler.fontRegularMicro(genericScaling) - label.textColor = UIColor.black - } - - class func styleLabelRegularMicro(_ label: UILabel) { - self.styleLabelRegularMicro(label, genericScaling: true) - } - - class func styleMVA3Label(_ label: UILabel, withStyle style: String?, genericScaling: Bool) -> Bool { - if (style == "Title2XLarge") { - self.styleLabelTitle2XLarge(label, genericScaling: genericScaling) - return true - } else if (style == "TitleXLarge") { - self.styleLabelTitleXLarge(label, genericScaling: genericScaling) - return true - } else if (style == "BoldTitleLarge") { - self.styleLabelBoldTitleLarge(label, genericScaling: genericScaling) - return true - } else if (style == "RegularTitleLarge") { - self.styleLabelRegularTitleLarge(label, genericScaling: genericScaling) - return true - } else if (style == "BoldTitleMedium") { - self.styleLabelBoldTitleMedium(label, genericScaling: genericScaling) - return true - } else if (style == "RegularTitleMedium") { - self.styleLabelRegularTitleMedium(label, genericScaling: genericScaling) - return true - } else if (style == "BoldBodyLarge") { - self.styleLabelBoldBodyLarge(label, genericScaling: genericScaling) - return true - } else if (style == "RegularBodyLarge") { - self.styleLabelRegularBodyLarge(label, genericScaling: genericScaling) - return true - } else if (style == "BoldBodySmall") { - self.styleLabelBoldBodySmall(label, genericScaling: genericScaling) - return true - } else if (style == "RegularBodySmall") { - self.styleLabelRegularBodySmall(label, genericScaling: genericScaling) - return true - } else if (style == "BoldMicro") { - self.styleLabelBoldMicro(label, genericScaling: genericScaling) - return true - } else if (style == "RegularMicro") { - self.styleLabelRegularMicro(label, genericScaling: genericScaling) - return true - } else { - return false - } - } - //-------------------------------------------------- // MARK: - Styles //-------------------------------------------------- - class func styleLabel(_ label: VogueTextProtocol, withStyle style: Style, genericScaling: Bool) { - - switch style { - case .H1: - styleLabelH1(label, genericScaling: genericScaling) - - case .H2: - styleLabelH2(label, genericScaling: genericScaling) - - case .H3: - styleLabelH3(label, genericScaling: genericScaling) - - case .H32: - styleLabelH32(label, genericScaling: genericScaling) - - case .B1: - styleLabelB1(label, genericScaling: genericScaling) - - case .B2: - styleLabelB2(label, genericScaling: genericScaling) - - case .B3: - styleLabelB3(label, genericScaling: genericScaling) - - case .B20: - styleLabelB20(label, genericScaling: genericScaling) - } - } - - class func styleLabel(_ label: UILabel, withStyle style: Style) { - styleLabel(label, withStyle: style, genericScaling: true) - } - - class func styleLabelH1(_ label: VogueTextProtocol, genericScaling: Bool = true) { - - label.styleTextColor(.black) - - if let h1 = fontH1(genericScaling) { - label.styleFont(h1) - } - } - - class func styleLabelH2(_ label: VogueTextProtocol, genericScaling: Bool = true) { - - label.styleTextColor(.black) - - if let h2 = fontH2(genericScaling) { - label.styleFont(h2) - } - } - - class func styleLabelH3(_ label: VogueTextProtocol, genericScaling: Bool = true) { - - label.styleTextColor(.black) - - if let h3 = fontH3(genericScaling) { - label.styleFont(h3) - } - } - - class func styleLabelH32(_ label: VogueTextProtocol, genericScaling: Bool = true) { - - label.styleTextColor(.black) - - if let h32 = fontH32(genericScaling) { - label.styleFont(h32) - } - } - - class func styleLabelB1(_ label: VogueTextProtocol, genericScaling: Bool = true) { - - label.styleTextColor(.black) - - if let b1 = fontB1(genericScaling) { - label.styleFont(b1) - } - } - - class func styleLabelB2(_ label: VogueTextProtocol, genericScaling: Bool = true) { - - label.styleTextColor(.black) - - if let b2 = fontB2(genericScaling) { - label.styleFont(b2) - } - } - - class func styleLabelB2(_ label: UILabel, size: CGFloat, genericScaling: Bool = true) { - label.font = fontForBody(withSize: size, genericScaling: genericScaling) - } - - class func styleLabelB3(_ label: VogueTextProtocol, genericScaling: Bool = true) { - - label.styleTextColor(.mfBackgroundGray()) - - if let b3 = fontB3(genericScaling) { - label.styleFont(b3) - } - } - - class func styleLabelB20(_ label: VogueTextProtocol, genericScaling: Bool = true) { - - label.styleTextColor(.black) - - if let b20 = fontB20(genericScaling) { - label.styleFont(b20) - } - } - - class func styleLabelTextStyle2(_ label: VogueTextProtocol, genericScaling: Bool = true) { - - label.styleTextColor(.mfBattleshipGrey()) - - if let b2 = fontB2(genericScaling) { - label.styleFont(b2) - } - } - - class func fontForBody(withSize size: CGFloat, genericScaling: Bool) -> UIFont? { - - var size = size - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont55Rg(size) - } - - class func fontForBody(withSize size: CGFloat, forWidth width: CGFloat) -> UIFont? { - - let size = sizeObjectGeneric(forCurrentDevice: size)?.getValueBased(onSize: width) ?? size - - return MFFonts.mfFont55Rg(size) - } - - //-------------------------------------------------- - // MARK: - 1.0 Fonts - //-------------------------------------------------- - - class func font(forPlan genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 100 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func font(forBiggerHeadLine genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 48 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func font(forHeadlineSmall genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 15 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func font(forHeadlineSmall2 genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 16 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func fontForHeadlineSmall2(forWidth size: CGFloat) -> UIFont? { - - var pointSize: CGFloat = 16 - pointSize = Styler.sizeObjectGeneric(forCurrentDevice: pointSize)!.getValueBased(onSize: size) - - return MFFonts.mfFont75Bd(pointSize) - } - - class func fontB1(forWidth size: CGFloat) -> UIFont? { - - var pointSize: CGFloat = 13 - pointSize = Styler.sizeObjectGeneric(forCurrentDevice: pointSize)!.getValueBased(onSize: size) - - return MFFonts.mfFont75Bd(pointSize) - } - - //-------------------------------------------------- - // MARK: - 1.0 Styles - //-------------------------------------------------- - - class func styleFeedCardTitleLabel(_ label: UILabel) { - - label.font = Styler.fontForFeedCardTitle() - label.textColor = .black - } - - class func styleFeedCardTagLabel(_ label: UILabel) { - - label.font = Styler.fontB3() - label.textColor = .mfBrownishGrey() - } - - class func styleStandardSeparatorView(_ view: UIView) { - - view.backgroundColor = .mfBackgroundGray() - } - - class func styleLabelHeadlineSmall(_ label: UILabel, genericScaling: Bool) { - - label.font = Styler.font(forHeadlineSmall: genericScaling) - label.textColor = .black - } - - class func styleFeedCardTitleLabel(_ label: UILabel, genericScaling: Bool) { - - label.font = Styler.font(forFeedCardTitle: genericScaling) - label.textColor = UIColor.black - } - - class func styleFeedCardTagLabel(_ label: UILabel, genericScaling: Bool) { - - label.font = Styler.fontB3(genericScaling) - label.textColor = UIColor.mfBrownishGrey() - } - - class func fontB2(forWidth size: CGFloat) -> UIFont? { - - var pointSize: CGFloat = 13 - - pointSize = Styler.sizeObjectGeneric(forCurrentDevice: pointSize)!.getValueBased(onSize: size) - - return MFFonts.mfFont55Rg(pointSize) - } - - class func fontforChatText(_ genericScaling: Bool = false) -> UIFont? { - - var size: CGFloat = 14 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont55Rg(size) - } - - class func font(forAccountLandingGreeting genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 16 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont55Rg(size) - } - - class func font(forProgressBarBottomLabel genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 10 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont55Rg(size) - } - - class func font(forFeedCardTitle genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 16 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func font(forPrimaryButton genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 14 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func fontForPrimaryButton(forWidth size: CGFloat) -> UIFont? { - - var pointSize: CGFloat = 14 - pointSize = Styler.sizeObjectGeneric(forCurrentDevice: pointSize)!.getValueBased(onSize: size) - return MFFonts.mfFont75Bd(pointSize) - } - - class func font(forSmallButton genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 11 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func fontForSmallButton(forWidth size: CGFloat) -> UIFont? { - - var pointSize: CGFloat = 11 - pointSize = Styler.sizeObjectGeneric(forCurrentDevice: pointSize)!.getValueBased(onSize: size) - - return MFFonts.mfFont75Bd(pointSize) - } - - class func font(forTextField genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 16 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont55Rg(size) - } - - class func font(forTextFieldUnderLabel genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 12 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont55Rg(size) - } - - class func fontForUnreadMessage(onSupport genericScaling: Bool = false) -> UIFont? { - - var size: CGFloat = 10 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func font5GMessage(_ genericScaling: Bool) -> UIFont? { - - var size: CGFloat = 16 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont55Rg(size) - } - - class func font5GMessage() -> UIFont? { - return font5GMessage(true) - } - - class func font(forHeadlineAlternative genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 24 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont55Rg(size) - } - - class func fontForHeadlineAlternative(forWidth size: CGFloat) -> UIFont? { - - var pointSize: CGFloat = 24 - pointSize = Styler.sizeObjectGeneric(forCurrentDevice: pointSize)!.getValueBased(onSize: size) - - return MFFonts.mfFont55Rg(pointSize) - } - - class func fontH255(_ genericScaling: Bool) -> UIFont? { - - var size: CGFloat = 25 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont55Rg(size) - } - - class func font(forLargeLoyaltyHeaderTitle genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 60 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func font(forLoyaltyTitleSmall genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 42 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func font(forLoyaltyMessage genericScaling: Bool = true) -> UIFont? { - - var size: CGFloat = 20 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont55Rg(size) - } - - class func font(forPtPCard genericScaling: Bool) -> UIFont? { - - var size: CGFloat = 22 - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func fontForLabelWithTopLeftCircle(withSize size: CGFloat, genericScaling: Bool) -> UIFont? { - - var size = size - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFont75Bd(size) - } - - class func fontOcratxtWitSize(_ size: CGFloat, genericScaling: Bool) -> UIFont? { - - var size = size - - if genericScaling { - size = sizeFontGeneric(forCurrentDevice: size) - } - - return MFFonts.mfFontOcratxt(size) - } - - class func boldFont(forScaledSize size: CGFloat) -> UIFont { - return MFFonts.mfFont75Bd(sizeFontGeneric(forCurrentDevice: size))! - } - - class func regularFont(forScaledSize size: CGFloat) -> UIFont { - return MFFonts.mfFont55Rg(sizeFontGeneric(forCurrentDevice: size))! - } - - //-------------------------------------------------- - // MARK: - 1.0 Attributed Strings Style - //-------------------------------------------------- - - class func styleGetAttributedString(_ string: String?, withStyle style: String?) -> NSAttributedString { - return styleGetAttributedString(string, withStyle: Styler.Style(rawValue: style!)!, genericScaling: true) - } - - class func styleGetAttributedString(_ string: String?, withStyle style: Style, genericScaling: Bool) -> NSAttributedString { - - switch style { - case .H1: - return styleGetH1AttributedString(string, genericScaling: genericScaling) - - case .H2: - return styleGetH2AttributedString(string, genericScaling: genericScaling) - - case .H3: - return styleGetH3AttributedString(string, genericScaling: genericScaling) - - case .H32: - return styleGetH32AttributedString(string, genericScaling: genericScaling) - - case .B1: - return styleGetB1AttributedString(string, genericScaling: genericScaling) - - case .B2: - return styleGetB2AttributedString(string, genericScaling: genericScaling) - - case .B3: - return styleGetB3AttributedString(string, genericScaling: genericScaling) - - case .B20: - return styleGetB20AttributedString(string, genericScaling: genericScaling) - } - } - - class func styleGetAttributedString(_ string: String?, font: UIFont, color: UIColor) -> NSAttributedString { - - var attributedString: NSAttributedString? = nil - - if let string = string, !string.isEmpty { - attributedString = NSAttributedString(string: string, attributes: [NSAttributedString.Key.font: font, - NSAttributedString.Key.foregroundColor: color]) - } else { - attributedString = NSAttributedString(string: "") - } - - return attributedString! - } - - class func styleGetH1AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { - return styleGetAttributedString(string, font: fontH1(genericScaling)!, color: .black) - } - - class func styleGetH2AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { - return styleGetAttributedString(string, font: fontH2(genericScaling)!, color: .black) - } - - class func styleGetH3AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { - return styleGetAttributedString(string, font: fontH3(genericScaling)!, color: .black) - } - - class func styleGetH32AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { - return styleGetAttributedString(string, font: fontH32(genericScaling)!, color: .black) - } - - class func styleGetB1AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { - return styleGetAttributedString(string, font: fontB1(genericScaling)!, color: .black) - } - - class func styleGetB2AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { - return styleGetAttributedString(string, font: fontB2(genericScaling)!, color: .black) - } - - class func styleGetB3AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { - return styleGetAttributedString(string, font: fontB3(genericScaling)!, color: .mfBattleshipGrey()) - } - - class func styleGetB20AttributedString(_ string: String?, genericScaling: Bool = true) -> NSAttributedString { - return styleGetAttributedString(string, font: fontB20(genericScaling)!, color: .black) - } - - class func styleGetTopAlignedAttributeString(withLeftStringRightTop left: String?, center: String, rightString right: String?, withCenterStringFontSize fontSize: CGFloat, andColor color: UIColor) -> NSAttributedString { - - var left = left ?? "" - var center = center - var right = right ?? "" - - let text = "\(left)\(center)\(right)" - let attribs = [NSAttributedString.Key.foregroundColor: color] - var attributedText = NSMutableAttributedString(string: text, attributes: attribs) - - let centerRange = (text as NSString).range(of: center) - let centerFont = MFFonts.mfFont75Bd(fontSize) - let centerHeight = centerFont?.capHeight ?? 0.0 - attributedText.addAttributes([NSAttributedString.Key.font: MFFonts.mfFont75Bd(fontSize) as Any], range: centerRange) - - let leftRange = (text as NSString).range(of: left) - let leftFont = MFFonts.mfFont75Bd(fontSize * 0.34) - let leftHeight = leftFont?.capHeight ?? 0.0 - - if let leftFont = leftFont { - attributedText.addAttributes([NSAttributedString.Key.font: leftFont, - NSAttributedString.Key.baselineOffset: NSNumber(value: Float(centerHeight - leftHeight))], range: leftRange) - } - - let rightRange = NSRange(location: centerRange.location + centerRange.length, length: right.count ) - let rightFont = MFFonts.mfFont75Bd(fontSize * 0.34) - - let offset = Float((centerFont?.pointSize ?? 0.0) - (centerFont?.capHeight ?? 0.0) + (rightFont?.pointSize ?? 0.0) / 2) - - if let rightFont = rightFont { - attributedText.addAttributes([NSAttributedString.Key.font: rightFont, - NSAttributedString.Key.baselineOffset: offset], - range: rightRange) - } - - return attributedText - } - class func styleGetAlignCenteredAttrituedString(_ string: inout NSMutableAttributedString?) { if let string = string, string.length > 0 { let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.alignment = .center - string.addAttribute(.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: string.length)) + string.addAttribute(.paragraphStyle, + value: paragraphStyle, + range: NSRange(location: 0, length: string.length)) } } @@ -1248,7 +208,9 @@ public class Styler { if openingRange?.location != NSNotFound && closingRange?.location != NSNotFound { let boldLength = (closingRange?.location ?? 0) - (openingRange?.location ?? 0) if let inputFont = inputFont { - attrString.setAttributes([NSAttributedString.Key.font: inputFont], range: NSRange(location: openingRange?.location ?? 0, length: boldLength)) + attrString.setAttributes([NSAttributedString.Key.font: inputFont], + range: NSRange(location: openingRange?.location ?? 0, + length: boldLength)) } if let closingRange = closingRange { @@ -1286,14 +248,14 @@ public class Styler { class func styleGetLowCaseSpace(_ inputString: String?) -> String? { if (inputString?.count ?? 0) > 0 { - let trimmedString = inputString?.lowercased().trimmingCharacters(in: CharacterSet.whitespacesAndNewlines) + let trimmedString = inputString?.lowercased().trimmingCharacters(in: .whitespacesAndNewlines) return trimmedString } return "" } - class func labelStrokeAttributes(_ color: UIColor?) -> [AnyHashable : Any]? { + class func labelStrokeAttributes(_ color: UIColor?) -> [AnyHashable: Any]? { guard let color = color else { return nil } @@ -1301,12 +263,6 @@ public class Styler { NSAttributedString.Key.strokeWidth: -1.0] } - class func mfStyleBlackPageControl(_ pageControl: UIPageControl?) { - - pageControl?.pageIndicatorTintColor = .mfLighterGray() - pageControl?.currentPageIndicatorTintColor = .black - } - //-------------------------------------------------- // MARK: - Custom Styling Views //-------------------------------------------------- @@ -1337,189 +293,8 @@ public class Styler { NSLayoutConstraint.constraintPinSubview(borderLine, pinTop: false, pinBottom: false, pinLeft: false, pinRight: true) NSLayoutConstraint.constraintPinView(borderLine, heightConstraint: true, heightConstant: borderLineLengh, widthConstraint: true, widthConstant: borderLineWidth) NSLayoutConstraint.constraintPinSubview(borderLine, pinCenterX: false, pinCenterY: true) - - default: - break } borderLine.backgroundColor = color } - - class func mfStylePageControl(_ pageControl: UIPageControl?) { - - pageControl?.pageIndicatorTintColor = .mfLighterGray() - pageControl?.currentPageIndicatorTintColor = .mfRed() - } - - class func styleTextField(_ textField: UITextField) { - - textField.font = fontForTextField() - // As per AKQA - /* If the length of the text field exceeds the amount of space, the size of the text drops down. - So, the entire line of copy can be read. - 16 point font size is the lowest recommended size. - */ - textField.minimumFontSize = 16 - textField.adjustsFontSizeToFitWidth = true // default is NO. if YES, text will shrink to minFontSize along baseline - } - /* - class func setGradientTo(_ label: UILabel, withColors colors: [AnyHashable]) { - - var textSize: CGSize? = nil - - if let font = UIFont(name: label.font.fontName, size: label.font.lineHeight) { - textSize = label.text?.size(withAttributes: [NSAttributedString.Key.baselineOffset: 0, - NSAttributedString.Key.font: font]) - } - - let width = (textSize?.width ?? 0.0) > 1024 ? 1024 : textSize?.width ?? 0.0 // max 1024 due to Core Graphics limitations - let height = (textSize?.height ?? 0.0) > 1024 ? 1024 : textSize?.height ?? 0.0 // max 1024 due to Core Graphics limitations - - // create a new bitmap image context - UIGraphicsBeginImageContext(CGSize(width: width, height: height)) - - let context = UIGraphicsGetCurrentContext() - - // push context to make it current (need to do this manually because we are not drawing in a UIView) - if let context = context { - UIGraphicsPushContext(context) - } - - var glossGradient: CGGradient? - var rgbColorspace: CGColorSpace? - let num_locations = colors.count - var locations = [CGFloat](repeating: 0.0, count: colors.count) - let components = [CGFloat](repeating: 0.0, count: colors.count * 4) - var componentIndex = 0 - - for i in 0.. UIImage? { - - UIGraphicsBeginImageContextWithOptions(image?.size ?? CGSize.zero, _: true, _: 1.0) - let imageRect = CGRect(x: 0, y: 0, width: image?.size.width ?? 0.0, height: image?.size.height ?? 0.0) - - // Draw the image with the luminosity blend mode. - // On top of a white background, this will give a black and white image. - image?.draw(in: imageRect, blendMode: .luminosity, alpha: 1.0) - - // Get the resulting image. - let filteredImage = UIGraphicsGetImageFromCurrentImageContext() - UIGraphicsEndImageContext() - - return filteredImage - } - /* - class func getCountTime(_ leftTime: Int, timeformat timeFormat: String?, time timeUnit: MFTimeFormatUnit, timeSuffix suffix: String?) -> String? { - - var seconds = leftTime % 60 - var minutes = (leftTime / 60) % 60 - var hours = (leftTime / 3600) % 24 - let days = leftTime / 86400 - - guard let times = timeFormat?.components(separatedBy: ":") else { return nil } - var timeString = "" - - if times.contains("DD") { - timeString += String(format: "%02ld", days) - - if timeUnit == .mfTimeFormatNormal { - let dayKey = (days <= 1) ? "CountDownDay" : "CountDownDays" - let dayUnit = MVMCoreUIUtility.hardcodedString(withKey: dayKey) - timeString += dayUnit! - - } else if timeUnit == MFTimeFormatColon && times?.last != "DD" { - timeString += " : " - } - - if times.last != "DD" && suffix != nil { - timeString += suffix ?? "" - } - } - - if times.contains("HH") { - if !times.contains("DD") { - hours = leftTime / 3600 - } - - timeString += String(format: "%02d", hours) - - if timeUnit == .mfTimeFormatNormal { - let hourKey = (hours <= 1) ? "CountDownHour" : "CountDownHours" - let hourUnit = MVMCoreUIUtility.hardcodedString(withKey: hourKey)! - timeString += hourUnit - - } else if timeUnit == MFTimeFormatColon && times?.last != "HH" { - timeString += " : " - } - - if times.last != "HH" && suffix != nil { - timeString += suffix ?? "" - } - } - - if times.contains("MM") { - if !times.contains("HH") { - if !times.contains("DD") { - minutes = leftTime / 60 - } else { - minutes = (leftTime - days * 86400) / 60 - } - } - - timeString += String(format: "%02d", minutes) - - if times.contains("SS") { - if !times.contains("MM") { - if !times.contains("HH") { - if !times.contains("DD") { - seconds = leftTime - } else { - seconds = leftTime % 86400 - } - } else { - seconds = leftTime % 3600 - } - } - - timeString += String(format: "%02d", seconds) - - if timeUnit == .mfTimeFormatNormal { - let secondKey = (seconds <= 1) ? "CountDownSec" : "CountDownSecs" - let secondUnit = MVMCoreUIUtility.hardcodedString(withKey: secondKey) - timeString += secondUnit! - } - } - return timeString - } - } - */ } From 1758192edfbe87bb4a71937f42cfa28cb10988f6 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 1 Apr 2020 17:03:03 -0400 Subject: [PATCH 06/62] decent state --- MVMCoreUI.xcodeproj/project.pbxproj | 4 + MVMCoreUI/Styles/Styler.swift | 182 ++------------------------- MVMCoreUI/Styles/VogueProtocol.swift | 23 ++++ 3 files changed, 39 insertions(+), 170 deletions(-) create mode 100644 MVMCoreUI/Styles/VogueProtocol.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index ddb3307c..101d0c8d 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -89,6 +89,7 @@ 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */; }; 0A6682AA2435125F00AD3CA1 /* Styler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682A92435125F00AD3CA1 /* Styler.swift */; }; 0A6682AC243531C300AD3CA1 /* Padding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682AB243531C300AD3CA1 /* Padding.swift */; }; + 0A6682AE243538DB00AD3CA1 /* VogueProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682AD243538DB00AD3CA1 /* VogueProtocol.swift */; }; 0A69F611241BDEA700F7231B /* RuleAnyRequiredModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */; }; 0A6BF4722360C56C0028F841 /* BaseDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */; }; 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; }; @@ -476,6 +477,7 @@ 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesProtocol.swift; sourceTree = ""; }; 0A6682A92435125F00AD3CA1 /* Styler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Styler.swift; sourceTree = ""; }; 0A6682AB243531C300AD3CA1 /* Padding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Padding.swift; sourceTree = ""; }; + 0A6682AD243538DB00AD3CA1 /* VogueProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VogueProtocol.swift; sourceTree = ""; }; 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyRequiredModel.swift; sourceTree = ""; }; 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseDropdownEntryField.swift; sourceTree = ""; }; 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = ""; }; @@ -1472,6 +1474,7 @@ D29DF13921E68637003B2FB9 /* MFStyler.m */, 0A6682A92435125F00AD3CA1 /* Styler.swift */, 0A6682AB243531C300AD3CA1 /* Padding.swift */, + 0A6682AD243538DB00AD3CA1 /* VogueProtocol.swift */, ); path = Styles; sourceTree = ""; @@ -2005,6 +2008,7 @@ AA11A42123F15D7000D7962F /* ListRightVariablePaymentsModel.swift in Sources */, 01EB369223609801006832FA /* MoleculeStackModel.swift in Sources */, 011D9626240EBB16000E3791 /* RadioButtonLabelModel.swift in Sources */, + 0A6682AE243538DB00AD3CA1 /* VogueProtocol.swift in Sources */, AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */, D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */, 944589232385DA9600DE9FD4 /* ImageViewModel.swift in Sources */, diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift index a43bc47a..62af40fe 100644 --- a/MVMCoreUI/Styles/Styler.swift +++ b/MVMCoreUI/Styles/Styler.swift @@ -7,39 +7,14 @@ // import Foundation -import MVMCore - - -public protocol VogueProtocol { - -} - -public protocol VogueViewProtocol { - -} - -public protocol VogueTextProtocol: VogueProtocol { - func styleFont(_ font: UIFont) - func styleTextColor(_ textColor: UIColor) -} - - open class Styler { - //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- - enum MFViewBorder: Int { - case top - case left - case bottom - case right - } - - public enum FontStyle: String { + public enum Font: String { case Title2XLarge case TitleXLarge case BoldTitleLarge @@ -53,7 +28,7 @@ open class Styler { case BoldMicro case RegularMicro - func pointSize() -> CGFloat { + public func pointSize() -> CGFloat { switch self { case .Title2XLarge: return 36 @@ -82,7 +57,7 @@ open class Styler { } } - func isBold() -> Bool { + public func isBold() -> Bool { switch self { case .Title2XLarge, @@ -103,39 +78,24 @@ open class Styler { } } - func getFont(_ genericScaling: Bool = true) -> UIFont? { + public func getFont(_ genericScaling: Bool = true) -> UIFont? { let size = genericScaling ? sizeFontGeneric(forCurrentDevice: pointSize()) : pointSize() return getMVA3FontSize(size, bold: isBold()) } - func styleLabel(_ label: UILabel, genericScaling: Bool = true) { + public func styleLabel(_ label: UILabel, genericScaling: Bool = true) { label.font = getFont(genericScaling) label.textColor = .black } } - - public enum Tier { - case primary - case secondary - case ternary - case quaternary - } - + //-------------------------------------------------- // MARK: - Functions //-------------------------------------------------- - class func splitTextFieldWidth() -> CGFloat { - return splitTextFieldWidth(forViewWidth: MVMCoreUISplitViewController.getDetailViewWidth()) - } - - class func splitTextFieldWidth(forViewWidth width: CGFloat) -> CGFloat { - return (width - CGFloat(PaddingOne)) / 2 - Padding.Default.HorizontalPaddingForApplicationWidth - } - - class func sizeObjectGeneric(forCurrentDevice size: CGFloat) -> MFSizeObject? { + open class func sizeObjectGeneric(forCurrentDevice size: CGFloat) -> MFSizeObject? { let sizeObject = MFSizeObject(standardSize: size, standardiPadPortraitSize: size * 1.3) sizeObject?.addLargerThanCustomSize(size * 1.4, forThreshold: MFSizeStandardiPadLandscapeThreshold) @@ -143,7 +103,7 @@ open class Styler { return sizeObject } - class func sizeFontGeneric(forCurrentDevice size: CGFloat) -> CGFloat { + open class func sizeFontGeneric(forCurrentDevice size: CGFloat) -> CGFloat { return sizeObjectGeneric(forCurrentDevice: size)?.getValueBasedOnApplicationWidth() ?? 0 } @@ -151,7 +111,7 @@ open class Styler { // MARK: - Spacing //-------------------------------------------------- - class func setDefaultMarginsFor(_ view: UIView?, size: CGFloat, horizontal: Bool = true, vertical: Bool = false) { + open class func setDefaultMarginsFor(_ view: UIView?, size: CGFloat, horizontal: Bool = true, vertical: Bool = false) { let horizontalPadding: CGFloat = horizontal ? Padding.Default.horizontalPadding(forSize: size) : 0 let verticalPadding: CGFloat = vertical ? PaddingDefaultVerticalSpacing3 : 0 @@ -161,7 +121,7 @@ open class Styler { } } - class func setMarginsFor(_ view: UIView?, size: CGFloat, defaultHorizontal horizontal: Bool, top: CGFloat, bottom: CGFloat) { + open class func setMarginsFor(_ view: UIView?, size: CGFloat, defaultHorizontal horizontal: Bool, top: CGFloat, bottom: CGFloat) { let horizontalPadding: CGFloat = horizontal ? Padding.Default.horizontalPadding(forSize: size) : 0 @@ -169,12 +129,8 @@ open class Styler { MVMCoreUIUtility.setMarginsFor(view, leading: horizontalPadding, top: top, trailing: horizontalPadding, bottom: bottom) } } - - //-------------------------------------------------- - // MARK: - 3.0 fonts - //-------------------------------------------------- - - class func getMVA3FontSize(_ size: CGFloat, bold isBold: Bool) -> UIFont { + + open class func getMVA3FontSize(_ size: CGFloat, bold isBold: Bool) -> UIFont { if isBold { return size >= 15 ? MFFonts.mfFontDSBold(size) : MFFonts.mfFontTXBold(size) @@ -183,118 +139,4 @@ open class Styler { return size >= 15 ? MFFonts.mfFontDSRegular(size) : MFFonts.mfFontTXRegular(size) } } - - //-------------------------------------------------- - // MARK: - Styles - //-------------------------------------------------- - - class func styleGetAlignCenteredAttrituedString(_ string: inout NSMutableAttributedString?) { - - if let string = string, string.length > 0 { - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.alignment = .center - string.addAttribute(.paragraphStyle, - value: paragraphStyle, - range: NSRange(location: 0, length: string.length)) - } - } - - class func styleGetBoldString(with inputFont: UIFont?, from inputString: String?) -> NSAttributedString? { - - let openingRange = (inputString as NSString?)?.range(of: "{") - let closingRange = (inputString as NSString?)?.range(of: "}") - let attrString = NSMutableAttributedString(string: inputString ?? "") - - if openingRange?.location != NSNotFound && closingRange?.location != NSNotFound { - let boldLength = (closingRange?.location ?? 0) - (openingRange?.location ?? 0) - if let inputFont = inputFont { - attrString.setAttributes([NSAttributedString.Key.font: inputFont], - range: NSRange(location: openingRange?.location ?? 0, - length: boldLength)) - } - - if let closingRange = closingRange { - attrString.replaceCharacters(in: closingRange, with: "") - } - - if let openingRange = openingRange { - attrString.replaceCharacters(in: openingRange, with: "") - } - } - - return attrString - } - - //-------------------------------------------------- - // MARK: - Gradient Colors - //-------------------------------------------------- - - class func gradientSpecialTicketGold() -> [AnyHashable] { - return [UIColor(red: 0.72, green: 0.6, blue: 0.33, alpha: 1), - UIColor(red: 1, green: 0.85, blue: 0.52, alpha: 1), - UIColor(red: 1, green: 0.85, blue: 0.52, alpha: 1), - UIColor(red: 1, green: 0.85, blue: 0.52, alpha: 1), - UIColor(red: 0.6, green: 0.42, blue: 0.07, alpha: 1)] - } - - class func gradientSpecialTicketGoldCGColor() -> [AnyHashable] { - return [UIColor(red: 0.72, green: 0.6, blue: 0.33, alpha: 1).cgColor, - UIColor(red: 1, green: 0.85, blue: 0.52, alpha: 1).cgColor, - UIColor(red: 1, green: 0.85, blue: 0.52, alpha: 1).cgColor, - UIColor(red: 1, green: 0.85, blue: 0.52, alpha: 1).cgColor, - UIColor(red: 0.6, green: 0.42, blue: 0.07, alpha: 1).cgColor].compactMap { $0 } - } - - class func styleGetLowCaseSpace(_ inputString: String?) -> String? { - - if (inputString?.count ?? 0) > 0 { - let trimmedString = inputString?.lowercased().trimmingCharacters(in: .whitespacesAndNewlines) - return trimmedString - } - - return "" - } - - class func labelStrokeAttributes(_ color: UIColor?) -> [AnyHashable: Any]? { - - guard let color = color else { return nil } - - return [NSAttributedString.Key.strokeColor: color, - NSAttributedString.Key.strokeWidth: -1.0] - } - - //-------------------------------------------------- - // MARK: - Custom Styling Views - //-------------------------------------------------- - - class func styleView(_ view: UIView, show border: MFViewBorder, with color: UIColor?, borderLineWidth: CGFloat, borderLineLength borderLineLengh: CGFloat) { - - let borderLine = UIView(frame: .zero) - borderLine.translatesAutoresizingMaskIntoConstraints = false - view.addSubview(borderLine) - - switch border { - case .top: - NSLayoutConstraint.constraintPinSubview(borderLine, pinTop: true, pinBottom: false, pinLeft: false, pinRight: false) - NSLayoutConstraint.constraintPinView(borderLine, heightConstraint: true, heightConstant: borderLineWidth, widthConstraint: true, widthConstant: borderLineLengh) - NSLayoutConstraint.constraintPinSubview(borderLine, pinCenterX: true, pinCenterY: false) - - case .left: - NSLayoutConstraint.constraintPinSubview(borderLine, pinTop: false, pinBottom: false, pinLeft: true, pinRight: false) - NSLayoutConstraint.constraintPinView(borderLine, heightConstraint: true, heightConstant: borderLineLengh, widthConstraint: true, widthConstant: borderLineWidth) - NSLayoutConstraint.constraintPinSubview(borderLine, pinCenterX: false, pinCenterY: true) - - case .bottom: - NSLayoutConstraint.constraintPinSubview(borderLine, pinTop: false, pinBottom: true, pinLeft: false, pinRight: false) - NSLayoutConstraint.constraintPinView(borderLine, heightConstraint: true, heightConstant: borderLineWidth, widthConstraint: true, widthConstant: borderLineLengh) - NSLayoutConstraint.constraintPinSubview(borderLine, pinCenterX: true, pinCenterY: false) - - case .right: - NSLayoutConstraint.constraintPinSubview(borderLine, pinTop: false, pinBottom: false, pinLeft: false, pinRight: true) - NSLayoutConstraint.constraintPinView(borderLine, heightConstraint: true, heightConstant: borderLineLengh, widthConstraint: true, widthConstant: borderLineWidth) - NSLayoutConstraint.constraintPinSubview(borderLine, pinCenterX: false, pinCenterY: true) - } - - borderLine.backgroundColor = color - } } diff --git a/MVMCoreUI/Styles/VogueProtocol.swift b/MVMCoreUI/Styles/VogueProtocol.swift new file mode 100644 index 00000000..1bd8e6a8 --- /dev/null +++ b/MVMCoreUI/Styles/VogueProtocol.swift @@ -0,0 +1,23 @@ +// +// VogueProtocol.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 4/1/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + + +public protocol VogueProtocol { + +} + +public protocol VogueViewProtocol { + +} + +public protocol VogueTextProtocol: VogueProtocol { + func styleFont(_ font: UIFont) + func styleTextColor(_ textColor: UIColor) +} From c26eea8cddd13666efad0cb8eaca40a94c0a9baf Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 1 Apr 2020 17:12:26 -0400 Subject: [PATCH 07/62] small change --- MVMCoreUI/Styles/Styler.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift index 62af40fe..75d81b89 100644 --- a/MVMCoreUI/Styles/Styler.swift +++ b/MVMCoreUI/Styles/Styler.swift @@ -81,7 +81,7 @@ open class Styler { public func getFont(_ genericScaling: Bool = true) -> UIFont? { let size = genericScaling ? sizeFontGeneric(forCurrentDevice: pointSize()) : pointSize() - return getMVA3FontSize(size, bold: isBold()) + return getMVA3FontSize(size, isBold: isBold()) } public func styleLabel(_ label: UILabel, genericScaling: Bool = true) { @@ -130,7 +130,7 @@ open class Styler { } } - open class func getMVA3FontSize(_ size: CGFloat, bold isBold: Bool) -> UIFont { + open class func getMVA3FontSize(_ size: CGFloat, isBold: Bool) -> UIFont { if isBold { return size >= 15 ? MFFonts.mfFontDSBold(size) : MFFonts.mfFontTXBold(size) From c723d96cbf470870dc62e8978d01df411f082140 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 2 Apr 2020 08:48:24 -0400 Subject: [PATCH 08/62] removed comment --- MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift | 2 -- 1 file changed, 2 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift index e74e57de..a630f63a 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift @@ -760,8 +760,6 @@ public typealias ActionBlock = () -> () */ static func getTextAttachmentImage(name: String = "externalLink", dimension: CGFloat) -> NSTextAttachment { -// let dimension = round(dimension * 0.8) - let imageAttachment = NSTextAttachment() imageAttachment.image = MVMCoreUIUtility.imageNamed(name) imageAttachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension) From 8788d98323186ac52a025bbaafb058ddb5e4a21f Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 2 Apr 2020 11:20:17 -0400 Subject: [PATCH 09/62] updates --- MVMCoreUI/Styles/Padding.swift | 5 +---- MVMCoreUI/Styles/Styler.swift | 2 +- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Styles/Padding.swift b/MVMCoreUI/Styles/Padding.swift index bdd65837..b47a64c5 100644 --- a/MVMCoreUI/Styles/Padding.swift +++ b/MVMCoreUI/Styles/Padding.swift @@ -24,7 +24,6 @@ public struct Padding { public static let TableCellParagraphSpace: CGFloat = 3 public static let FooterLabelParagraphSpace: CGFloat = 4 - public static let WebViewInset: CGFloat = 8 public static let HeightTableSeperatorHeight: CGFloat = 1 public static let MFHeightForSwitch: CGFloat = 22 public static let MFWidthForSwitch: CGFloat = 42 @@ -33,9 +32,7 @@ public struct Padding { public static let MinCellHeight: CGFloat = 96 public static let HeightIphone5: CGFloat = 568 public static let DefaultOptionCellHeight: CGFloat = 120 - public static let PromoViewHeight: CGFloat = 41.9 public static let BetweenFields: CGFloat = 24 - public static let LabelWithInternalButtonLineSpace: CGFloat = 2 public static let PrimaryButtonTop: CGFloat = 36 public struct Default { @@ -45,7 +42,7 @@ public struct Padding { public static let VerticalSpacing3: CGFloat = 24 public static var HorizontalPaddingForApplicationWidth: CGFloat { - return MFSizeObject(scalingStandardSize: PaddingDefaultHorizontalSpacing)?.getValueBasedOnApplicationWidth() ?? 0 + return MFSizeObject(scalingStandardSize: PaddingDefaultHorizontalSpacing)?.getValueBasedOnApplicationWidth() ?? HorizontalSpacing } public static var VerticalPaddingForApplicationWidth: CGFloat { diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift index 75d81b89..46210b9c 100644 --- a/MVMCoreUI/Styles/Styler.swift +++ b/MVMCoreUI/Styles/Styler.swift @@ -104,7 +104,7 @@ open class Styler { } open class func sizeFontGeneric(forCurrentDevice size: CGFloat) -> CGFloat { - return sizeObjectGeneric(forCurrentDevice: size)?.getValueBasedOnApplicationWidth() ?? 0 + return sizeObjectGeneric(forCurrentDevice: size)?.getValueBasedOnApplicationWidth() ?? size } //-------------------------------------------------- From c9bb3ce1f389553ae05be14af7b42cf1c4aeac1b Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 2 Apr 2020 17:16:04 -0400 Subject: [PATCH 10/62] including 2.0 legacy as it's being used in some molecular at the moment. --- .../Views/Label/LabelAttributeFontModel.swift | 4 +- .../Atomic/Atoms/Views/Label/LabelModel.swift | 29 +---- MVMCoreUI/Styles/Styler.swift | 104 +++++++++++++++--- 3 files changed, 90 insertions(+), 47 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeFontModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeFontModel.swift index 437bb6f8..862f8f9b 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeFontModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelAttributeFontModel.swift @@ -18,7 +18,7 @@ import UIKit return "font" } - var style: LabelModel.FontStyle? + var style: Styler.Font? var name: String? var size: CGFloat? @@ -38,7 +38,7 @@ import UIKit required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - style = try typeContainer.decodeIfPresent(LabelModel.FontStyle.self, forKey: .style) + style = try typeContainer.decodeIfPresent(Styler.Font.self, forKey: .style) name = try typeContainer.decodeIfPresent(String.self, forKey: .name) size = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .size) try super.init(from: decoder) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift index 74e6efa4..4ec23ad6 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift @@ -10,31 +10,6 @@ import Foundation @objcMembers public class LabelModel: MoleculeModelProtocol { - - public enum FontStyle: String, Codable { - case Title2XLarge - case TitleXLarge - case BoldTitleLarge - case RegularTitleLarge - case BoldTitleMedium - case RegularTitleMedium - case BoldBodyLarge - case RegularBodyLarge - case BoldBodySmall - case RegularBodySmall - case BoldMicro - case RegularMicro - // Legacy - case H1 - case H2 - case H3 - case H32 - case B1 - case B2 - case B3 - case B20 - } - //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -44,7 +19,7 @@ import Foundation public var text: String public var accessibilityText: String? public var textColor: Color? - public var fontStyle: FontStyle? + public var fontStyle: Styler.Font? public var fontName: String? public var fontSize: CGFloat? public var textAlignment: NSTextAlignment? @@ -95,7 +70,7 @@ import Foundation accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText) textColor = try typeContainer.decodeIfPresent(Color.self, forKey: .textColor) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) - fontStyle = try typeContainer.decodeIfPresent(FontStyle.self, forKey: .fontStyle) + fontStyle = try typeContainer.decodeIfPresent(Styler.Font.self, forKey: .fontStyle) fontName = try typeContainer.decodeIfPresent(String.self, forKey: .fontName) fontSize = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .fontSize) textAlignment = try typeContainer.decodeIfPresent(NSTextAlignment.self, forKey: .textAlignment) diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift index 46210b9c..57b0ad18 100644 --- a/MVMCoreUI/Styles/Styler.swift +++ b/MVMCoreUI/Styles/Styler.swift @@ -14,7 +14,7 @@ open class Styler { // MARK: - Enums //-------------------------------------------------- - public enum Font: String { + public enum Font: String, Codable { case Title2XLarge case TitleXLarge case BoldTitleLarge @@ -28,31 +28,56 @@ open class Styler { case BoldMicro case RegularMicro + // Legacy Fonts + case H1 + case H2 + case H3 + case H32 + case B1 + case B2 + case B3 + case B20 + public func pointSize() -> CGFloat { switch self { + case .H1: + return 40 + case .Title2XLarge: return 36 - case .TitleXLarge: + case .TitleXLarge, + .H32: return 32 + case .H2: + return 25 + case .BoldTitleLarge, .RegularTitleLarge: return 24 case .BoldTitleMedium, - .RegularTitleMedium: + .RegularTitleMedium, + .B20: return 20 + case .H3: + return 18 + case .BoldBodyLarge, .RegularBodyLarge: return 16 case .BoldBodySmall, - .RegularBodySmall: + .RegularBodySmall, + .B1, + .B2: return 13 - case .BoldMicro, .RegularMicro: + case .BoldMicro, + .RegularMicro, + .B3: return 11 } } @@ -66,14 +91,51 @@ open class Styler { .RegularTitleMedium, .RegularBodyLarge, .RegularBodySmall, - .RegularMicro: + .RegularMicro, + .B2, + .B3, + .B20: return false case .BoldTitleLarge, + .BoldTitleMedium, + .BoldBodyLarge, + .BoldBodySmall, + .BoldMicro, + .H1, + .H2, + .H3, + .H32, + .B1: + return true + } + } + + public func isLegacyFont() -> Bool { + + switch self { + case .Title2XLarge, + .TitleXLarge, + .RegularTitleLarge, + .RegularTitleMedium, + .RegularBodyLarge, + .RegularBodySmall, + .RegularMicro, + .BoldTitleLarge, .BoldTitleMedium, .BoldBodyLarge, .BoldBodySmall, .BoldMicro: + return false + + case .H1, + .H2, + .H3, + .H32, + .B1, + .B2, + .B3, + .B20: return true } } @@ -81,7 +143,23 @@ open class Styler { public func getFont(_ genericScaling: Bool = true) -> UIFont? { let size = genericScaling ? sizeFontGeneric(forCurrentDevice: pointSize()) : pointSize() - return getMVA3FontSize(size, isBold: isBold()) + + if isLegacyFont() { + switch self { + case .B2, .B3, .B20: + return MFFonts.mfFont55Rg(size) + + default: + return MFFonts.mfFont75Bd(size) + } + } else { + if isBold() { + return size >= 15 ? MFFonts.mfFontDSBold(size) : MFFonts.mfFontTXBold(size) + + } else { + return size >= 15 ? MFFonts.mfFontDSRegular(size) : MFFonts.mfFontTXRegular(size) + } + } } public func styleLabel(_ label: UILabel, genericScaling: Bool = true) { @@ -90,7 +168,7 @@ open class Styler { label.textColor = .black } } - + //-------------------------------------------------- // MARK: - Functions //-------------------------------------------------- @@ -129,14 +207,4 @@ open class Styler { MVMCoreUIUtility.setMarginsFor(view, leading: horizontalPadding, top: top, trailing: horizontalPadding, bottom: bottom) } } - - open class func getMVA3FontSize(_ size: CGFloat, isBold: Bool) -> UIFont { - - if isBold { - return size >= 15 ? MFFonts.mfFontDSBold(size) : MFFonts.mfFontTXBold(size) - - } else { - return size >= 15 ? MFFonts.mfFontDSRegular(size) : MFFonts.mfFontTXRegular(size) - } - } } From de6fe50c82776cef7d13c0ec3e922730d1349de8 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 3 Apr 2020 11:19:51 -0400 Subject: [PATCH 11/62] updates --- MVMCoreUI.xcodeproj/project.pbxproj | 12 +++------ MVMCoreUI/Styles/Padding.swift | 37 +++++----------------------- MVMCoreUI/Styles/Styler.swift | 17 ++++++++++--- MVMCoreUI/Styles/VogueProtocol.swift | 23 ----------------- 4 files changed, 23 insertions(+), 66 deletions(-) delete mode 100644 MVMCoreUI/Styles/VogueProtocol.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 2679f3f0..f7bdfec3 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -85,11 +85,10 @@ 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */; }; 0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */; }; 0A5D59C223AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */; }; - 0A6682AA2435125F00AD3CA1 /* Styler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682A92435125F00AD3CA1 /* Styler.swift */; }; - 0A6682AC243531C300AD3CA1 /* Padding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682AB243531C300AD3CA1 /* Padding.swift */; }; - 0A6682AE243538DB00AD3CA1 /* VogueProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682AD243538DB00AD3CA1 /* VogueProtocol.swift */; }; 0A6682A22434DB4F00AD3CA1 /* ListLeftVariableRadioButtonBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682A12434DB4F00AD3CA1 /* ListLeftVariableRadioButtonBodyText.swift */; }; 0A6682A42434DB8D00AD3CA1 /* ListLeftVariableRadioButtonBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682A32434DB8D00AD3CA1 /* ListLeftVariableRadioButtonBodyTextModel.swift */; }; + 0A6682AA2435125F00AD3CA1 /* Styler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682A92435125F00AD3CA1 /* Styler.swift */; }; + 0A6682AC243531C300AD3CA1 /* Padding.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6682AB243531C300AD3CA1 /* Padding.swift */; }; 0A69F611241BDEA700F7231B /* RuleAnyRequiredModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */; }; 0A6BF4722360C56C0028F841 /* BaseDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */; }; 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; }; @@ -479,11 +478,10 @@ 0A41BA6D2344FCD400D4C0BC /* CATransaction+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CATransaction+Extension.swift"; sourceTree = ""; }; 0A41BA7E23453A6400D4C0BC /* TextEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryField.swift; sourceTree = ""; }; 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppleGuidelinesProtocol.swift; sourceTree = ""; }; - 0A6682A92435125F00AD3CA1 /* Styler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Styler.swift; sourceTree = ""; }; - 0A6682AB243531C300AD3CA1 /* Padding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Padding.swift; sourceTree = ""; }; - 0A6682AD243538DB00AD3CA1 /* VogueProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VogueProtocol.swift; sourceTree = ""; }; 0A6682A12434DB4F00AD3CA1 /* ListLeftVariableRadioButtonBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonBodyText.swift; sourceTree = ""; }; 0A6682A32434DB8D00AD3CA1 /* ListLeftVariableRadioButtonBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableRadioButtonBodyTextModel.swift; sourceTree = ""; }; + 0A6682A92435125F00AD3CA1 /* Styler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Styler.swift; sourceTree = ""; }; + 0A6682AB243531C300AD3CA1 /* Padding.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Padding.swift; sourceTree = ""; }; 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyRequiredModel.swift; sourceTree = ""; }; 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseDropdownEntryField.swift; sourceTree = ""; }; 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = ""; }; @@ -1490,7 +1488,6 @@ D29DF13921E68637003B2FB9 /* MFStyler.m */, 0A6682A92435125F00AD3CA1 /* Styler.swift */, 0A6682AB243531C300AD3CA1 /* Padding.swift */, - 0A6682AD243538DB00AD3CA1 /* VogueProtocol.swift */, ); path = Styles; sourceTree = ""; @@ -2029,7 +2026,6 @@ AA11A42123F15D7000D7962F /* ListRightVariablePaymentsModel.swift in Sources */, 01EB369223609801006832FA /* MoleculeStackModel.swift in Sources */, 011D9626240EBB16000E3791 /* RadioButtonLabelModel.swift in Sources */, - 0A6682AE243538DB00AD3CA1 /* VogueProtocol.swift in Sources */, AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */, D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */, 944589232385DA9600DE9FD4 /* ImageViewModel.swift in Sources */, diff --git a/MVMCoreUI/Styles/Padding.swift b/MVMCoreUI/Styles/Padding.swift index b47a64c5..1c3bba53 100644 --- a/MVMCoreUI/Styles/Padding.swift +++ b/MVMCoreUI/Styles/Padding.swift @@ -22,50 +22,25 @@ public struct Padding { public static let Nine: CGFloat = 54 public static let Ten: CGFloat = 60 - public static let TableCellParagraphSpace: CGFloat = 3 - public static let FooterLabelParagraphSpace: CGFloat = 4 - public static let HeightTableSeperatorHeight: CGFloat = 1 - public static let MFHeightForSwitch: CGFloat = 22 - public static let MFWidthForSwitch: CGFloat = 42 - public static let DisableOppacity: CGFloat = 0.5 - public static let PaymentMethodViewHeightWidthMultiplier: CGFloat = 0.55 - public static let MinCellHeight: CGFloat = 96 - public static let HeightIphone5: CGFloat = 568 - public static let DefaultOptionCellHeight: CGFloat = 120 - public static let BetweenFields: CGFloat = 24 - public static let PrimaryButtonTop: CGFloat = 36 - public struct Default { public static let Standard: CGFloat = 24 public static let HorizontalSpacing: CGFloat = 32 public static let VerticalSpacing: CGFloat = 32 - public static let VerticalSpacing3: CGFloat = 24 public static var HorizontalPaddingForApplicationWidth: CGFloat { - return MFSizeObject(scalingStandardSize: PaddingDefaultHorizontalSpacing)?.getValueBasedOnApplicationWidth() ?? HorizontalSpacing + return MFSizeObject(scalingStandardSize: HorizontalSpacing)?.getValueBasedOnApplicationWidth() ?? HorizontalSpacing } public static var VerticalPaddingForApplicationWidth: CGFloat { - return MFSizeObject(scalingStandardSize: PaddingDefaultVerticalSpacing)?.getValueBasedOnApplicationWidth() ?? 0 + return MFSizeObject(scalingStandardSize: VerticalSpacing)?.getValueBasedOnApplicationWidth() ?? VerticalSpacing } - public static func horizontalPadding(forSize size: CGFloat) -> CGFloat { - return MFSizeObject(scalingStandardSize: PaddingDefaultHorizontalSpacing)?.getValueBased(onSize: size) ?? 0 + public static func horizontalPaddingForSize(_ size: CGFloat) -> CGFloat { + return MFSizeObject(scalingStandardSize: HorizontalSpacing)?.getValueBased(onSize: size) ?? VerticalSpacing } - public static func verticalPadding(forSize size: CGFloat) -> CGFloat { - return MFSizeObject(scalingStandardSize: PaddingDefaultVerticalSpacing)?.getValueBased(onSize: size) ?? 0 + public static func verticalPaddingForSize(_ size: CGFloat) -> CGFloat { + return MFSizeObject(scalingStandardSize: VerticalSpacing)?.getValueBased(onSize: size) ?? VerticalSpacing } } - - public struct Horizontal { - public static let HeadlineWhiteView: CGFloat = 60 - public static let Large: CGFloat = 72 - public static let BetweenRelatedItems: CGFloat = 16 - } - - public struct Vertical { - public static let WhiteGrayView: CGFloat = 72 - public static let HeadlineAlternate: CGFloat = 48 - } } diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift index 57b0ad18..06a4b41f 100644 --- a/MVMCoreUI/Styles/Styler.swift +++ b/MVMCoreUI/Styles/Styler.swift @@ -178,6 +178,7 @@ open class Styler { let sizeObject = MFSizeObject(standardSize: size, standardiPadPortraitSize: size * 1.3) sizeObject?.addLargerThanCustomSize(size * 1.4, forThreshold: MFSizeStandardiPadLandscapeThreshold) sizeObject?.addLargerThanCustomSize(size * 1.5, forThreshold: MFSizeiPadProLandscapeThreshold) + return sizeObject } @@ -191,20 +192,28 @@ open class Styler { open class func setDefaultMarginsFor(_ view: UIView?, size: CGFloat, horizontal: Bool = true, vertical: Bool = false) { - let horizontalPadding: CGFloat = horizontal ? Padding.Default.horizontalPadding(forSize: size) : 0 + let horizontalPadding: CGFloat = horizontal ? Padding.Default.horizontalPaddingForSize(size) : 0 let verticalPadding: CGFloat = vertical ? PaddingDefaultVerticalSpacing3 : 0 DispatchQueue.main.async { - MVMCoreUIUtility.setMarginsFor(view, leading: horizontalPadding, top: verticalPadding, trailing: horizontalPadding, bottom: verticalPadding) + MVMCoreUIUtility.setMarginsFor(view, + leading: horizontalPadding, + top: verticalPadding, + trailing: horizontalPadding, + bottom: verticalPadding) } } open class func setMarginsFor(_ view: UIView?, size: CGFloat, defaultHorizontal horizontal: Bool, top: CGFloat, bottom: CGFloat) { - let horizontalPadding: CGFloat = horizontal ? Padding.Default.horizontalPadding(forSize: size) : 0 + let horizontalPadding: CGFloat = horizontal ? Padding.Default.horizontalPaddingForSize(size) : 0 DispatchQueue.main.async { - MVMCoreUIUtility.setMarginsFor(view, leading: horizontalPadding, top: top, trailing: horizontalPadding, bottom: bottom) + MVMCoreUIUtility.setMarginsFor(view, + leading: horizontalPadding, + top: top, + trailing: horizontalPadding, + bottom: bottom) } } } diff --git a/MVMCoreUI/Styles/VogueProtocol.swift b/MVMCoreUI/Styles/VogueProtocol.swift deleted file mode 100644 index 1bd8e6a8..00000000 --- a/MVMCoreUI/Styles/VogueProtocol.swift +++ /dev/null @@ -1,23 +0,0 @@ -// -// VogueProtocol.swift -// MVMCoreUI -// -// Created by Kevin Christiano on 4/1/20. -// Copyright © 2020 Verizon Wireless. All rights reserved. -// - -import Foundation - - -public protocol VogueProtocol { - -} - -public protocol VogueViewProtocol { - -} - -public protocol VogueTextProtocol: VogueProtocol { - func styleFont(_ font: UIFont) - func styleTextColor(_ textColor: UIColor) -} From c0d85694c68269980e578917edcfdeeac048a26f Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 3 Apr 2020 11:25:29 -0400 Subject: [PATCH 12/62] more updates --- MVMCoreUI/Styles/Styler.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift index 06a4b41f..24a1d94c 100644 --- a/MVMCoreUI/Styles/Styler.swift +++ b/MVMCoreUI/Styles/Styler.swift @@ -162,6 +162,7 @@ open class Styler { } } + /// Styles the provided label to the declared enum Font case. public func styleLabel(_ label: UILabel, genericScaling: Bool = true) { label.font = getFont(genericScaling) From cf6db73acbdf05cfa45789725c1f3e6a60cd2d22 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 3 Apr 2020 11:28:05 -0400 Subject: [PATCH 13/62] comments --- MVMCoreUI/Styles/Styler.swift | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift index 24a1d94c..2815873b 100644 --- a/MVMCoreUI/Styles/Styler.swift +++ b/MVMCoreUI/Styles/Styler.swift @@ -38,6 +38,7 @@ open class Styler { case B3 case B20 + /// Returns the font size of the current enum case. public func pointSize() -> CGFloat { switch self { case .H1: @@ -82,6 +83,7 @@ open class Styler { } } + /// Determines if the selected font case is bold or regular. public func isBold() -> Bool { switch self { @@ -111,6 +113,7 @@ open class Styler { } } + /// Determines if the current enum is a legacy or modern font. public func isLegacyFont() -> Bool { switch self { @@ -140,6 +143,7 @@ open class Styler { } } + /// Returns the font based on the declared enum case. public func getFont(_ genericScaling: Bool = true) -> UIFont? { let size = genericScaling ? sizeFontGeneric(forCurrentDevice: pointSize()) : pointSize() From 1331c34579ccb8ce23425b3ad22d5c6cb2fca7e5 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 3 Apr 2020 13:10:14 -0400 Subject: [PATCH 14/62] changes made --- MVMCoreUI/Styles/Padding.swift | 3 ++- MVMCoreUI/Styles/Styler.swift | 10 +++++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Styles/Padding.swift b/MVMCoreUI/Styles/Padding.swift index 1c3bba53..6ef0cc62 100644 --- a/MVMCoreUI/Styles/Padding.swift +++ b/MVMCoreUI/Styles/Padding.swift @@ -26,6 +26,7 @@ public struct Padding { public static let Standard: CGFloat = 24 public static let HorizontalSpacing: CGFloat = 32 public static let VerticalSpacing: CGFloat = 32 + public static let VerticalSpacing3: CGFloat = 24 public static var HorizontalPaddingForApplicationWidth: CGFloat { return MFSizeObject(scalingStandardSize: HorizontalSpacing)?.getValueBasedOnApplicationWidth() ?? HorizontalSpacing @@ -36,7 +37,7 @@ public struct Padding { } public static func horizontalPaddingForSize(_ size: CGFloat) -> CGFloat { - return MFSizeObject(scalingStandardSize: HorizontalSpacing)?.getValueBased(onSize: size) ?? VerticalSpacing + return MFSizeObject(scalingStandardSize: HorizontalSpacing)?.getValueBased(onSize: size) ?? HorizontalSpacing } public static func verticalPaddingForSize(_ size: CGFloat) -> CGFloat { diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift index 2815873b..75d0b9ee 100644 --- a/MVMCoreUI/Styles/Styler.swift +++ b/MVMCoreUI/Styles/Styler.swift @@ -195,10 +195,14 @@ open class Styler { // MARK: - Spacing //-------------------------------------------------- - open class func setDefaultMarginsFor(_ view: UIView?, size: CGFloat, horizontal: Bool = true, vertical: Bool = false) { + open class func setDefaultMarginsFor(_ view: UIView?, size: CGFloat?, horizontal: Bool = true, vertical: Bool = false) { - let horizontalPadding: CGFloat = horizontal ? Padding.Default.horizontalPaddingForSize(size) : 0 - let verticalPadding: CGFloat = vertical ? PaddingDefaultVerticalSpacing3 : 0 + var horizontalPadding: CGFloat = Padding.Default.HorizontalSpacing + let verticalPadding: CGFloat = vertical ? Padding.Default.VerticalSpacing3 : 0 + + if let size = size { + horizontalPadding = horizontal ? Padding.Default.horizontalPaddingForSize(size) : 0 + } DispatchQueue.main.async { MVMCoreUIUtility.setMarginsFor(view, From e4f561ca7d0aca90d99d96081d31e7e607b439cf Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Fri, 3 Apr 2020 13:16:50 -0400 Subject: [PATCH 15/62] lowercasd --- MVMCoreUI/Styles/Padding.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Styles/Padding.swift b/MVMCoreUI/Styles/Padding.swift index 6ef0cc62..ca99d5dc 100644 --- a/MVMCoreUI/Styles/Padding.swift +++ b/MVMCoreUI/Styles/Padding.swift @@ -28,11 +28,11 @@ public struct Padding { public static let VerticalSpacing: CGFloat = 32 public static let VerticalSpacing3: CGFloat = 24 - public static var HorizontalPaddingForApplicationWidth: CGFloat { + public static var horizontalPaddingForApplicationWidth: CGFloat { return MFSizeObject(scalingStandardSize: HorizontalSpacing)?.getValueBasedOnApplicationWidth() ?? HorizontalSpacing } - public static var VerticalPaddingForApplicationWidth: CGFloat { + public static var verticalPaddingForApplicationWidth: CGFloat { return MFSizeObject(scalingStandardSize: VerticalSpacing)?.getValueBasedOnApplicationWidth() ?? VerticalSpacing } From 29805d347a7e38c1a265a3e1a8c1e51cdfd15418 Mon Sep 17 00:00:00 2001 From: "Xinlei(Ryan) Pan" Date: Fri, 3 Apr 2020 14:41:22 -0400 Subject: [PATCH 16/62] use new font for legacy --- MVMCoreUI/Utility/MFFonts.m | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Utility/MFFonts.m b/MVMCoreUI/Utility/MFFonts.m index 533b3a87..24c62a9a 100644 --- a/MVMCoreUI/Utility/MFFonts.m +++ b/MVMCoreUI/Utility/MFFonts.m @@ -85,14 +85,20 @@ NSString * const DS55Rg = @"NHaasGroteskDSStd-55Rg"; + (nonnull UIFont *)mfFont75Bd:(CGFloat)size { [self loadMVMFonts]; - UIFont *font = [UIFont fontWithName:DS75Bd size:size]; - return font ?: [UIFont boldSystemFontOfSize:size]; + if (size >= 15) { + return [MFFonts mfFontDSBold:size]; + } else { + return [MFFonts mfFontTXBold:size]; + } } + (nonnull UIFont *)mfFont55Rg:(CGFloat)size { [self loadMVMFonts]; - UIFont *font = [UIFont fontWithName:DS55Rg size:size]; - return font ?: [UIFont systemFontOfSize:size]; + if (size >= 15) { + return [MFFonts mfFontDSRegular:size]; + } else { + return [MFFonts mfFontTXRegular:size]; + } } + (nullable UIFont *)mfFontOcratxt:(CGFloat)size { From 9f07e155789fe497fc78aebffbf647e3428d4852 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 6 Apr 2020 14:31:53 -0400 Subject: [PATCH 17/62] color added. --- MVMCoreUI/Categories/UIColor+MFConvenience.h | 1 + MVMCoreUI/Categories/UIColor+MFConvenience.m | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/MVMCoreUI/Categories/UIColor+MFConvenience.h b/MVMCoreUI/Categories/UIColor+MFConvenience.h index c3c78c7a..92b28a36 100644 --- a/MVMCoreUI/Categories/UIColor+MFConvenience.h +++ b/MVMCoreUI/Categories/UIColor+MFConvenience.h @@ -24,6 +24,7 @@ + (nonnull UIColor *)mvmOrange; + (nonnull UIColor *)mfPumpkinColor; + (nonnull UIColor *)mfShamrock; ++ (nonnull UIColor *)mvmGreen; + (nonnull UIColor *)mfCerulean; + (nonnull UIColor *)mfWhiteTwo; diff --git a/MVMCoreUI/Categories/UIColor+MFConvenience.m b/MVMCoreUI/Categories/UIColor+MFConvenience.m index 6ff8f70f..33df3848 100644 --- a/MVMCoreUI/Categories/UIColor+MFConvenience.m +++ b/MVMCoreUI/Categories/UIColor+MFConvenience.m @@ -61,6 +61,10 @@ return [UIColor mfColor8bitsWithRed:0 green:134 blue:49 alpha:1.0]; } ++ (nonnull UIColor *)mvmGreen { + return [UIColor mfColor8bitsWithRed:0 green:134 blue:48 alpha:1.0]; +} + + (nonnull UIColor *)mfCerulean { return [UIColor mfColor8bitsWithRed:0 green:122 blue:184 alpha:1.0]; } From 7a221da7ba330d8e5cb5ee5eb97560f7704b6277 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Mon, 6 Apr 2020 14:32:55 -0400 Subject: [PATCH 18/62] asd --- MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m index 930828f6..4e79ee6f 100644 --- a/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m +++ b/MVMCoreUI/TopAlert/MVMCoreUITopAlertView.m @@ -117,7 +117,7 @@ NSString * const MFAccTopAlertClosed = @"Top alert notification is closed."; if ([type isEqualToString:ValueTypeError]) { return [UIColor mvmOrange]; } else { - return [UIColor mfShamrock]; + return [UIColor mvmGreen]; } } From b0be1dbce3de6a9f8f0e979dfd9ebd79619c4a9d Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 7 Apr 2020 10:08:07 -0400 Subject: [PATCH 19/62] Collection changes --- MVMCoreUI.xcodeproj/project.pbxproj | 32 +- .../Molecules/Items/CarouselItemModel.swift | 12 +- .../Items/CollectionItemModelProtocol.swift | 13 + .../Items/MoleculeCollectionItemModel.swift | 66 ++++ .../Items/MoleculeCollectionViewCell.swift | 133 ++------ MVMCoreUI/Atomic/Organisms/Carousel.swift | 30 +- .../Atomic/Organisms/CarouselModel.swift | 14 +- .../CarouselPagingModelProtocol.swift | 2 +- .../Atomic/Templates/CollectionTemplate.swift | 15 + .../Templates/CollectionTemplateModel.swift | 67 ++++ .../Atomic/Templates/ThreeLayerTemplate.swift | 4 - .../BaseClasses/CollectionViewCell.swift | 77 +++++ .../ThreeLayerCollectionViewController.swift | 289 ++++++++++++++++++ .../MVMCoreUIViewControllerMappingObject.m | 3 +- 14 files changed, 613 insertions(+), 144 deletions(-) create mode 100644 MVMCoreUI/Atomic/Molecules/Items/CollectionItemModelProtocol.swift create mode 100644 MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift create mode 100644 MVMCoreUI/Atomic/Templates/CollectionTemplate.swift create mode 100644 MVMCoreUI/Atomic/Templates/CollectionTemplateModel.swift create mode 100644 MVMCoreUI/BaseClasses/CollectionViewCell.swift create mode 100644 MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index c0a56ebc..e1310f0d 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -210,6 +210,10 @@ D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; }; D20FB165241A5D75004AFC3A /* NavigationItemModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20FB164241A5D75004AFC3A /* NavigationItemModelProtocol.swift */; }; D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; }; + D21B7F71243BAC1600051ABF /* CollectionViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21B7F70243BAC1600051ABF /* CollectionViewCell.swift */; }; + D21B7F73243BAC6800051ABF /* CollectionItemModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21B7F72243BAC6800051ABF /* CollectionItemModelProtocol.swift */; }; + D21B7F75243BAC8900051ABF /* CarouselItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21B7F74243BAC8900051ABF /* CarouselItem.swift */; }; + D21B7F77243BB70700051ABF /* MoleculeCollectionItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21B7F76243BB70700051ABF /* MoleculeCollectionItemModel.swift */; }; D21EE53C23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */; }; D224798A2314445E003FCCF9 /* LabelToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D22479892314445E003FCCF9 /* LabelToggle.swift */; }; D224798C231450C8003FCCF9 /* HeadlineBodyToggle.swift in Sources */ = {isa = PBXBuildFile; fileRef = D224798B231450C8003FCCF9 /* HeadlineBodyToggle.swift */; }; @@ -242,6 +246,9 @@ D260D7B122D65BDD007E7233 /* MVMCoreUIPageControl.h in Headers */ = {isa = PBXBuildFile; fileRef = D260D7AF22D65BDD007E7233 /* MVMCoreUIPageControl.h */; settings = {ATTRIBUTES = (Public, ); }; }; 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, ); }; }; + D264FA8C243BCD8E00D98315 /* CollectionTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FA8B243BCD8E00D98315 /* CollectionTemplateModel.swift */; }; + D264FA8E243BCD9A00D98315 /* CollectionTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FA8D243BCD9A00D98315 /* CollectionTemplate.swift */; }; + D264FA90243BCE6800D98315 /* ThreeLayerCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FA8F243BCE6800D98315 /* ThreeLayerCollectionViewController.swift */; }; D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368A23609801006832FA /* MoleculeStackItemModel.swift */; }; D268C70E238C22D7007F2C1C /* DropDownFilterTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */; }; D26C5A6B23F4A40D007AEECE /* ListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */; }; @@ -608,6 +615,10 @@ D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = ""; }; D20FB164241A5D75004AFC3A /* NavigationItemModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItemModelProtocol.swift; sourceTree = ""; }; D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; + D21B7F70243BAC1600051ABF /* CollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionViewCell.swift; sourceTree = ""; }; + D21B7F72243BAC6800051ABF /* CollectionItemModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionItemModelProtocol.swift; sourceTree = ""; }; + D21B7F74243BAC8900051ABF /* CarouselItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CarouselItem.swift; sourceTree = ""; }; + D21B7F76243BB70700051ABF /* MoleculeCollectionItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeCollectionItemModel.swift; sourceTree = ""; }; D21EE53B23AD3AD4003D1A30 /* NSLayoutConstraintAxis+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NSLayoutConstraintAxis+Extension.swift"; sourceTree = ""; }; D22479892314445E003FCCF9 /* LabelToggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LabelToggle.swift; sourceTree = ""; }; D224798B231450C8003FCCF9 /* HeadlineBodyToggle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyToggle.swift; sourceTree = ""; }; @@ -640,6 +651,9 @@ D260D7AF22D65BDD007E7233 /* MVMCoreUIPageControl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MVMCoreUIPageControl.h; sourceTree = ""; }; 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 = ""; }; + D264FA8B243BCD8E00D98315 /* CollectionTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionTemplateModel.swift; sourceTree = ""; }; + D264FA8D243BCD9A00D98315 /* CollectionTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionTemplate.swift; sourceTree = ""; }; + D264FA8F243BCE6800D98315 /* ThreeLayerCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerCollectionViewController.swift; sourceTree = ""; }; D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropDownFilterTableViewCell.swift; sourceTree = ""; }; D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemModel.swift; sourceTree = ""; }; D274CA322236A78900B01B62 /* FooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FooterView.swift; sourceTree = ""; }; @@ -1236,8 +1250,6 @@ D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */, 01EB368923609801006832FA /* MoleculeListItemModel.swift */, 01509D8E2327EC6F00EF99AA /* MoleculeTableViewCell.swift */, - 012A88C1238D7BCA00FE3DA1 /* CarouselItemModel.swift */, - D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */, D28A838023CCB0D800DFE4FC /* AccordionListItemModel.swift */, D224799A231965AD003FCCF9 /* AccordionMoleculeTableViewCell.swift */, D28A837C23CCA86A00DFE4FC /* TabsListItemModel.swift */, @@ -1249,6 +1261,11 @@ D260105E23D0BFFC00764D80 /* StackItem.swift */, 01EB368A23609801006832FA /* MoleculeStackItemModel.swift */, D2FB151C23A40F1500C20E10 /* MoleculeStackItem.swift */, + D21B7F72243BAC6800051ABF /* CollectionItemModelProtocol.swift */, + D21B7F76243BB70700051ABF /* MoleculeCollectionItemModel.swift */, + D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */, + 012A88C1238D7BCA00FE3DA1 /* CarouselItemModel.swift */, + D21B7F74243BAC8900051ABF /* CarouselItem.swift */, ); path = Items; sourceTree = ""; @@ -1403,6 +1420,8 @@ 942C378B2412F4FA0066E45E /* ModalMoleculeListTemplate.swift */, 014AA72A23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift */, D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */, + D264FA8B243BCD8E00D98315 /* CollectionTemplateModel.swift */, + D264FA8D243BCD9A00D98315 /* CollectionTemplate.swift */, ); path = Templates; sourceTree = ""; @@ -1458,6 +1477,7 @@ D29DF2CD21E7C104003B2FB9 /* MFLoadingViewController.m */, D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */, D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */, + D264FA8F243BCE6800D98315 /* ThreeLayerCollectionViewController.swift */, D2C521A823EDE79E00CA2634 /* ViewController.swift */, D2A92881241AAB67004E01C6 /* ScrollingViewController.swift */, D2A92883241ACB25004E01C6 /* ProgrammaticScrollViewController.swift */, @@ -1757,6 +1777,7 @@ D2B18B802360945C00A9AEDC /* View.swift */, 0AE14F63238315D2005417F8 /* TextField.swift */, D2755D7A23689C7500485468 /* TableViewCell.swift */, + D21B7F70243BAC1600051ABF /* CollectionViewCell.swift */, 0A5D59C323AD488600EFD9E9 /* Protocols */, ); path = BaseClasses; @@ -2005,6 +2026,7 @@ D2E2A98323D8B32D000B42E6 /* EyebrowHeadlineBodyLinkModel.swift in Sources */, 012A88AD238C418100FE3DA1 /* TemplateProtocol.swift in Sources */, BB6C6AC1242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift in Sources */, + D21B7F77243BB70700051ABF /* MoleculeCollectionItemModel.swift in Sources */, D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */, 011D9602240DA20A000E3791 /* FormRuleWatcherFieldProtocol.swift in Sources */, D260106323D0C05000764D80 /* StackItemModel.swift in Sources */, @@ -2022,6 +2044,7 @@ 0A21DB91235E0EDB00C160A2 /* DigitBox.swift in Sources */, D22D1F572204CE5D0077CEC0 /* MVMCoreUIStackableViewController.m in Sources */, D28A838B23CCDA6B00DFE4FC /* ButtonModel.swift in Sources */, + D21B7F71243BAC1600051ABF /* CollectionViewCell.swift in Sources */, D2A5145F2211DDC100345BFB /* MoleculeStackView.swift in Sources */, C7F8012323E846C300396FBD /* ListRVWheelModel.swift in Sources */, D29DF27621E79E81003B2FB9 /* MVMCoreUILoggingHandler.m in Sources */, @@ -2076,6 +2099,7 @@ D29DF13021E6851E003B2FB9 /* MVMCoreUITopAlertShortView.m in Sources */, 5248BFEC23F12E350059236A /* ListThreeColumnPlanDataDivider.swift in Sources */, 0ABD136D237CAD1E0081388D /* DateDropdownEntryField.swift in Sources */, + D264FA8E243BCD9A00D98315 /* CollectionTemplate.swift in Sources */, 0A7EF85B23D8A52800B2AAD1 /* EntryFieldModel.swift in Sources */, 94F217B723E0BF6100A47C06 /* PrimaryButtonView.m in Sources */, 0A1B4A96233BB18F005B3FB4 /* CheckboxLabel.swift in Sources */, @@ -2203,6 +2227,7 @@ D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */, D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */, 0A21DB94235E24ED00C160A2 /* DigitEntryField.swift in Sources */, + D264FA8C243BCD8E00D98315 /* CollectionTemplateModel.swift in Sources */, 52B201D224081CFB00D2011E /* ListLeftVariableRadioButtonAndPaymentMethod.swift in Sources */, D26C5A6B23F4A40D007AEECE /* ListItemModel.swift in Sources */, 0A21DB8D235E06EF00C160A2 /* MFDigitTextField.m in Sources */, @@ -2229,10 +2254,12 @@ 52267A0723FFE25000906CBA /* ListOneColumnFullWidthTextAllTextAndLinks.swift in Sources */, C003506123AA94CD00B6AC29 /* Button.swift in Sources */, DBC4391B224421A0001AB423 /* CaretLink.swift in Sources */, + D264FA90243BCE6800D98315 /* ThreeLayerCollectionViewController.swift in Sources */, 0198F7A82256A80B0066C936 /* MFRadioButton.m in Sources */, 0A6BF4722360C56C0028F841 /* BaseDropdownEntryField.swift in Sources */, BB6C6AC824225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShort.swift in Sources */, 0A41BA6E2344FCD400D4C0BC /* CATransaction+Extension.swift in Sources */, + D21B7F73243BAC6800051ABF /* CollectionItemModelProtocol.swift in Sources */, C7192E7D23C301750050C2A0 /* HeadLineBodyCaretLinkImage.swift in Sources */, D29DF13221E6851E003B2FB9 /* MVMCoreUITopAlertBaseView.m in Sources */, D29DF29C21E7ADB9003B2FB9 /* MFProgrammaticTableViewController.m in Sources */, @@ -2262,6 +2289,7 @@ EA5124FD243601600051A3A4 /* BGImageHeadlineBodyButton.swift in Sources */, 0105618D224BBE7700E1557D /* FormValidator.swift in Sources */, 01509D912327ECE600EF99AA /* CornerLabels.swift in Sources */, + D21B7F75243BAC8900051ABF /* CarouselItem.swift in Sources */, D22D1F1B220341F60077CEC0 /* MVMCoreUICheckBox.m in Sources */, C695A69823C990C200BFB94E /* DoughnutChartView.swift in Sources */, 8D3BA9BD2433787000D341BA /* ListThreeColumnInternationalDataDividerModel.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Molecules/Items/CarouselItemModel.swift b/MVMCoreUI/Atomic/Molecules/Items/CarouselItemModel.swift index 9fc218a7..ab6a1cbd 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/CarouselItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/CarouselItemModel.swift @@ -9,22 +9,20 @@ import Foundation -@objcMembers public class CarouselItemModel: MoleculeContainerModel, CarouselItemModelProtocol { - public static var identifier: String = "carouselItem" - public var backgroundColor: Color? +@objcMembers public class CarouselItemModel: MoleculeCollectionItemModel, CarouselItemModelProtocol { + public override class var identifier: String { + return "carouselItem" + } public var peakingUI: Bool? public var peakingArrowColor: Color? private enum CodingKeys: String, CodingKey { - case moleculeName - case backgroundColor case peakingUI case peakingArrowColor } required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) peakingUI = try typeContainer.decodeIfPresent(Bool.self, forKey: .peakingUI) peakingArrowColor = try typeContainer.decodeIfPresent(Color.self, forKey: .peakingArrowColor) try super.init(from: decoder) @@ -33,8 +31,6 @@ import Foundation public override func encode(to encoder: Encoder) throws { try super.encode(to: encoder) var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(moleculeName, forKey: .moleculeName) - try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encodeIfPresent(peakingUI, forKey: .peakingUI) try container.encodeIfPresent(peakingArrowColor, forKey: .peakingArrowColor) } diff --git a/MVMCoreUI/Atomic/Molecules/Items/CollectionItemModelProtocol.swift b/MVMCoreUI/Atomic/Molecules/Items/CollectionItemModelProtocol.swift new file mode 100644 index 00000000..c8bfb7d7 --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/Items/CollectionItemModelProtocol.swift @@ -0,0 +1,13 @@ +// +// CollectionItemModelProtocol.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 4/6/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol CollectionItemModelProtocol: ContainerModelProtocol { + +} diff --git a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift new file mode 100644 index 00000000..8d236f4b --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift @@ -0,0 +1,66 @@ +// +// MoleculeCollectionItemModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 4/6/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + + +@objcMembers open class MoleculeCollectionItemModel: CollectionItemModelProtocol, MoleculeModelProtocol { + open class var identifier: String { + return "collectionItem" + } + open var molecule: MoleculeModelProtocol + public var backgroundColor: Color? + + public var horizontalAlignment: UIStackView.Alignment? + public var verticalAlignment: UIStackView.Alignment? + public var useHorizontalMargins: Bool? + public var useVerticalMargins: Bool? + public var topMarginPadding: CGFloat? + public var bottomMarginPadding: CGFloat? + + /// Defaults to set + open func setDefaults() { + if useHorizontalMargins == nil { + useHorizontalMargins = true + } + if useVerticalMargins == nil { + useVerticalMargins = true + } + if topMarginPadding == nil { + topMarginPadding = PaddingDefault + } + if bottomMarginPadding == nil { + bottomMarginPadding = PaddingDefault + } + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case molecule + case backgroundColor + } + + public init(with moleculeModel: MoleculeModelProtocol) { + molecule = moleculeModel + setDefaults() + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + molecule = try typeContainer.decodeModel(codingKey: .molecule) + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + setDefaults() + } + + open func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encodeModel(molecule, forKey: .molecule) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + } +} diff --git a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift index 219617ec..0ae515f5 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift @@ -8,90 +8,15 @@ import UIKit -open class MoleculeCollectionViewCell: UICollectionViewCell, MoleculeViewProtocol { - - open var molecule: MoleculeViewProtocol? - public let containerHelper = ContainerHelper() - - // In updateView, will set padding to default. - open var updateViewHorizontalDefaults = true - open var updateViewVerticalDefaults = true - - open var allowsPeaking = false - var peakingLeftArrow = UIImageView(image: MVMCoreUIUtility.imageNamed("peakingRightArrow")?.withRenderingMode(.alwaysTemplate)) - var peakingRightArrow = UIImageView(image: MVMCoreUIUtility.imageNamed("peakingRightArrow")?.withRenderingMode(.alwaysTemplate)) - var peakingCover = MVMCoreUICommonViewsUtility.commonView() - - public override init(frame: CGRect) { - super.init(frame: .zero) - setupView() - } - - public required init?(coder aDecoder: NSCoder) { - super.init(coder: aDecoder) - setupView() - } - - public func setupView() { - guard peakingCover.superview == nil else { - return - } - isAccessibilityElement = false - contentView.isAccessibilityElement = false - insetsLayoutMarginsFromSafeArea = false - contentView.insetsLayoutMarginsFromSafeArea = false - contentView.preservesSuperviewLayoutMargins = false - - // Covers the card when peaking. - peakingCover.backgroundColor = .white - peakingCover.alpha = 0 - contentView.addSubview(peakingCover) - NSLayoutConstraint.constraintPinSubview(toSuperview: peakingCover) - - // A small arrow on the next card for when peaking. - let ratio: CGFloat = 0.015 - peakingLeftArrow.translatesAutoresizingMaskIntoConstraints = false - peakingLeftArrow.alpha = 0 - peakingLeftArrow.tintColor = .black - contentView.addSubview(peakingLeftArrow) - peakingLeftArrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true - NSLayoutConstraint.scalingPinViewLeft(toSuper: peakingLeftArrow, ratio: ratio, anchor: contentView.widthAnchor) - - peakingRightArrow.translatesAutoresizingMaskIntoConstraints = false - peakingRightArrow.transform = CGAffineTransform(scaleX: -1, y: 1) // Flip - peakingRightArrow.alpha = 0 - peakingRightArrow.tintColor = .black - contentView.addSubview(peakingRightArrow) - peakingRightArrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true - NSLayoutConstraint.scalingPinViewRight(toSuper: peakingRightArrow, ratio: ratio, anchor: contentView.widthAnchor) - } - - - public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { - guard let collectionModel = model as? CarouselItemModel else { return } - if let useHorizontalMargins = collectionModel.useHorizontalMargins { - updateViewHorizontalDefaults = useHorizontalMargins - } - if let useVerticalMargins = collectionModel.useVerticalMargins { - updateViewVerticalDefaults = useVerticalMargins - } - // Handles peaking. - allowsPeaking = collectionModel.peakingUI ?? false - if let peakingArrowColor = collectionModel.peakingArrowColor { - let color = peakingArrowColor.uiColor - peakingLeftArrow.tintColor = color - peakingRightArrow.tintColor = color - } - - if let backgroundColor = collectionModel.backgroundColor { - self.backgroundColor = backgroundColor.uiColor - } +open class MoleculeCollectionViewCell: CollectionViewCell { + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.set(with: model, delegateObject, additionalData) + guard let collectionModel = model as? MoleculeCollectionItemModel else { return } if molecule == nil { if let moleculeView = MoleculeObjectMapping.shared()?.createMolecule(collectionModel.molecule, delegateObject: delegateObject, additionalData: additionalData) { - contentView.insertSubview(moleculeView, at: 0) - containerHelper.constrainView(moleculeView) - molecule = moleculeView + addMolecule(moleculeView) + contentView.sendSubviewToBack(moleculeView) } } else { molecule?.set(with: collectionModel.molecule, delegateObject, additionalData) @@ -102,39 +27,33 @@ open class MoleculeCollectionViewCell: UICollectionViewCell, MoleculeViewProtoco accessibilityElements = molecule.subviews } - public func reset() { + open override func reset() { + super.reset() molecule?.reset() - updateViewVerticalDefaults = true - updateViewHorizontalDefaults = true backgroundColor = .white } - public class func nameForReuse(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { - guard let molecule = (model as? CarouselItemModel)?.molecule, - let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(molecule) else { - return nil - } - return moleculeClass.nameForReuse(with: molecule, delegateObject) ?? molecule.moleculeName + open class func nameForReuse(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> String? { + guard let moleculeModel = (model as? MoleculeCollectionItemModel)?.molecule else { return "\(self)<>" } + let className = MoleculeObjectMapping.shared()?.getMoleculeClass(moleculeModel) + let moleculeName = className?.nameForReuse(with: moleculeModel, delegateObject) ?? moleculeModel.moleculeName + return "\(self)<\(moleculeName)>" } - public func updateView(_ size: CGFloat) { - (molecule as? MVMCoreViewProtocol)?.updateView(size) - MFStyler.setDefaultMarginsFor(contentView, size: size, horizontal: updateViewHorizontalDefaults, vertical: updateViewVerticalDefaults) + open class func requiredModules(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> [String]? { + guard let moleculeModel = (model as? MoleculeCollectionItemModel)?.molecule, + let theClass = MoleculeObjectMapping.shared()?.getMoleculeClass(moleculeModel) + else { return nil } + + return theClass.requiredModules(with: moleculeModel, delegateObject, error: error) } - public func setPeaking(_ peaking: Bool, animated: Bool) { - guard allowsPeaking else { - return - } - let animation = {() in - self.peakingRightArrow.alpha = peaking ? 1 : 0 - self.peakingLeftArrow.alpha = peaking ? 1 : 0 - self.peakingCover.alpha = peaking ? 0.5 : 0 - } - if animated { - UIView.animate(withDuration: 0.4, animations: animation) - } else { - animation() - } + open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + guard let model = model as? MoleculeCollectionItemModel, + let classType = MoleculeObjectMapping.shared()?.getMoleculeClass(model.molecule), + let height = classType.estimatedHeight(with: model.molecule, delegateObject) + else { return 100 } + + return height + (model.topMarginPadding ?? 0) + (model.bottomMarginPadding ?? 0) } } diff --git a/MVMCoreUI/Atomic/Organisms/Carousel.swift b/MVMCoreUI/Atomic/Organisms/Carousel.swift index a7117e33..05a28a51 100644 --- a/MVMCoreUI/Atomic/Organisms/Carousel.swift +++ b/MVMCoreUI/Atomic/Organisms/Carousel.swift @@ -52,12 +52,11 @@ open class Carousel: View { public var delegateObject: MVMCoreUIDelegateObject? + private var size: CGFloat? + // MARK: - MVMCoreViewProtocol open override func setupView() { super.setupView() - guard collectionView.superview == nil else { - return - } collectionView.translatesAutoresizingMaskIntoConstraints = false collectionView.dataSource = self collectionView.delegate = self @@ -73,6 +72,7 @@ open class Carousel: View { open override func updateView(_ size: CGFloat) { super.updateView(size) + self.size = size collectionView.collectionViewLayout.invalidateLayout() showPeaking(false) @@ -143,7 +143,7 @@ open class Carousel: View { } /// Sets up the paging molecule - open func setupPagingMolecule(_ molecule: CarouselPagingModelProtocol?, delegateObject: MVMCoreUIDelegateObject?) { + open func setupPagingMolecule(_ molecule: (CarouselPagingModelProtocol & MoleculeModelProtocol)?, delegateObject: MVMCoreUIDelegateObject?) { var pagingView: (UIView & MVMCoreUIPagingProtocol)? = nil if let molecule = molecule { pagingView = MoleculeObjectMapping.shared()?.createMolecule(molecule, delegateObject: delegateObject) as? (UIView & MVMCoreUIPagingProtocol) @@ -208,15 +208,15 @@ open class Carousel: View { // Show overlay and arrow in peaking Cell let visibleItemsPaths = collectionView.indexPathsForVisibleItems.sorted { $0.row < $1.row } if let firstItem = visibleItemsPaths.first, firstItem.row != currentIndex { - (collectionView.cellForItem(at: firstItem) as? MoleculeCollectionViewCell)?.setPeaking(true, animated: true) + (collectionView.cellForItem(at: firstItem) as? CarouselItem)?.setPeaking(true, animated: true) } if let lastItem = visibleItemsPaths.last, lastItem.row != currentIndex { - (collectionView.cellForItem(at: lastItem) as? MoleculeCollectionViewCell)?.setPeaking(true, animated: true) + (collectionView.cellForItem(at: lastItem) as? CarouselItem)?.setPeaking(true, animated: true) } } else { // Hide peaking. for item in collectionView.visibleCells { - (item as? MoleculeCollectionViewCell)?.setPeaking(false, animated: true) + (item as? CarouselItem)?.setPeaking(false, animated: true) } } } @@ -229,10 +229,12 @@ open class Carousel: View { cell.accessibilityElementsHidden = false var array = cell.accessibilityElements - if let acc = pagingView?.accessibilityElements { - array?.append(contentsOf: acc) - } else { - array?.append(pagingView!) + if let pagingView = pagingView { + if let acc = pagingView.accessibilityElements { + array?.append(contentsOf: acc) + } else { + array?.append(pagingView) + } } self.accessibilityElements = array @@ -244,12 +246,12 @@ open class Carousel: View { extension Carousel: UICollectionViewDelegateFlowLayout { open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { - let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent) + let itemWidth = (size ?? collectionView.bounds.width) * CGFloat(itemWidthPercent) return CGSize(width: itemWidth, height: collectionView.bounds.height) } open func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { - (cell as? MoleculeCollectionViewCell)?.setPeaking(false, animated: false) + (cell as? CarouselItem)?.setPeaking(false, animated: false) } } @@ -268,7 +270,7 @@ extension Carousel: UICollectionViewDataSource { protocolCell.reset() protocolCell.set(with: moleculeInfo.molecule, delegateObject, nil) } - (cell as? MVMCoreViewProtocol)?.updateView(collectionView.bounds.width) + (cell as? MVMCoreViewProtocol)?.updateView(size ?? collectionView.bounds.width) setAccessiblity(cell, index: indexPath.row) return cell } diff --git a/MVMCoreUI/Atomic/Organisms/CarouselModel.swift b/MVMCoreUI/Atomic/Organisms/CarouselModel.swift index 8b987a73..9fb4fe3b 100644 --- a/MVMCoreUI/Atomic/Organisms/CarouselModel.swift +++ b/MVMCoreUI/Atomic/Organisms/CarouselModel.swift @@ -19,7 +19,7 @@ import UIKit public var height: Float? public var itemWidthPercent: Float? public var itemAlignment: UICollectionView.ScrollPosition? - public var pagingMolecule: CarouselPagingModelProtocol? + public var pagingMolecule: (CarouselPagingModelProtocol & MoleculeModelProtocol)? public init(molecules: [CarouselItemModel]){ self.molecules = molecules @@ -42,12 +42,12 @@ import UIKit let typeContainer = try decoder.container(keyedBy: CodingKeys.self) self.molecules = try typeContainer.decode([CarouselItemModel].self, forKey: .molecules) self.backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) - self.spacing = try typeContainer.decode(Float.self, forKey: .spacing) - self.border = try typeContainer.decode(Bool.self, forKey: .border) - self.loop = try typeContainer.decode(Bool.self, forKey: .loop) - self.height = try typeContainer.decode(Float.self, forKey: .height) - self.itemWidthPercent = try typeContainer.decode(Float.self, forKey: .itemWidthPercent) - self.itemAlignment = try typeContainer.decode(UICollectionView.ScrollPosition.self, forKey: .itemAlignment) + self.spacing = try typeContainer.decodeIfPresent(Float.self, forKey: .spacing) + self.border = try typeContainer.decodeIfPresent(Bool.self, forKey: .border) + self.loop = try typeContainer.decodeIfPresent(Bool.self, forKey: .loop) + self.height = try typeContainer.decodeIfPresent(Float.self, forKey: .height) + self.itemWidthPercent = try typeContainer.decodeIfPresent(Float.self, forKey: .itemWidthPercent) + self.itemAlignment = try typeContainer.decodeIfPresent(UICollectionView.ScrollPosition.self, forKey: .itemAlignment) self.pagingMolecule = try typeContainer.decodeModelIfPresent(codingKey: .pagingMolecule) } diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/CarouselPagingModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/CarouselPagingModelProtocol.swift index 94b1277a..72138290 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/CarouselPagingModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/CarouselPagingModelProtocol.swift @@ -9,6 +9,6 @@ import Foundation -public protocol CarouselPagingModelProtocol: MoleculeModelProtocol { +public protocol CarouselPagingModelProtocol { var position: Float? { get } } diff --git a/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift new file mode 100644 index 00000000..ce135631 --- /dev/null +++ b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift @@ -0,0 +1,15 @@ +// +// CollectionTemplate.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 4/6/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objc open class CollectionTemplate: ThreeLayerCollectionViewController, TemplateProtocol { + public typealias TemplateModel = CollectionTemplateModel + public var templateModel: CollectionTemplateModel? + +} diff --git a/MVMCoreUI/Atomic/Templates/CollectionTemplateModel.swift b/MVMCoreUI/Atomic/Templates/CollectionTemplateModel.swift new file mode 100644 index 00000000..56c56456 --- /dev/null +++ b/MVMCoreUI/Atomic/Templates/CollectionTemplateModel.swift @@ -0,0 +1,67 @@ +// +// CollectionTemplateModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 4/6/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers public class CollectionTemplateModel: TemplateModel { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public override class var identifier: String { + return "collection" + } + public var header: MoleculeModelProtocol? + public var molecules: [CollectionItemModelProtocol & MoleculeModelProtocol]? + public var footer: MoleculeModelProtocol? + public var columns: Int? + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + + public init(pageType: String, screenHeading: String?, molecules: [CollectionItemModelProtocol & MoleculeModelProtocol]) { + super.init(pageType: pageType) + self.screenHeading = screenHeading + self.molecules = molecules + } + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case molecules + case header + case footer + case columns + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + molecules = try typeContainer.decodeModelsIfPresent(codingKey: .molecules) + header = try typeContainer.decodeModelIfPresent(codingKey: .header) + footer = try typeContainer.decodeModelIfPresent(codingKey: .footer) + columns = try typeContainer.decodeIfPresent(Int.self, forKey: .columns) + try super.init(from: decoder) + } + + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeModelsIfPresent(molecules, forKey: .molecules) + try container.encodeModelIfPresent(header, forKey: .header) + try container.encodeModelIfPresent(footer, forKey: .footer) + try container.encodeIfPresent(columns, forKey: .columns) + } +} + diff --git a/MVMCoreUI/Atomic/Templates/ThreeLayerTemplate.swift b/MVMCoreUI/Atomic/Templates/ThreeLayerTemplate.swift index 8f963f5d..96e85fad 100644 --- a/MVMCoreUI/Atomic/Templates/ThreeLayerTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/ThreeLayerTemplate.swift @@ -51,10 +51,6 @@ import UIKit return molecule } - open override func spaceBetweenMiddleAndBottom() -> CGFloat? { - return 0 - } - open override func spaceBetweenTopAndMiddle() -> CGFloat? { return 0 } diff --git a/MVMCoreUI/BaseClasses/CollectionViewCell.swift b/MVMCoreUI/BaseClasses/CollectionViewCell.swift new file mode 100644 index 00000000..50cece5d --- /dev/null +++ b/MVMCoreUI/BaseClasses/CollectionViewCell.swift @@ -0,0 +1,77 @@ +// +// CollectionViewCell.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 4/6/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCoreViewProtocol { + + // Convenience helpers + open var molecule: MoleculeViewProtocol? + public let containerHelper = ContainerHelper() + open var model: CollectionItemModelProtocol? + + private var initialSetupPerformed = false + + public override init(frame: CGRect) { + super.init(frame: .zero) + initialSetup() + } + + public required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + initialSetup() + } + + private func initialSetup() { + if !initialSetupPerformed { + initialSetupPerformed = true + setupView() + } + } + + open func setupView() { + isAccessibilityElement = false + contentView.isAccessibilityElement = false + insetsLayoutMarginsFromSafeArea = false + contentView.insetsLayoutMarginsFromSafeArea = false + contentView.preservesSuperviewLayoutMargins = false + MVMCoreUIUtility.setMarginsFor(self, leading: 0, top: 0, trailing: 0, bottom: 0) + } + + open func updateView(_ size: CGFloat) { + containerHelper.updateViewMargins(contentView, model: model, size: size) + DispatchQueue.main.async { + print("\(self.contentView.directionalLayoutMargins.leading)") + } + } + + open func reset() { + molecule?.reset() + backgroundColor = .white + } + + open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + guard let model = model as? CollectionItemModelProtocol else { return } + self.model = model + + if let moleculeModel = model as? MoleculeModelProtocol, + let backgroundColor = moleculeModel.backgroundColor { + self.backgroundColor = backgroundColor.uiColor + } + + // align if needed. + containerHelper.set(with: model, for: molecule as? MVMCoreUIViewConstrainingProtocol) + } + + /// Convenience function. Adds the molecule to the view. + open func addMolecule(_ molecule: MoleculeViewProtocol) { + contentView.addSubview(molecule) + containerHelper.constrainView(molecule) + self.molecule = molecule + } +} diff --git a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift new file mode 100644 index 00000000..a7b39cfd --- /dev/null +++ b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift @@ -0,0 +1,289 @@ +// +// ThreeLayerCollectionViewController.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 4/6/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objc open class ThreeLayerCollectionViewController: ScrollingViewController, UICollectionViewDataSource, UICollectionViewDelegate { + public var collectionView: UICollectionView? + + // The three main views + private var topView: UIView? + private var bottomView: UIView? + private var headerView: UIView? + private var footerView: UIView? + private var safeAreaView: UIView? + var useMargins: Bool = true + public var bottomViewOutsideOfScrollArea: Bool = false + private var topViewBottomConstraint: NSLayoutConstraint? + private var bottomViewTopConstraint: NSLayoutConstraint? + + //MARK: - MFViewController + open override func updateViews() { + super.updateViews() + let width = view.bounds.width + if let topView = topView as? MVMCoreViewProtocol { + topView.updateView(width) + //showHeader(width) + } + if let bottomView = bottomView as? MVMCoreViewProtocol { + bottomView.updateView(width) + //showFooter(width) + } + self.collectionView?.collectionViewLayout.invalidateLayout() + } + + open override func handleNewData() { + super.handleNewData() + //createViewForTableHeader() + //createViewForTableFooter() + collectionView?.reloadData() + } + + override open func viewDidLoad() { + let collection = createCollectionView() + collectionView = collection + view.addSubview(collection) + NSLayoutConstraint.constraintPinSubview(toSuperview: collection) + scrollView = collectionView + + registerCells() + + super.viewDidLoad() + // Do any additional setup after loading the view. + } + + //MARK: - Spacing + // If both are subclassed to return a value, then the buttons will not be pinned towards the bottom because neither spacing would try to fill the screen. + /// Space between the top view and the table sections, nil to fill. 0 default + open func spaceBelowTopView() -> CGFloat? { + return 0 + } + + /// Space between the bottom view and the table sections, nil to fill. nil default + open func spaceAboveBottomView() -> CGFloat? { + return nil + } + + /// can override to return a minimum fill space. + open func minimumFillSpace() -> CGFloat { + return 0 + } + + /*open override func updateViewConstraints() { + super.updateViewConstraints() + + guard let tableView = collectionView else { return } + + let minimumSpace: CGFloat = minimumFillSpace() + var currentSpace: CGFloat = 0 + var totalMinimumSpace: CGFloat = 0 + + var fillTop = false + if spaceBelowTopView() == nil, headerView != nil { + fillTop = true + currentSpace += topViewBottomConstraint?.constant ?? 0 + totalMinimumSpace += minimumSpace + } + + var fillBottom = false + if spaceAboveBottomView() == nil, !bottomViewOutsideOfScrollArea, footerView != nil { + fillBottom = true + currentSpace += bottomViewTopConstraint?.constant ?? 0 + totalMinimumSpace += minimumSpace + } + + guard fillTop || fillBottom else { return } + + let newSpace = MVMCoreUIUtility.getVariableConstraintHeight(currentSpace, in: tableView, minimumHeight: totalMinimumSpace) + + // If the bottom view is outside of the scroll, then only the top view constraint is being used, so we have to double it to account for the bottom constraint not being there when we compare to the new value. + var currentSpaceForCompare: CGFloat = currentSpace + if fillTop && bottomViewOutsideOfScrollArea { + currentSpaceForCompare = currentSpace * 2; + } + + let width = view.bounds.width + if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpaceForCompare, 0.1) { + if fillTop && fillBottom { + // space both + let half = newSpace / 2 + topViewBottomConstraint?.constant = half + bottomViewTopConstraint?.constant = half + showHeader(width) + showFooter(width) + } else if fillTop { + // Only top is spaced (half the size if the bottom view is out of the scroll because it needs to be sized as if there are two spacers but there is only one. + if bottomViewOutsideOfScrollArea { + topViewBottomConstraint?.constant = newSpace / 2 + } else { + topViewBottomConstraint?.constant = newSpace + } + showHeader(width) + } else if fillBottom { + // Only bottom is spaced. + bottomViewTopConstraint?.constant = newSpace + showFooter(width) + } + } + } + + //MARK: - Header Footer + /// Gets the top view and adds it to a spacing view, headerView, and then calls showHeader. + open func createViewForTableHeader() { + let topView = viewForTop() + self.topView = topView + + let headerView = MVMCoreUICommonViewsUtility.commonView() + headerView.addSubview(topView) + topView.topAnchor.constraint(equalTo: headerView.topAnchor).isActive = true + topView.leftAnchor.constraint(equalTo: headerView.leftAnchor).isActive = true + headerView.rightAnchor.constraint(equalTo: topView.rightAnchor).isActive = true + topViewBottomConstraint = headerView.bottomAnchor.constraint(equalTo: topView.bottomAnchor, constant: spaceBelowTopView() ?? 0) + topViewBottomConstraint?.isActive = true + self.headerView = headerView + showHeader(nil) + } + + /// Gets the bottom view and adds it to a spacing view, footerView, and then calls showFooter. + open func createViewForTableFooter() { + let bottomView = viewForBottom() + self.bottomView = bottomView + + let footerView = MVMCoreUICommonViewsUtility.commonView() + footerView.addSubview(bottomView) + bottomViewTopConstraint = bottomView.topAnchor.constraint(equalTo: footerView.topAnchor, constant: spaceAboveBottomView() ?? 0) + 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).isActive = true + self.footerView = footerView + showFooter(nil) + } + + /// Takes the current headerView and adds it to the tableHeaderView + func showHeader(_ sizingWidth: CGFloat?) { + headerView?.removeFromSuperview() + tableView?.tableHeaderView = nil + guard let headerView = headerView else { + return + } + + // This extra view is needed because of the wonkiness of apple's table header. Things breaks if using autolayout. + headerView.setNeedsLayout() + headerView.layoutIfNeeded() + MVMCoreUIUtility.sizeView(toFit: headerView) + let tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: MVMCoreUIUtility.getWidth(), height: headerView.frame.height)) + tableHeaderView.addSubview(headerView) + NSLayoutConstraint.constraintPinSubview(toSuperview: headerView) + tableView?.tableHeaderView = tableHeaderView + } + + /// Takes the current footerView and adds it to the tableFooterView + func showFooter(_ sizingWidth: CGFloat?) { + footerView?.removeFromSuperview() + safeAreaView?.removeFromSuperview() + guard let footerView = footerView, let tableView = tableView else { + return + } + + if bottomViewOutsideOfScrollArea { + // put bottom view outside of scrolling area. + bottomConstraint?.isActive = false + view.addSubview(footerView) + footerView.topAnchor.constraint(equalTo: tableView.bottomAnchor).isActive = true + footerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true + view.rightAnchor.constraint(equalTo: footerView.rightAnchor).isActive = true + view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: footerView.bottomAnchor).isActive = true + safeAreaView = MVMCoreUICommonViewsUtility.getAndSetupSafeAreaView(on: view) + safeAreaView?.backgroundColor = bottomView?.backgroundColor + } else { + bottomConstraint?.isActive = true + var y: CGFloat? + if let tableFooterView = tableView.tableFooterView { + // if footer already exists, use the same y location to avoid strange moving animation + y = tableFooterView.frame.minY + } + + // This extra view is needed because of the wonkiness of apple's table footer. Things breaks if using autolayout. + MVMCoreUIUtility.sizeView(toFit: footerView) + let tableFooterView = UIView(frame: CGRect(x: 0, y: y ?? 0, width: MVMCoreUIUtility.getWidth(), height: footerView.frame.height)) + tableFooterView.addSubview(footerView) + NSLayoutConstraint.constraintPinSubview(toSuperview: footerView) + tableView.tableFooterView = tableFooterView + } + }*/ + + //MARK: - Functions to subclass + /// Subclass for a top view. + open func viewForTop() -> UIView { + let view = MVMCoreUICommonViewsUtility.commonView() + // 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: PaddingDefaultVerticalSpacing).isActive = true + return view + } + + open func createCollectionView() -> UICollectionView { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .vertical + layout.minimumLineSpacing = 1 + layout.minimumInteritemSpacing = 0 + + let collection = UICollectionView(frame: .zero, collectionViewLayout: layout) + collection.translatesAutoresizingMaskIntoConstraints = false + collection.dataSource = self + collection.delegate = self + collection.showsHorizontalScrollIndicator = false + collection.backgroundColor = .white + collection.isAccessibilityElement = false + collection.contentInsetAdjustmentBehavior = .always + return collection + } + + deinit { + collectionView?.delegate = nil + collectionView?.dataSource = nil + } + + //MARK: - Collection + + public func registerCells() { + collectionView?.register(MoleculeCollectionViewCell.self, forCellWithReuseIdentifier: "collectionItem") + } + + public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return 2 + } + + public func numberOfSections(in collectionView: UICollectionView) -> Int { + return 1 + } + + public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionItem", for: indexPath) as! MoleculeCollectionViewCell + let labelModel = LabelModel(text: "hello") + let model = MoleculeCollectionItemModel(with: labelModel) + cell.set(with: model, delegateObjectIVar, nil) + return cell + } + + open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { + return CGSize(width: 200, height: 200) + } + + open func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { + (cell as? CarouselItem)?.setPeaking(false, animated: false) + } +} diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject.m b/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject.m index d3db2a2d..20fb924e 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject.m +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject.m @@ -24,7 +24,8 @@ @"list" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[MoleculeListTemplate class]], @"threeLayer" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[ThreeLayerTemplate class]], @"modalStack" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[ModalMoleculeStackTemplate class]], - @"modalList" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[ModalMoleculeListTemplate class]] + @"modalList" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[ModalMoleculeListTemplate class]], + @"collection" : [[MVMCoreViewControllerProgrammaticMappingObject alloc] initWithClass:[CollectionTemplate class]] } mutableCopy]; }); return viewControllerMapping; From d393098fcddc0e963a54737d63e44251d1fa9748 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 7 Apr 2020 10:08:47 -0400 Subject: [PATCH 20/62] collection changes --- .../Atomic/Molecules/Items/CarouselItem.swift | 73 +++++++++++++++++++ 1 file changed, 73 insertions(+) create mode 100644 MVMCoreUI/Atomic/Molecules/Items/CarouselItem.swift diff --git a/MVMCoreUI/Atomic/Molecules/Items/CarouselItem.swift b/MVMCoreUI/Atomic/Molecules/Items/CarouselItem.swift new file mode 100644 index 00000000..9cf2a246 --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/Items/CarouselItem.swift @@ -0,0 +1,73 @@ +// +// CarouselItem.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 4/6/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +open class CarouselItem: MoleculeCollectionViewCell { + + open var allowsPeaking = false + var peakingLeftArrow = UIImageView(image: MVMCoreUIUtility.imageNamed("peakingRightArrow")?.withRenderingMode(.alwaysTemplate)) + var peakingRightArrow = UIImageView(image: MVMCoreUIUtility.imageNamed("peakingRightArrow")?.withRenderingMode(.alwaysTemplate)) + var peakingCover = MVMCoreUICommonViewsUtility.commonView() + + open override func setupView() { + super.setupView() + + // Covers the card when peaking. + peakingCover.backgroundColor = .white + peakingCover.alpha = 0 + contentView.addSubview(peakingCover) + NSLayoutConstraint.constraintPinSubview(toSuperview: peakingCover) + + // A small arrow on the next card for when peaking. + let ratio: CGFloat = 0.015 + peakingLeftArrow.translatesAutoresizingMaskIntoConstraints = false + peakingLeftArrow.alpha = 0 + peakingLeftArrow.tintColor = .black + contentView.addSubview(peakingLeftArrow) + peakingLeftArrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true + NSLayoutConstraint.scalingPinViewLeft(toSuper: peakingLeftArrow, ratio: ratio, anchor: contentView.widthAnchor) + + peakingRightArrow.translatesAutoresizingMaskIntoConstraints = false + peakingRightArrow.transform = CGAffineTransform(scaleX: -1, y: 1) // Flip + peakingRightArrow.alpha = 0 + peakingRightArrow.tintColor = .black + contentView.addSubview(peakingRightArrow) + peakingRightArrow.centerYAnchor.constraint(equalTo: contentView.centerYAnchor).isActive = true + NSLayoutConstraint.scalingPinViewRight(toSuper: peakingRightArrow, ratio: ratio, anchor: contentView.widthAnchor) + } + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.set(with: model, delegateObject, additionalData) + guard let collectionModel = model as? CarouselItemModel else { return } + + // Handles peaking. + allowsPeaking = collectionModel.peakingUI ?? false + if let peakingArrowColor = collectionModel.peakingArrowColor { + let color = peakingArrowColor.uiColor + peakingLeftArrow.tintColor = color + peakingRightArrow.tintColor = color + } + } + + public func setPeaking(_ peaking: Bool, animated: Bool) { + guard allowsPeaking else { + return + } + let animation = {() in + self.peakingRightArrow.alpha = peaking ? 1 : 0 + self.peakingLeftArrow.alpha = peaking ? 1 : 0 + self.peakingCover.alpha = peaking ? 0.5 : 0 + } + if animated { + UIView.animate(withDuration: 0.4, animations: animation) + } else { + animation() + } + } +} From 9079d6dcae44899e35659d83fb0831007ee2e7ce Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 7 Apr 2020 11:22:01 -0400 Subject: [PATCH 21/62] more chanes made for design request --- .../Atomic/Atoms/Buttons/CaretLink.swift | 6 ++--- .../Atoms/TextFields/DigitEntryField.swift | 2 +- .../Atomic/Atoms/TextFields/EntryField.swift | 18 ++++++++------- .../Atoms/TextFields/TextEntryField.swift | 21 +++++++++++++----- MVMCoreUI/Atomic/Atoms/Views/Toggle.swift | 6 ++--- .../Views/EntryFieldContainer.swift | 22 +++++++++---------- 6 files changed, 43 insertions(+), 32 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift b/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift index 697f4282..2e042824 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift @@ -25,11 +25,11 @@ open class CaretLink: Button, MVMCoreUIViewConstrainingProtocol { @objc public var rightViewHeight: NSNumber? @objc public var rightViewWidth: NSNumber? - @objc public var enabledColor: UIColor = .black { + @objc public var enabledColor: UIColor = .mvmBlack { didSet { changeCaretColor() } } - @objc public var disabledColor: UIColor = .mfSilver() { + @objc public var disabledColor: UIColor = .mvmCoolGray3 { didSet { changeCaretColor() } } @@ -114,7 +114,7 @@ open class CaretLink: Button, MVMCoreUIViewConstrainingProtocol { caretView.widthAnchor.constraint(equalToConstant: width).isActive = true caretView.heightAnchor.constraint(equalToConstant: height).isActive = true - let caretLabelSpacing = NSLayoutConstraint(item: caretView, attribute: .left, relatedBy: .equal, toItem: titleLabel, attribute: .right, multiplier: 1.0, constant: 4) + let caretLabelSpacing = NSLayoutConstraint(item: caretView, attribute: .left, relatedBy: .equal, toItem: titleLabel, attribute: .right, multiplier: 1.0, constant: 7) caretLabelSpacing.isActive = true caretSpacingConstraint = caretLabelSpacing diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/DigitEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/DigitEntryField.swift index 091f9e51..38adee03 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/DigitEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/DigitEntryField.swift @@ -116,7 +116,7 @@ import UIKit for (index, field) in digitBoxes.enumerated() { if index < newValue.count { let indexChar = newValue.index(newValue.startIndex, offsetBy: index) - field.digitField.attributedPlaceholder = NSAttributedString(string: String(newValue[indexChar]), attributes: [NSAttributedString.Key.foregroundColor: UIColor.mfBattleshipGrey()]) + field.digitField.attributedPlaceholder = NSAttributedString(string: String(newValue[indexChar]), attributes: [NSAttributedString.Key.foregroundColor: UIColor.mvmCoolGray6]) } } diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift index 7fb3a458..658af357 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift @@ -20,8 +20,8 @@ import UIKit public private(set) var titleLabel: Label = { let label = Label() - label.font = MFStyler.fontB3() - label.textColor = .mvmCoolGray6 + label.font = MFStyler.fontRegularMicro() + label.textColor = .mvmBlack label.setContentCompressionResistancePriority(.required, for: .vertical) return label }() @@ -31,7 +31,7 @@ import UIKit /// Provides contextual information on the TextField. public private(set) var feedbackLabel: Label = { let label = Label() - label.font = MFStyler.fontForTextFieldUnderLabel() + label.font = MFStyler.fontRegularMicro() label.textColor = .mvmBlack label.setContentCompressionResistancePriority(.required, for: .vertical) return label @@ -65,7 +65,8 @@ import UIKit public var isEnabled: Bool { get { return entryFieldContainer.isEnabled } set (enabled) { - self.feedbackLabel.textColor = enabled ? .black : .mfSilver() + self.titleLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3 + self.feedbackLabel.textColor = enabled ? .mvmBlack : .mvmCoolGray3 self.entryFieldContainer.isEnabled = enabled } } @@ -233,15 +234,16 @@ import UIKit //-------------------------------------------------- // MARK: - MoleculeViewProtocol //-------------------------------------------------- + @objc open override func reset() { super.reset() backgroundColor = .clear isAccessibilityElement = false - titleLabel.font = MFStyler.fontB3() - titleLabel.textColor = .mfBattleshipGrey() - feedbackLabel.font = MFStyler.fontForTextFieldUnderLabel() - feedbackLabel.textColor = .black + titleLabel.font = MFStyler.fontRegularMicro() + titleLabel.textColor = .mvmBlack + feedbackLabel.font = MFStyler.fontRegularMicro() + feedbackLabel.textColor = .mvmBlack entryFieldContainer.reset() } diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift index 2e7df5ee..cf927c03 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift @@ -28,7 +28,8 @@ import UIKit let textField = TextField() textField.isAccessibilityElement = true textField.setContentCompressionResistancePriority(.required, for: .vertical) - textField.font = MFStyler.fontForTextField() + textField.font = MFStyler.fontRegularBodyLarge() + textField.textColor = .mvmBlack textField.smartQuotesType = .no textField.smartDashesType = .no textField.smartInsertDeleteType = .no @@ -40,7 +41,7 @@ import UIKit //-------------------------------------------------- /// Set enabled and disabled colors to be utilized when setting this texfield's isEnabled property. - public var textColor: (enabled: UIColor?, disabled: UIColor?) = (.black, .mfSilver()) + public var textColor: (enabled: UIColor?, disabled: UIColor?) = (.mvmBlack, .mvmCoolGray3) private var observingForChange: Bool = false @@ -78,7 +79,9 @@ import UIKit if error { textField.accessibilityValue = String(format: MVMCoreUIUtility.hardcodedString(withKey: "textfield_error_message") ?? "", textField.text ?? "", errorMessage ?? "") + errorIconWidthContraint?.constant = 20 } else { + errorIconWidthContraint?.constant = 0 textField.accessibilityValue = nil } @@ -140,6 +143,7 @@ import UIKit //-------------------------------------------------- public var textFieldTrailingConstraint: NSLayoutConstraint? + public var errorIconWidthContraint: NSLayoutConstraint? //-------------------------------------------------- // MARK: - Initializers @@ -168,7 +172,7 @@ import UIKit @objc open override func setupFieldContainerContent(_ container: UIView) { - MFStyler.styleTextField(textField) + textField.font = MFStyler.fontRegularBodyLarge() container.addSubview(textField) NSLayoutConstraint.activate([ @@ -193,14 +197,14 @@ import UIKit @objc open override func updateView(_ size: CGFloat) { super.updateView(size) - MFStyler.styleTextField(textField) + textField.font = MFStyler.fontRegularBodyLarge() layoutIfNeeded() } open override func reset() { super.reset() - textField.font = MFStyler.fontForTextField() + textField.font = MFStyler.fontRegularBodyLarge() } @objc deinit { @@ -252,6 +256,7 @@ import UIKit observingTextFieldDelegate?.isValid?(textfield: self) } } + /// Executes on UITextField.textDidBeginEditingNotification @objc func startEditing() { isSelected = true @@ -270,7 +275,7 @@ import UIKit resignFirstResponder() if isValid { showError = false - entryFieldContainer.bottomBar?.backgroundColor = UIColor.black.cgColor + entryFieldContainer.bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor } } @@ -278,6 +283,10 @@ import UIKit resignFirstResponder() } + //-------------------------------------------------- + // MARK: - MoleculeViewProtocol + //-------------------------------------------------- + public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Toggle.swift b/MVMCoreUI/Atomic/Atoms/Views/Toggle.swift index 1e072faf..956c2afc 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Toggle.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Toggle.swift @@ -25,13 +25,13 @@ public typealias ActionBlockConfirmation = () -> (Bool) //-------------------------------------------------- /// Holds the on and off colors for the container. - public var containerTintColor: (on: UIColor?, off: UIColor?)? = (on: .mvmGreen, off: .black) + public var containerTintColor: (on: UIColor?, off: UIColor?)? = (on: .mvmGreen, off: .mvmBlack) /// Holds the on and off colors for the knob. - public var knobTintColor: (on: UIColor?, off: UIColor?)? = (on: .white, off: .white) + public var knobTintColor: (on: UIColor?, off: UIColor?)? = (on: .mvmWhite, off: .mvmWhite) /// Holds the on and off colors for the disabled state.. - public var disabledTintColor: (container: UIColor?, knob: UIColor?)? = (container: .mvmCoolGray3, knob: .white) + public var disabledTintColor: (container: UIColor?, knob: UIColor?)? = (container: .mvmCoolGray3, knob: .mvmWhite) /// Set this flag to false if you do not want to animate state changes. public var isAnimated = true diff --git a/MVMCoreUI/Containers/Views/EntryFieldContainer.swift b/MVMCoreUI/Containers/Views/EntryFieldContainer.swift index cf56fb9d..3a8fac64 100644 --- a/MVMCoreUI/Containers/Views/EntryFieldContainer.swift +++ b/MVMCoreUI/Containers/Views/EntryFieldContainer.swift @@ -17,7 +17,7 @@ import UIKit /// The bottom border line. Height is dynamic based on scenario. public var bottomBar: CAShapeLayer? = { let layer = CAShapeLayer() - layer.backgroundColor = UIColor.black.cgColor + layer.backgroundColor = UIColor.mvmBlack.cgColor layer.drawsAsynchronously = true layer.anchorPoint = CGPoint(x: 0.5, y: 1.0); return layer @@ -46,7 +46,7 @@ import UIKit /// Determines if the top, left, and right borders should be drawn. private var hideBorders = false - public var borderStrokeColor: UIColor = .mfSilver() + public var borderStrokeColor: UIColor = .mvmCoolGray3 private var borderPath: UIBezierPath = UIBezierPath() //-------------------------------------------------- @@ -210,8 +210,8 @@ import UIKit isUserInteractionEnabled = true hideBorders = false - borderStrokeColor = .mfSilver() - bottomBar?.backgroundColor = UIColor.black.cgColor + borderStrokeColor = .mvmCoolGray3 + bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor refreshUI(bottomBarSize: 1) } @@ -219,8 +219,8 @@ import UIKit isUserInteractionEnabled = true hideBorders = false - borderStrokeColor = .mfPumpkin() - bottomBar?.backgroundColor = UIColor.mfPumpkin().cgColor + borderStrokeColor = .mvmOrange + bottomBar?.backgroundColor = UIColor.mvmOrange.cgColor refreshUI(bottomBarSize: 4) } @@ -228,8 +228,8 @@ import UIKit isUserInteractionEnabled = true hideBorders = false - borderStrokeColor = .black - bottomBar?.backgroundColor = UIColor.mfPumpkin().cgColor + borderStrokeColor = .mvmBlack + bottomBar?.backgroundColor = UIColor.mvmOrange.cgColor refreshUI(bottomBarSize: 4) } @@ -237,8 +237,8 @@ import UIKit isUserInteractionEnabled = true hideBorders = false - borderStrokeColor = .black - bottomBar?.backgroundColor = UIColor.black.cgColor + borderStrokeColor = .mvmBlack + bottomBar?.backgroundColor = UIColor.mvmBlack.cgColor refreshUI(bottomBarSize: 1) } @@ -255,7 +255,7 @@ import UIKit isUserInteractionEnabled = false hideBorders = false - borderStrokeColor = .mfSilver() + borderStrokeColor = .mvmCoolGray3 bottomBar?.backgroundColor = UIColor.mvmCoolGray3.cgColor refreshUI(bottomBarSize: 1) } From 1ac94059dbcc084aa5138e81ab435f42d2e1423b Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 7 Apr 2020 11:27:56 -0400 Subject: [PATCH 22/62] mild updates to caret --- .../Atomic/Atoms/Buttons/CaretLink.swift | 28 +++++++++++-------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift b/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift index 2e042824..75c44eb3 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift @@ -103,8 +103,10 @@ open class CaretLink: Button, MVMCoreUIViewConstrainingProtocol { let width = CGFloat(rightViewWidth?.floatValue ?? CARET_VIEW_WIDTH) let height = CGFloat(rightViewHeight?.floatValue ?? CARET_VIEW_HEIGHT) - let edgeInsets: UIEdgeInsets = contentEdgeInsets - contentEdgeInsets = UIEdgeInsets(top: edgeInsets.top, left: edgeInsets.left, bottom: edgeInsets.bottom, right: 4 + width) + contentEdgeInsets = UIEdgeInsets(top: contentEdgeInsets.top, + left: contentEdgeInsets.left, + bottom: contentEdgeInsets.bottom, + right: 4 + width) let caretView: UIView = rightView ?? createCaretView() rightView = caretView @@ -118,8 +120,8 @@ open class CaretLink: Button, MVMCoreUIViewConstrainingProtocol { caretLabelSpacing.isActive = true caretSpacingConstraint = caretLabelSpacing - NSLayoutConstraint(item: caretView, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .centerY, multiplier: 1.0, constant: 0).isActive = true - NSLayoutConstraint(item: self, attribute: .right, relatedBy: .greaterThanOrEqual, toItem: caretView, attribute: .right, multiplier: 1.0, constant: 0).isActive = true + caretView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + trailingAnchor.constraint(greaterThanOrEqualTo: caretView.trailingAnchor).isActive = true caretView.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true bottomAnchor.constraint(greaterThanOrEqualTo: caretView.bottomAnchor).isActive = true contentHorizontalAlignment = .left @@ -137,17 +139,21 @@ open class CaretLink: Button, MVMCoreUIViewConstrainingProtocol { // MARK: - Atomization //------------------------------------------------------ public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { - guard let caretLinkModel = model as? CaretLinkModel else { return } - if let color = caretLinkModel.backgroundColor { + + guard let model = model as? CaretLinkModel else { return } + + if let color = model.backgroundColor { backgroundColor = color.uiColor } - enabledColor = caretLinkModel.enabledColor.uiColor - if let color = caretLinkModel.disabledColor { + + enabledColor = model.enabledColor.uiColor + if let color = model.disabledColor { disabledColor = color.uiColor } - isEnabled = caretLinkModel.enabled - set(with: caretLinkModel.action, delegateObject: delegateObject, additionalData: additionalData) - setTitle(caretLinkModel.title, for: .normal) + + isEnabled = model.enabled + set(with: model.action, delegateObject: delegateObject, additionalData: additionalData) + setTitle(model.title, for: .normal) } public func needsToBeConstrained() -> Bool { From 2b065d1b80032653eeafd623d10116509e04998b Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 7 Apr 2020 11:34:12 -0400 Subject: [PATCH 23/62] improvedment --- MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift b/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift index 75c44eb3..b437a56f 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift @@ -103,10 +103,7 @@ open class CaretLink: Button, MVMCoreUIViewConstrainingProtocol { let width = CGFloat(rightViewWidth?.floatValue ?? CARET_VIEW_WIDTH) let height = CGFloat(rightViewHeight?.floatValue ?? CARET_VIEW_HEIGHT) - contentEdgeInsets = UIEdgeInsets(top: contentEdgeInsets.top, - left: contentEdgeInsets.left, - bottom: contentEdgeInsets.bottom, - right: 4 + width) + contentEdgeInsets.right = 4 + width let caretView: UIView = rightView ?? createCaretView() rightView = caretView From 544a630ffb164ee59043773b2e47365e807e1520 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 7 Apr 2020 11:35:33 -0400 Subject: [PATCH 24/62] readable consteaint --- MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift b/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift index b437a56f..4ba95472 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift @@ -113,7 +113,7 @@ open class CaretLink: Button, MVMCoreUIViewConstrainingProtocol { caretView.widthAnchor.constraint(equalToConstant: width).isActive = true caretView.heightAnchor.constraint(equalToConstant: height).isActive = true - let caretLabelSpacing = NSLayoutConstraint(item: caretView, attribute: .left, relatedBy: .equal, toItem: titleLabel, attribute: .right, multiplier: 1.0, constant: 7) + let caretLabelSpacing = caretView.leadingAnchor.constraint(equalTo: titleLabel?.trailingAnchor, constant: 7) caretLabelSpacing.isActive = true caretSpacingConstraint = caretLabelSpacing From d96aa1c310687f34116245af8dd9e0fa47369a35 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 7 Apr 2020 11:36:34 -0400 Subject: [PATCH 25/62] undo --- MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift b/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift index 4ba95472..b437a56f 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/CaretLink.swift @@ -113,7 +113,7 @@ open class CaretLink: Button, MVMCoreUIViewConstrainingProtocol { caretView.widthAnchor.constraint(equalToConstant: width).isActive = true caretView.heightAnchor.constraint(equalToConstant: height).isActive = true - let caretLabelSpacing = caretView.leadingAnchor.constraint(equalTo: titleLabel?.trailingAnchor, constant: 7) + let caretLabelSpacing = NSLayoutConstraint(item: caretView, attribute: .left, relatedBy: .equal, toItem: titleLabel, attribute: .right, multiplier: 1.0, constant: 7) caretLabelSpacing.isActive = true caretSpacingConstraint = caretLabelSpacing From d9337cadff6bee8405d15840fa5bee0d8eaeb51c Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 7 Apr 2020 13:37:12 -0400 Subject: [PATCH 26/62] cleaning and revising donut --- MVMCoreUI.xcodeproj/project.pbxproj | 8 + .../Doughnut/ColorViewWithLabel.swift | 73 +++++ .../Molecules/Doughnut/DoughnutChart.swift | 292 ++++++++++-------- .../Doughnut/DoughnutChartItemModel.swift | 44 +++ .../Doughnut/DoughnutChartModel.swift | 24 +- .../Doughnut/DoughnutChartView.swift | 76 ++--- 6 files changed, 312 insertions(+), 205 deletions(-) create mode 100644 MVMCoreUI/Atomic/Molecules/Doughnut/ColorViewWithLabel.swift create mode 100644 MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartItemModel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index c0a56ebc..67f83ce7 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -91,6 +91,8 @@ 0A6BF4722360C56C0028F841 /* BaseDropdownEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A6BF4712360C56C0028F841 /* BaseDropdownEntryField.swift */; }; 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */; }; 0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */; }; + 0A7ECC5D243CE85300C828E8 /* DoughnutChartItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7ECC5C243CE85300C828E8 /* DoughnutChartItemModel.swift */; }; + 0A7ECC5F243CEB1200C828E8 /* ColorViewWithLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7ECC5E243CEB1200C828E8 /* ColorViewWithLabel.swift */; }; 0A7EF85B23D8A52800B2AAD1 /* EntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85A23D8A52800B2AAD1 /* EntryFieldModel.swift */; }; 0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */; }; 0A7EF85F23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A7EF85E23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift */; }; @@ -488,6 +490,8 @@ 0A7BAD73232A8DC700FB8E22 /* HeadlineBodyButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadlineBodyButton.swift; sourceTree = ""; }; 0A7BAFA0232BE61800FB8E22 /* Checkbox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = ""; }; 0A7BAFA2232BE63400FB8E22 /* CheckboxLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxLabel.swift; sourceTree = ""; }; + 0A7ECC5C243CE85300C828E8 /* DoughnutChartItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DoughnutChartItemModel.swift; sourceTree = ""; }; + 0A7ECC5E243CEB1200C828E8 /* ColorViewWithLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColorViewWithLabel.swift; sourceTree = ""; }; 0A7EF85A23D8A52800B2AAD1 /* EntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EntryFieldModel.swift; sourceTree = ""; }; 0A7EF85C23D8A95600B2AAD1 /* TextEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextEntryFieldModel.swift; sourceTree = ""; }; 0A7EF85E23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MdnEntryFieldModel.swift; sourceTree = ""; }; @@ -1340,9 +1344,11 @@ D260105723CF9CC500764D80 /* Doughnut */ = { isa = PBXGroup; children = ( + 0A7ECC5C243CE85300C828E8 /* DoughnutChartItemModel.swift */, C695A69323C9909000BFB94E /* DoughnutChartModel.swift */, C695A69523C990BC00BFB94E /* DoughnutChart.swift */, C695A69723C990C200BFB94E /* DoughnutChartView.swift */, + 0A7ECC5E243CEB1200C828E8 /* ColorViewWithLabel.swift */, ); path = Doughnut; sourceTree = ""; @@ -2067,6 +2073,7 @@ D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */, DBEFFA04225A829700230692 /* Label.swift in Sources */, D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */, + 0A7ECC5D243CE85300C828E8 /* DoughnutChartItemModel.swift in Sources */, 0A7EF85F23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift in Sources */, 011D959B240451E3000E3791 /* RuleRequiredModel.swift in Sources */, 526A265C240D1FF700B0D828 /* ListTwoColumnCompareChangesModel.swift in Sources */, @@ -2173,6 +2180,7 @@ C695A67F23C9830600BFB94E /* UnOrderedListModel.swift in Sources */, 0AE98BB523FF18D2004C5109 /* Arrow.swift in Sources */, D2D90B442404789000DD6EC9 /* MoleculeContainerProtocol.swift in Sources */, + 0A7ECC5F243CEB1200C828E8 /* ColorViewWithLabel.swift in Sources */, 94C0150A24215643005811A9 /* ActionTopAlertModel.swift in Sources */, 012A88DB238ED45900FE3DA1 /* CarouselModel.swift in Sources */, D29DF28C21E7AC2B003B2FB9 /* ViewConstrainingView.m in Sources */, diff --git a/MVMCoreUI/Atomic/Molecules/Doughnut/ColorViewWithLabel.swift b/MVMCoreUI/Atomic/Molecules/Doughnut/ColorViewWithLabel.swift new file mode 100644 index 00000000..f8dd4b5c --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/Doughnut/ColorViewWithLabel.swift @@ -0,0 +1,73 @@ +// +// ColorViewWithLabel.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 4/7/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + + +open class ColorViewWithLabel: View { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public var label = Label.createLabelRegularBodySmall(true) + public var colorView = View() + private var sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: 8)! + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + + public var heightConstraint: NSLayoutConstraint? + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + + open override func setupView() { + super.setupView() + + addSubview(colorView) + addSubview(label) + + heightConstraint = colorView.heightAnchor.constraint(equalToConstant: sizeObject.getValueBasedOnApplicationWidth()) + heightConstraint?.isActive = true + colorView.widthAnchor.constraint(equalTo: colorView.heightAnchor).isActive = true + colorView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true + colorView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + + label.leadingAnchor.constraint(equalTo: colorView.trailingAnchor, constant: PaddingOne).isActive = true + label.topAnchor.constraint(equalTo: topAnchor).isActive = true + trailingAnchor.constraint(equalTo: label.trailingAnchor).isActive = true + bottomAnchor.constraint(equalTo: label.bottomAnchor).isActive = true + } + + open override func updateView(_ size: CGFloat) { + super.updateView(size) + label.updateView(size) + heightConstraint?.constant = sizeObject.getValueBased(onSize: size) + setNeedsDisplay() + } + + open override func reset() { + super.reset() + label.reset() + } + + //-------------------------------------------------- + // MARK: - MoleculeViewProtocol + //-------------------------------------------------- + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.set(with: model, delegateObject, additionalData) + + guard let chartItemModel = model as? DoughnutChartItemModel else { return } + + label.set(with: chartItemModel.label, delegateObject, additionalData) + colorView.backgroundColor = chartItemModel.color.uiColor + } +} diff --git a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChart.swift b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChart.swift index d84c7dc0..c7025b0f 100644 --- a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChart.swift +++ b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChart.swift @@ -8,23 +8,38 @@ import UIKit + open class DoughnutChart: View { - var doughnutLayer = CALayer() - var titleLabel = Label.commonLabelH3(true) - var subTitleLabel = Label.commonLabelB2(true) - var doughnutChartModel: DoughnutChartModel? { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public var doughnutLayer = CALayer() + public var titleLabel = Label.createLabelRegularTitleLarge(true) + public var subTitleLabel = Label.createLabelRegularMicro(true) + public var labelContainer = View() + public static let heightConstant: CGFloat = 136 + private var sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: heightConstant)! + + //-------------------------------------------------- + // MARK: - Constraints + //-------------------------------------------------- + + public var labelContainerLeftConstraint: NSLayoutConstraint? + public var labelContainerTopConstraint: NSLayoutConstraint? + public var labelContainerBottomConstraint: NSLayoutConstraint? + public var labelContainerRightConstraint: NSLayoutConstraint? + public var heightConstraint: NSLayoutConstraint? + + //-------------------------------------------------- + // MARK: - Computed Properties + //-------------------------------------------------- + + public var doughnutChartModel: DoughnutChartModel? { get { return model as? DoughnutChartModel } - } - var labelContainer = MVMCoreUICommonViewsUtility.commonView() - var labelContainerLeftConstraint: NSLayoutConstraint? - var labelContainerTopConstraint: NSLayoutConstraint? - var labelContainerBottomConstraint: NSLayoutConstraint? - var labelContainerRightConstraint: NSLayoutConstraint? - var heightConstraint: NSLayoutConstraint? - - static let heightConstant: CGFloat = 150 - private var sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: heightConstant)! - var height: CGFloat = heightConstant { + } + + public var height: CGFloat = heightConstant { didSet { if height != oldValue { sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: height)! @@ -32,69 +47,73 @@ open class DoughnutChart: View { drawGraph() } } - } - - open override func updateView(_ size: CGFloat) { - super.updateView(size) - titleLabel.updateView(size) - subTitleLabel.updateView(size) - updateContainer() - drawGraph() - } - - open override func reset() { - super.reset() - titleLabel.reset() - subTitleLabel.reset() - clearLayers() - } - - open override func setupView() { - super.setupView() - guard labelContainer.superview == nil else { - return - } - addSubview(labelContainer) - - labelContainer.addSubview(titleLabel) - labelContainer.addSubview(subTitleLabel) - titleLabel.textAlignment = .center - subTitleLabel.textAlignment = .center - - //Make label font size to adjust width if label content is high - titleLabel.numberOfLines = 1 - titleLabel.adjustsFontSizeToFitWidth = true - - layer.addSublayer(doughnutLayer) - heightConstraint = heightAnchor.constraint(equalToConstant: - sizeObject.getValueBasedOnApplicationWidth()) - heightConstraint?.isActive = true - widthAnchor.constraint(equalTo: heightAnchor).isActive = true - - labelContainerLeftConstraint = labelContainer.leftAnchor.constraint(greaterThanOrEqualTo: leftAnchor, constant: lineWidth()) - labelContainerLeftConstraint?.isActive = true - labelContainerTopConstraint = labelContainer.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: lineWidth()) - labelContainerTopConstraint?.isActive = true - labelContainerRightConstraint = rightAnchor.constraint(greaterThanOrEqualTo: labelContainer.rightAnchor, constant: lineWidth()) - labelContainerRightConstraint?.isActive = true - labelContainerBottomConstraint = bottomAnchor.constraint(greaterThanOrEqualTo: labelContainer.bottomAnchor, constant: lineWidth()) - labelContainerBottomConstraint?.isActive = true - labelContainer.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true - labelContainer.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true - - NSLayoutConstraint.constraintPinSubview(titleLabel, pinTop: true, pinBottom: false, pinLeft: true, pinRight: true) - NSLayoutConstraint.constraintPinSubview(subTitleLabel, pinTop: false, pinBottom: true, pinLeft: true, pinRight: true) - _ = NSLayoutConstraint(pinFirstView: titleLabel, toSecondView: subTitleLabel, withConstant: 0, directionVertical: true) - //Rotate view for initial draw - doughnutLayer.transform = CATransform3DMakeRotation(1 * .pi, 0.0, 0.0, 1.0) } - open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + + open override func updateView(_ size: CGFloat) { + super.updateView(size) + titleLabel.updateView(size) + subTitleLabel.updateView(size) + updateContainer() + drawGraph() + } + + open override func reset() { + super.reset() + titleLabel.reset() + subTitleLabel.reset() + clearLayers() + } + + open override func setupView() { + super.setupView() + + addSubview(labelContainer) + + labelContainer.addSubview(titleLabel) + labelContainer.addSubview(subTitleLabel) + titleLabel.textAlignment = .center + subTitleLabel.textAlignment = .center + + //Make label font size to adjust width if label content is high + titleLabel.numberOfLines = 1 + titleLabel.adjustsFontSizeToFitWidth = true + + layer.addSublayer(doughnutLayer) + heightConstraint = heightAnchor.constraint(equalToConstant: sizeObject.getValueBasedOnApplicationWidth()) + heightConstraint?.isActive = true + widthAnchor.constraint(equalTo: heightAnchor).isActive = true + + labelContainerLeftConstraint = labelContainer.leadingAnchor.constraint(greaterThanOrEqualTo: leadingAnchor, constant: lineWidth()) + labelContainerLeftConstraint?.isActive = true + labelContainerTopConstraint = labelContainer.topAnchor.constraint(greaterThanOrEqualTo: topAnchor, constant: lineWidth()) + labelContainerTopConstraint?.isActive = true + labelContainerRightConstraint = trailingAnchor.constraint(greaterThanOrEqualTo: labelContainer.trailingAnchor, constant: lineWidth()) + labelContainerRightConstraint?.isActive = true + labelContainerBottomConstraint = bottomAnchor.constraint(greaterThanOrEqualTo: labelContainer.bottomAnchor, constant: lineWidth()) + labelContainerBottomConstraint?.isActive = true + labelContainer.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true + labelContainer.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true + + NSLayoutConstraint.constraintPinSubview(titleLabel, pinTop: true, pinBottom: false, pinLeft: true, pinRight: true) + NSLayoutConstraint.constraintPinSubview(subTitleLabel, pinTop: false, pinBottom: true, pinLeft: true, pinRight: true) + _ = NSLayoutConstraint(pinFirstView: titleLabel, toSecondView: subTitleLabel, withConstant: 0, directionVertical: true) + //Rotate view for initial draw + doughnutLayer.transform = CATransform3DMakeRotation(1 * .pi, 0, 0, 1) + } + + //-------------------------------------------------- + // MARK: - MoleculeViewProtocol + //-------------------------------------------------- + + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) clearLayers() - guard let doughnutChartModel = doughnutChartModel else { - return - } + guard let doughnutChartModel = doughnutChartModel else { return } + titleLabel.setOptional(with: doughnutChartModel.title, delegateObject, additionalData) subTitleLabel.setOptional(with: doughnutChartModel.subtitle, delegateObject, additionalData) titleLabel.textAlignment = .center @@ -103,78 +122,83 @@ open class DoughnutChart: View { drawGraph() } - func drawGraph() { - clearLayers() - let widthHeight = sizeObject.getValueBasedOnApplicationWidth() - doughnutLayer.frame = CGRect(x: 0, y: 0, - width: widthHeight, - height: widthHeight) - if let doughnutChart = doughnutChartModel { - var prevPercent: CGFloat = 0.0 - for model in doughnutChart.sections { + //-------------------------------------------------- + // MARK: - Draw Graph + //-------------------------------------------------- + + private func drawGraph() { + clearLayers() + let widthHeight = sizeObject.getValueBasedOnApplicationWidth() + doughnutLayer.frame = CGRect(x: 0, y: 0, width: widthHeight, height: widthHeight) + + if let doughnutChart = doughnutChartModel { + var prevPercent: CGFloat = 0.0 + for model in doughnutChart.sections { prevPercent += drawBar(model, prevPercent) - } - } - } - - func drawBar(_ chartModel: DoughnutChartItemModel, _ prevPercent: CGFloat) -> CGFloat { - - let shapeLayer = CAShapeLayer() - shapeLayer.frame = doughnutLayer.frame - shapeLayer.lineWidth = lineWidth() - shapeLayer.fillColor = nil - shapeLayer.strokeColor = chartModel.color.uiColor.cgColor - - let arcCenter = shapeLayer.position - let radius = shapeLayer.bounds.size.width / 2.0 - lineWidth()/2.0 - - let value: CGFloat = chartModel.percent - let gap: CGFloat = spaceRequired() ? lineGap() : 0.0 - let startAngle = ((prevPercent / 100.0) * 2 * .pi) - (0.5 * .pi) - let endAngle = ((value / 100.0) * 2 * .pi) + startAngle - gap - let circlePath = UIBezierPath(arcCenter: arcCenter, - radius: radius, - startAngle: startAngle, - endAngle: endAngle, - clockwise: true) - - shapeLayer.path = circlePath.cgPath - doughnutLayer.addSublayer(shapeLayer) - return value - } - - func clearLayers() { - doughnutLayer.sublayers?.forEach({ $0.removeFromSuperlayer() }) - } + } + } + } - func updateContainer() { - heightConstraint?.constant = sizeObject.getValueBasedOnApplicationWidth() - updateLabelContainer() - setNeedsDisplay() - } + private func drawBar(_ chartModel: DoughnutChartItemModel, _ prevPercent: CGFloat) -> CGFloat { + + let shapeLayer = CAShapeLayer() + shapeLayer.frame = doughnutLayer.frame + shapeLayer.lineWidth = lineWidth() + shapeLayer.fillColor = nil + shapeLayer.strokeColor = chartModel.color.uiColor.cgColor + + let arcCenter = shapeLayer.position + let radius = shapeLayer.bounds.size.width / 2.0 - lineWidth() / 2.0 + + let value: CGFloat = chartModel.percent + let gap: CGFloat = spaceRequired() ? lineGap() : 0.0 + let startAngle = ((prevPercent / 100.0) * 2 * .pi) - (0.5 * .pi) + let endAngle = ((value / 100.0) * 2 * .pi) + startAngle - gap + let circlePath = UIBezierPath(arcCenter: arcCenter, + radius: radius, + startAngle: startAngle, + endAngle: endAngle, + clockwise: true) + + shapeLayer.path = circlePath.cgPath + doughnutLayer.addSublayer(shapeLayer) + return value + } - func lineWidth() -> CGFloat { - return 30 - } + private func clearLayers() { + doughnutLayer.sublayers?.forEach{ $0.removeFromSuperlayer() } + } - func lineGap() -> CGFloat { + public func updateContainer() { + + heightConstraint?.constant = sizeObject.getValueBasedOnApplicationWidth() + updateLabelContainer() + setNeedsDisplay() + } + + public func lineWidth() -> CGFloat { + return 12 + } + + public func lineGap() -> CGFloat { //If array is having the single item then no space required return doughnutChartModel?.sections.count == 1 ? 0.0 : 0.05 - } + } - func spaceRequired() -> Bool { + public func spaceRequired() -> Bool { return doughnutChartModel?.spaceRequired ?? true - } + } - func updateLabelContainer() { + public func updateLabelContainer() { + labelContainer.setNeedsDisplay() labelContainer.layoutIfNeeded() - let radius = sizeObject.getValueBasedOnApplicationWidth()/2 - lineWidth() - let labelheight = labelContainer.frame.height/2 - let padding = sizeObject.getValueBasedOnApplicationWidth()/2 - sqrt(max(0, pow(radius, 2) - pow(labelheight, 2))) + let radius = sizeObject.getValueBasedOnApplicationWidth() / 2 - lineWidth() + let labelheight = labelContainer.frame.height / 2 + let padding = sizeObject.getValueBasedOnApplicationWidth() / 2 - sqrt(max(0, pow(radius, 2) - pow(labelheight, 2))) - labelContainerLeftConstraint?.constant = padding - labelContainerRightConstraint?.constant = padding + labelContainerLeftConstraint?.constant = round(padding) + labelContainerRightConstraint?.constant = round(padding) labelContainerTopConstraint?.constant = max(radius - labelheight, labelheight) labelContainerBottomConstraint?.constant = max(radius - labelheight, labelheight) } diff --git a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartItemModel.swift b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartItemModel.swift new file mode 100644 index 00000000..ee4e664a --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartItemModel.swift @@ -0,0 +1,44 @@ +// +// DoughnutChartItemModel.swift +// MVMCoreUI +// +// Created by Kevin Christiano on 4/7/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + + +@objcMembers public class DoughnutChartItemModel: MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public var backgroundColor: Color? + public static var identifier: String = "doughnutChartItem" + public var moleculeName: String = DoughnutChartItemModel.identifier + public var label: LabelModel + @Percent public var percent: CGFloat + public var color: Color + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case backgroundColor + case label + case percent + case color + } + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + + public init(percent: CGFloat, color: Color, label: LabelModel) { + self.percent = percent + self.color = color + self.label = label + } +} diff --git a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartModel.swift b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartModel.swift index ff9b1bf6..fbb034c6 100644 --- a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartModel.swift +++ b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartModel.swift @@ -8,7 +8,12 @@ import Foundation + @objcMembers public class DoughnutChartModel: MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public var backgroundColor: Color? public static var identifier: String = "doughnutChart" public var moleculeName: String = DoughnutChartModel.identifier @@ -17,22 +22,11 @@ import Foundation public var sections: [DoughnutChartItemModel] public var spaceRequired: Bool? + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(sections: [DoughnutChartItemModel]) { self.sections = sections } } - -@objcMembers public class DoughnutChartItemModel: MoleculeModelProtocol { - public var backgroundColor: Color? - public static var identifier: String = "doughnutChartItem" - public var moleculeName: String = DoughnutChartItemModel.identifier - public var label: LabelModel - @Percent public var percent: CGFloat - public var color: Color - - public init(percent: CGFloat, color: Color, label: LabelModel) { - self.percent = percent - self.color = color - self.label = label - } -} diff --git a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartView.swift b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartView.swift index 280385cb..e037c984 100644 --- a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartView.swift +++ b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartView.swift @@ -8,18 +8,26 @@ import Foundation + @objcMembers open class DoughnutChartView: View { - var doughnutChart = DoughnutChart(frame: CGRect.zero) + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + var doughnutChart = DoughnutChart(frame: .zero) var colorLablesStack = ColorViewLabelsStack() + var doughnutChartModel: DoughnutChartModel? { - get { return model as? DoughnutChartModel } + get { return model as? DoughnutChartModel } } + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open override func setupView() { super.setupView() - guard doughnutChart.superview == nil else { - return - } + doughnutChart.translatesAutoresizingMaskIntoConstraints = false addSubview(doughnutChart) colorLablesStack.translatesAutoresizingMaskIntoConstraints = false @@ -65,12 +73,16 @@ import Foundation colorLablesStack.reset() } + //-------------------------------------------------- + // MARK: - MoleculeViewProtocol + //-------------------------------------------------- + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { super.set(with: model, delegateObject, additionalData) guard let model = doughnutChartModel else { return } doughnutChart.set(with: model, delegateObject, additionalData) - + // Create the stack model var stackItems: [MoleculeStackItemModel] = [] for item in model.sections { @@ -82,6 +94,7 @@ import Foundation } } +// MARK: - MVMCoreUIViewConstrainingProtocol extension DoughnutChartView: MVMCoreUIViewConstrainingProtocol { open func horizontalAlignment() -> UIStackView.Alignment { return .leading @@ -89,6 +102,7 @@ extension DoughnutChartView: MVMCoreUIViewConstrainingProtocol { } class ColorViewLabelsStack: MoleculeStackView { + override func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { guard let stackItemModels = stackModel?.molecules else { return } for model in stackItemModels { @@ -99,53 +113,3 @@ class ColorViewLabelsStack: MoleculeStackView { } } } - -class ColorViewWithLabel: View { - - var label = Label.commonLabelB2(true) - var colorView = MVMCoreUICommonViewsUtility.commonView() - private var sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: 8)! - var heightConstraint: NSLayoutConstraint? - - override func setupView() { - super.setupView() - guard colorView.superview == nil else { - return - } - translatesAutoresizingMaskIntoConstraints = false - addSubview(colorView) - addSubview(label) - - heightConstraint = colorView.heightAnchor.constraint(equalToConstant: sizeObject.getValueBasedOnApplicationWidth()) - heightConstraint?.isActive = true - colorView.widthAnchor.constraint(equalTo: colorView.heightAnchor).isActive = true - colorView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true - colorView.centerYAnchor.constraint(equalTo: centerYAnchor).isActive = true - - label.leadingAnchor.constraint(equalTo: colorView.trailingAnchor, constant: PaddingOne).isActive = true - label.topAnchor.constraint(equalTo: topAnchor).isActive = true - trailingAnchor.constraint(equalTo: label.trailingAnchor).isActive = true - bottomAnchor.constraint(equalTo: label.bottomAnchor).isActive = true - } - - override func updateView(_ size: CGFloat) { - super.updateView(size) - label.updateView(size) - heightConstraint?.constant = sizeObject.getValueBased(onSize: size) - setNeedsDisplay() - } - - override func reset() { - super.reset() - label.reset() - } - - override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { - super.set(with: model, delegateObject, additionalData) - guard let chartItemModel = model as? DoughnutChartItemModel else { - return - } - label.set(with: chartItemModel.label, delegateObject, additionalData) - colorView.backgroundColor = chartItemModel.color.uiColor - } -} From f125d55962e7b8f43885429c38de7b0442c3d395 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 7 Apr 2020 14:10:32 -0400 Subject: [PATCH 27/62] improved constraints to center align as requested by design --- .../Molecules/Doughnut/DoughnutChart.swift | 18 ++++++++++++++++- .../Doughnut/DoughnutChartView.swift | 20 +++++++++---------- 2 files changed, 26 insertions(+), 12 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChart.swift b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChart.swift index c7025b0f..2908a90d 100644 --- a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChart.swift +++ b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChart.swift @@ -15,7 +15,7 @@ open class DoughnutChart: View { //-------------------------------------------------- public var doughnutLayer = CALayer() - public var titleLabel = Label.createLabelRegularTitleLarge(true) + public var titleLabel = Label.createLabelBoldTitleLarge(true) public var subTitleLabel = Label.createLabelRegularMicro(true) public var labelContainer = View() public static let heightConstant: CGFloat = 136 @@ -49,6 +49,22 @@ open class DoughnutChart: View { } } + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + + public override init(frame: CGRect) { + super.init(frame: .zero) + } + + public convenience init() { + self.init(frame: .zero) + } + + public required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartView.swift b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartView.swift index e037c984..2b3afdd5 100644 --- a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartView.swift +++ b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartView.swift @@ -28,35 +28,33 @@ import Foundation open override func setupView() { super.setupView() - doughnutChart.translatesAutoresizingMaskIntoConstraints = false addSubview(doughnutChart) - colorLablesStack.translatesAutoresizingMaskIntoConstraints = false addSubview(colorLablesStack) doughnutChart.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true - doughnutChart.topAnchor.constraint(equalTo: topAnchor).isActive = true + doughnutChart.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true + bottomAnchor.constraint(greaterThanOrEqualTo: doughnutChart.bottomAnchor).isActive = true let doughnutBottomAnchor = bottomAnchor.constraint(equalTo: doughnutChart.bottomAnchor) doughnutBottomAnchor.priority = UILayoutPriority(rawValue: 200) doughnutBottomAnchor.isActive = true + bottomAnchor.constraint(greaterThanOrEqualTo: colorLablesStack.bottomAnchor).isActive = true + let colorLablesBottomAnchor = bottomAnchor.constraint(equalTo: colorLablesStack.bottomAnchor) colorLablesBottomAnchor.priority = UILayoutPriority(rawValue: 204) colorLablesBottomAnchor.isActive = true - let colorLablesTopAnchor = colorLablesStack.topAnchor.constraint(equalTo: doughnutChart.topAnchor) + colorLablesStack.topAnchor.constraint(greaterThanOrEqualTo: topAnchor).isActive = true + + let colorLablesTopAnchor = colorLablesStack.topAnchor.constraint(equalTo: topAnchor) colorLablesTopAnchor.priority = .defaultLow colorLablesTopAnchor.isActive = true - colorLablesStack.topAnchor.constraint(greaterThanOrEqualTo: doughnutChart.topAnchor).isActive = true - bottomAnchor.constraint(greaterThanOrEqualTo: colorLablesStack.bottomAnchor).isActive = true trailingAnchor.constraint(equalTo: colorLablesStack.trailingAnchor).isActive = true - - let centerY = colorLablesStack.centerYAnchor.constraint(equalTo: doughnutChart.centerYAnchor) - centerY.priority = UILayoutPriority(rawValue: 500) - centerY.isActive = true - + doughnutChart.centerYAnchor.constraint(equalTo: colorLablesStack.centerYAnchor).isActive = true + colorLablesStack.leadingAnchor.constraint(equalTo: doughnutChart.trailingAnchor, constant: PaddingThree).isActive = true colorLablesStack.backgroundColor = .clear } From 752ff76e79f6bac7f1a6724a0fca3a4e108ad5dc Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 7 Apr 2020 14:22:06 -0400 Subject: [PATCH 28/62] access modified --- .../Atomic/Molecules/Doughnut/DoughnutChartView.swift | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartView.swift b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartView.swift index 2b3afdd5..1c0ea963 100644 --- a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartView.swift +++ b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartView.swift @@ -14,10 +14,10 @@ import Foundation // MARK: - Properties //-------------------------------------------------- - var doughnutChart = DoughnutChart(frame: .zero) + public var doughnutChart = DoughnutChart() var colorLablesStack = ColorViewLabelsStack() - var doughnutChartModel: DoughnutChartModel? { + public var doughnutChartModel: DoughnutChartModel? { get { return model as? DoughnutChartModel } } @@ -75,7 +75,7 @@ import Foundation // MARK: - MoleculeViewProtocol //-------------------------------------------------- - open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) guard let model = doughnutChartModel else { return } @@ -94,6 +94,7 @@ import Foundation // MARK: - MVMCoreUIViewConstrainingProtocol extension DoughnutChartView: MVMCoreUIViewConstrainingProtocol { + open func horizontalAlignment() -> UIStackView.Alignment { return .leading } @@ -101,7 +102,7 @@ extension DoughnutChartView: MVMCoreUIViewConstrainingProtocol { class ColorViewLabelsStack: MoleculeStackView { - override func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + override func createStackItemsFromModel(_ model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { guard let stackItemModels = stackModel?.molecules else { return } for model in stackItemModels { let view = ColorViewWithLabel() From 8072d8d4aa585a19df1a7e55d5748e7d7d0cf5ba Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 7 Apr 2020 14:33:57 -0400 Subject: [PATCH 29/62] organized radio --- .../Atomic/Atoms/Buttons/RadioButton.swift | 23 +++++++-------- .../Buttons/RadioButtonSelectionHelper.swift | 28 ++++++++++++++----- 2 files changed, 33 insertions(+), 18 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/RadioButton.swift b/MVMCoreUI/Atomic/Atoms/Buttons/RadioButton.swift index 98532549..b73ddc8b 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/RadioButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/RadioButton.swift @@ -8,6 +8,7 @@ import UIKit + @objcMembers open class RadioButton: Control { //-------------------------------------------------- // MARK: - Properties @@ -18,19 +19,19 @@ import UIKit widthConstraint?.constant = diameter } } - - public var enabledColor: UIColor = .black - public var disabledColor: UIColor = .mfSilver() + + public var enabledColor: UIColor = .mvmBlack + public var disabledColor: UIColor = .mvmCoolGray6 public var delegateObject: MVMCoreUIDelegateObject? public var radioModel: RadioButtonModel? { return model as? RadioButtonModel } - + lazy public var radioGroupName: String? = { return radioModel?.fieldKey }() - + lazy public var radioButtonSelectionHelper: RadioButtonSelectionHelper? = { if let radioGroupName = radioGroupName, let radioButtonModel = delegateObject?.formHolderDelegate?.formValidator?.radioButtonsModelByGroup[radioGroupName] { @@ -100,7 +101,7 @@ import UIKit public func formFieldValue() -> AnyHashable? { return radioModel?.fieldValue } - + //-------------------------------------------------- // MARK: - MVMViewProtocol //-------------------------------------------------- @@ -108,7 +109,7 @@ import UIKit open override func setupView() { super.setupView() - backgroundColor = .white + backgroundColor = .mvmWhite clipsToBounds = true widthConstraint = widthAnchor.constraint(equalToConstant: 30) widthConstraint?.isActive = true @@ -120,7 +121,7 @@ import UIKit accessibilityTraits = .button accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "radio_action_hint") } - + public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) @@ -130,9 +131,9 @@ import UIKit isSelected = model.state RadioButtonSelectionHelper.setupForRadioButtonGroup(model, self, delegateObject: delegateObject) } - + public override func reset() { - super.reset() - backgroundColor = .white + super.reset() + backgroundColor = .white } } diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/RadioButtonSelectionHelper.swift b/MVMCoreUI/Atomic/Atoms/Buttons/RadioButtonSelectionHelper.swift index 3decadb5..c7208802 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/RadioButtonSelectionHelper.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/RadioButtonSelectionHelper.swift @@ -7,29 +7,41 @@ // import Foundation -import UIKit + @objcMembers public class RadioButtonSelectionHelper: FormFieldProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public var fieldKey: String? public var groupName: String = FormValidator.defaultGroupName private var selectedRadioButton: RadioButton? private var fieldGroupName: String? public var baseValue: AnyHashable? - + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + init(_ fieldKey: String?) { self.fieldKey = fieldKey } + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + public static func setupForRadioButtonGroup(_ radioButtonModel: RadioButtonModel, _ radioButton: RadioButton, delegateObject: MVMCoreUIDelegateObject?) { + guard let groupName = radioButtonModel.fieldKey, - let formValidator = delegateObject?.formHolderDelegate?.formValidator else { - return - } + let formValidator = delegateObject?.formHolderDelegate?.formValidator + else { return } let radioButtonSelectionHelper = formValidator.radioButtonsModelByGroup[groupName] ?? RadioButtonSelectionHelper(radioButtonModel.fieldKey) radioButtonSelectionHelper.fieldGroupName = radioButtonModel.fieldKey formValidator.radioButtonsModelByGroup[groupName] = radioButtonSelectionHelper - + if radioButtonModel.state { radioButtonSelectionHelper.selectedRadioButton = radioButton } @@ -37,6 +49,7 @@ import UIKit } public func selected(_ radioButton: RadioButton) { + selectedRadioButton?.isSelected = false selectedRadioButton = radioButton selectedRadioButton?.isSelected = true @@ -45,8 +58,9 @@ import UIKit // MARK: - FormValidationFormFieldProtocol extension RadioButtonSelectionHelper { + public func formFieldGroupName() -> String? { - return selectedRadioButton?.formFieldGroupName() ?? self.fieldGroupName + return selectedRadioButton?.formFieldGroupName() ?? fieldGroupName } public func formFieldValue() -> AnyHashable? { From 6ca54fce6a4679ddb01c31dec363297e4bc406d2 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Tue, 7 Apr 2020 15:22:33 -0400 Subject: [PATCH 30/62] settingup new accessor --- MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift index 658af357..c12b7dd3 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift @@ -57,6 +57,12 @@ import UIKit } } + public var accessoryInput: View? { + didSet { + + } + } + //-------------------------------------------------- // MARK: - Computed Properties //-------------------------------------------------- @@ -209,6 +215,9 @@ import UIKit feedbackLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: feedbackLabel.trailingAnchor) feedbackLabelTrailing?.isActive = true layoutMarginsGuide.bottomAnchor.constraint(equalTo: feedbackLabel.bottomAnchor).isActive = true + + container.trailingAnchor.constraint(equalTo: dropDownCaretView.trailingAnchor, constant: 16).isActive = true + dropDownCaretView.centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true } @objc open override func layoutSubviews() { From d53b21224183a14fedb07a5c2debc271ce03d29e Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Tue, 7 Apr 2020 15:29:23 -0400 Subject: [PATCH 31/62] fiddling with three layer --- MVMCoreUI.xcodeproj/project.pbxproj | 4 + MVMCoreUI/Atomic/MoleculeObjectMapping.swift | 4 +- .../Doughnut/DoughnutChartModel.swift | 7 + .../Atomic/Templates/CollectionTemplate.swift | 162 ++++++++++ .../ContainerCollectionReusableView.swift | 25 ++ .../ThreeLayerCollectionViewController.swift | 281 +++++++++--------- MVMCoreUI/Utility/MVMCoreUIUtility.m | 2 +- 7 files changed, 348 insertions(+), 137 deletions(-) create mode 100644 MVMCoreUI/BaseControllers/ContainerCollectionReusableView.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index e1310f0d..6db35f4e 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -249,6 +249,7 @@ D264FA8C243BCD8E00D98315 /* CollectionTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FA8B243BCD8E00D98315 /* CollectionTemplateModel.swift */; }; D264FA8E243BCD9A00D98315 /* CollectionTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FA8D243BCD9A00D98315 /* CollectionTemplate.swift */; }; D264FA90243BCE6800D98315 /* ThreeLayerCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FA8F243BCE6800D98315 /* ThreeLayerCollectionViewController.swift */; }; + D264FAA1243CF66B00D98315 /* ContainerCollectionReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FAA0243CF66B00D98315 /* ContainerCollectionReusableView.swift */; }; D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368A23609801006832FA /* MoleculeStackItemModel.swift */; }; D268C70E238C22D7007F2C1C /* DropDownFilterTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */; }; D26C5A6B23F4A40D007AEECE /* ListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */; }; @@ -654,6 +655,7 @@ D264FA8B243BCD8E00D98315 /* CollectionTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionTemplateModel.swift; sourceTree = ""; }; D264FA8D243BCD9A00D98315 /* CollectionTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionTemplate.swift; sourceTree = ""; }; D264FA8F243BCE6800D98315 /* ThreeLayerCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerCollectionViewController.swift; sourceTree = ""; }; + D264FAA0243CF66B00D98315 /* ContainerCollectionReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerCollectionReusableView.swift; sourceTree = ""; }; D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropDownFilterTableViewCell.swift; sourceTree = ""; }; D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemModel.swift; sourceTree = ""; }; D274CA322236A78900B01B62 /* FooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FooterView.swift; sourceTree = ""; }; @@ -1477,6 +1479,7 @@ D29DF2CD21E7C104003B2FB9 /* MFLoadingViewController.m */, D2A5146A2214905000345BFB /* ThreeLayerViewController.swift */, D2E1FADE2268B8E700AEFD8C /* ThreeLayerTableViewController.swift */, + D264FAA0243CF66B00D98315 /* ContainerCollectionReusableView.swift */, D264FA8F243BCE6800D98315 /* ThreeLayerCollectionViewController.swift */, D2C521A823EDE79E00CA2634 /* ViewController.swift */, D2A92881241AAB67004E01C6 /* ScrollingViewController.swift */, @@ -2029,6 +2032,7 @@ D21B7F77243BB70700051ABF /* MoleculeCollectionItemModel.swift in Sources */, D29DF2B421E7B76D003B2FB9 /* MFLoadingSpinner.m in Sources */, 011D9602240DA20A000E3791 /* FormRuleWatcherFieldProtocol.swift in Sources */, + D264FAA1243CF66B00D98315 /* ContainerCollectionReusableView.swift in Sources */, D260106323D0C05000764D80 /* StackItemModel.swift in Sources */, D2E2A99823D8D63C000B42E6 /* ActionDetailWithImageModel.swift in Sources */, D2E2A99D23DA3217000B42E6 /* UIStackViewAlignment+Extension.swift in Sources */, diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index 94bbc61f..5ef0e20e 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -112,7 +112,9 @@ import Foundation // Other Items MoleculeObjectMapping.shared()?.register(viewClass: MoleculeStackItem.self, viewModelClass: MoleculeStackItemModel.self) MoleculeObjectMapping.shared()?.register(viewClass: StackItem.self, viewModelClass: StackItemModel.self) - MoleculeObjectMapping.shared()?.register(viewClass: MoleculeCollectionViewCell.self, viewModelClass: CarouselItemModel.self) + MoleculeObjectMapping.shared()?.register(viewClass: MoleculeCollectionViewCell.self, viewModelClass: MoleculeCollectionItemModel.self) + MoleculeObjectMapping.shared()?.register(viewClass: CarouselItem.self, viewModelClass: CarouselItemModel.self) + // Other Container Molecules MoleculeObjectMapping.shared()?.register(viewClass: MoleculeHeaderView.self, viewModelClass: MoleculeHeaderModel.self) diff --git a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartModel.swift b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartModel.swift index ff9b1bf6..2b64d1ae 100644 --- a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartModel.swift +++ b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartModel.swift @@ -35,4 +35,11 @@ import Foundation self.color = color self.label = label } + + private enum CodingKeys: String, CodingKey { + case backgroundColor + case label + case percent + case color + } } diff --git a/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift index ce135631..11142532 100644 --- a/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift @@ -11,5 +11,167 @@ import Foundation @objc open class CollectionTemplate: ThreeLayerCollectionViewController, TemplateProtocol { public typealias TemplateModel = CollectionTemplateModel public var templateModel: CollectionTemplateModel? + + public var moleculesInfo: [(identifier: String, class: AnyClass, molecule: (CollectionItemModelProtocol & MoleculeModelProtocol))]? + + var observer: NSKeyValueObservation? + //-------------------------------------------------- + // MARK: - Computed Properties + //-------------------------------------------------- + open override func parsePageJSON() throws { + try parseTemplate(json: loadObject?.pageJSON) + try super.parsePageJSON() + } + + open override var loadObject: MVMCoreLoadObject? { + didSet { + guard loadObject != oldValue else { return } + + updateRequiredModules() + observer?.invalidate() + if let newObject = loadObject { + observer = newObject.observe(\MVMCoreLoadObject.pageJSON, options: [.old, .new]) { [weak self] object, change in + self?.updateRequiredModules() + } + } + } + } + + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + + open override func viewForTop() -> UIView? { + guard let headerModel = templateModel?.header, + let molecule = MoleculeObjectMapping.shared()?.createMolecule(headerModel, delegateObject: delegateObjectIVar) + else { return super.viewForTop() } + + // Temporary, Default the horizontal padding + if var container = templateModel?.header as? ContainerModelProtocol, container.useHorizontalMargins == nil { + container.useHorizontalMargins = true + } + + return molecule + } + + override open func viewForBottom() -> UIView? { + guard let footerModel = templateModel?.footer, + let molecule = MoleculeObjectMapping.shared()?.createMolecule(footerModel, delegateObject: delegateObjectIVar) + else { return super.viewForBottom() } + + return molecule + } + + open override func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer) -> Bool { + + guard super.shouldFinishProcessingLoad(loadObject, error: error) else { return false } + + // This template requires atleast one of the three layers. + if templateModel?.header == nil, + templateModel?.molecules?.count ?? 0 == 0, + templateModel?.footer == nil, + let errorObject = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess), messageToLog: "Collection template requires atleast one of the following: header, footer, molecules", code: CoreUIErrorCode.ErrorCodeListMolecule.rawValue, domain: ErrorDomainNative, location: String(describing: self)) { + error.pointee = errorObject + return false + } + return true + } + + + open override func handleNewData() { + super.handleNewData() + setup() + registerCells() + } + + //-------------------------------------------------- + // MARK: - Collection + //-------------------------------------------------- + + open override func registerCells() { + super.registerCells() + guard let moleculesInfo = moleculesInfo else { return } + + for moleculeInfo in moleculesInfo { + collectionView?.register(moleculeInfo.class, forCellWithReuseIdentifier: moleculeInfo.identifier) + } + } + + open override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return moleculesInfo?.count ?? 0 + } + + open override func numberOfSections(in collectionView: UICollectionView) -> Int { + return 1 + } + + open override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let moleculeInfo = moleculesInfo?[indexPath.row] + else { return UICollectionViewCell() } + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: moleculeInfo.identifier, for: indexPath) + (cell as? MoleculeViewProtocol)?.reset() + (cell as? MoleculeViewProtocol)?.set(with: moleculeInfo.molecule, delegateObjectIVar, nil) + (cell as? MVMCoreViewProtocol)?.updateView(view.bounds.width) + + // Neded to fix an apple defect where the cell is not the correct size on certain devices for certain cells + cell.layoutIfNeeded() + return cell + } + + //-------------------------------------------------- + // MARK: - Convenience + //-------------------------------------------------- + + /// Returns the (identifier, class) of the molecule for the given map. + func getMoleculeInfo(with item: (CollectionItemModelProtocol & MoleculeModelProtocol)?) -> (identifier: String, class: AnyClass, molecule: CollectionItemModelProtocol & MoleculeModelProtocol)? { + guard let item = item, + let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(item) else { return nil } + let moleculeName = moleculeClass.nameForReuse(with: item, delegateObjectIVar) ?? item.moleculeName + return (moleculeName, moleculeClass, item) + } + + /// Sets up the molecule list and ensures no errors loading all content. + func getMoleculeInfoList() -> [(identifier: String, class: AnyClass, molecule: (CollectionItemModelProtocol & MoleculeModelProtocol))]? { + + var moleculeList: [(identifier: String, class: AnyClass, molecule: CollectionItemModelProtocol & MoleculeModelProtocol)] = [] + + if let molecules = templateModel?.molecules { + for molecule in molecules { + if let info = getMoleculeInfo(with: molecule) { + moleculeList.append(info) + } + } + } + + return moleculeList.count > 0 ? moleculeList : nil + } + + /// Sets up the header, footer, molecule list and ensures no errors loading all content. + func setup() { + moleculesInfo = getMoleculeInfoList() + } + + /// Adds modules from requiredModules() to the MVMCoreViewControllerMapping.requiredModules map. + open func updateRequiredModules() { + if let requiredModules = requiredModules(), let pageType = pageType { + MVMCoreViewControllerMappingObject.shared()?.addRequiredModules(toMapping: requiredModules, forPageType: pageType) + } + } + + /// Gets modules required by the loadObject.pageJSON. + open func requiredModules() -> [Any]? { + var modules: [String]? = [] + var errors: [MVMCoreErrorObject]? = nil + MoleculeObjectMapping.addRequiredModules(for: templateModel?.header, delegateObjectIVar, moduleList: &modules, errorList: &errors) + MoleculeObjectMapping.addRequiredModules(for: templateModel?.footer, delegateObjectIVar, moduleList: &modules, errorList: &errors) + + if let molecules = templateModel?.molecules { + for molecule in molecules { + MoleculeObjectMapping.addRequiredModules(for: molecule, delegateObjectIVar, moduleList: &modules, errorList: &errors) + } + } + + return modules + } } diff --git a/MVMCoreUI/BaseControllers/ContainerCollectionReusableView.swift b/MVMCoreUI/BaseControllers/ContainerCollectionReusableView.swift new file mode 100644 index 00000000..c578c273 --- /dev/null +++ b/MVMCoreUI/BaseControllers/ContainerCollectionReusableView.swift @@ -0,0 +1,25 @@ +// +// ContainerCollectionReusableView.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 4/7/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class ContainerCollectionReusableView: UICollectionReusableView { + var view: UIView? + var topConstraint: NSLayoutConstraint? + var bottomConstraint: NSLayoutConstraint? + + public func addAndContain(view: UIView) { + self.view?.removeFromSuperview() + view.setContentCompressionResistancePriority(.required, for: .vertical) + addSubview(view) + self.view = view + let constraints = NSLayoutConstraint.constraintPinSubview(toSuperview: view) + topConstraint = constraints?[ConstraintTop] as? NSLayoutConstraint + bottomConstraint = constraints?[ConstraintBot] as? NSLayoutConstraint + } +} diff --git a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift index a7b39cfd..74877925 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift @@ -8,19 +8,17 @@ import Foundation -@objc open class ThreeLayerCollectionViewController: ScrollingViewController, UICollectionViewDataSource, UICollectionViewDelegate { +@objc open class ThreeLayerCollectionViewController: ScrollingViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout { public var collectionView: UICollectionView? // The three main views private var topView: UIView? private var bottomView: UIView? - private var headerView: UIView? - private var footerView: UIView? - private var safeAreaView: UIView? + private var headerView: ContainerCollectionReusableView? + private var footerView: ContainerCollectionReusableView? var useMargins: Bool = true - public var bottomViewOutsideOfScrollArea: Bool = false - private var topViewBottomConstraint: NSLayoutConstraint? - private var bottomViewTopConstraint: NSLayoutConstraint? + private let headerID = "header" + private let footerID = "footer" //MARK: - MFViewController open override func updateViews() { @@ -28,7 +26,7 @@ import Foundation let width = view.bounds.width if let topView = topView as? MVMCoreViewProtocol { topView.updateView(width) - //showHeader(width) + // showHeader(width) } if let bottomView = bottomView as? MVMCoreViewProtocol { bottomView.updateView(width) @@ -39,8 +37,8 @@ import Foundation open override func handleNewData() { super.handleNewData() - //createViewForTableHeader() - //createViewForTableFooter() + createViewForTableHeader() + createViewForTableFooter() collectionView?.reloadData() } @@ -74,11 +72,11 @@ import Foundation return 0 } - /*open override func updateViewConstraints() { + open override func updateViewConstraints() { super.updateViewConstraints() - + guard let tableView = collectionView else { return } - + let minimumSpace: CGFloat = minimumFillSpace() var currentSpace: CGFloat = 0 var totalMinimumSpace: CGFloat = 0 @@ -86,48 +84,43 @@ import Foundation var fillTop = false if spaceBelowTopView() == nil, headerView != nil { fillTop = true - currentSpace += topViewBottomConstraint?.constant ?? 0 + currentSpace += headerView?.bottomConstraint?.constant ?? 0 totalMinimumSpace += minimumSpace } - + var fillBottom = false - if spaceAboveBottomView() == nil, !bottomViewOutsideOfScrollArea, footerView != nil { + if spaceAboveBottomView() == nil, footerView != nil { fillBottom = true - currentSpace += bottomViewTopConstraint?.constant ?? 0 + currentSpace += footerView?.topConstraint?.constant ?? 0 totalMinimumSpace += minimumSpace } - + guard fillTop || fillBottom else { return } - + let newSpace = MVMCoreUIUtility.getVariableConstraintHeight(currentSpace, in: tableView, minimumHeight: totalMinimumSpace) - + // If the bottom view is outside of the scroll, then only the top view constraint is being used, so we have to double it to account for the bottom constraint not being there when we compare to the new value. var currentSpaceForCompare: CGFloat = currentSpace - if fillTop && bottomViewOutsideOfScrollArea { + if fillTop { currentSpaceForCompare = currentSpace * 2; } - - let width = view.bounds.width + if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpaceForCompare, 0.1) { if fillTop && fillBottom { // space both let half = newSpace / 2 - topViewBottomConstraint?.constant = half - bottomViewTopConstraint?.constant = half - showHeader(width) - showFooter(width) + headerView?.bottomConstraint?.constant = half + footerView?.topConstraint?.constant = half + collectionView?.invalidateIntrinsicContentSize() } else if fillTop { // Only top is spaced (half the size if the bottom view is out of the scroll because it needs to be sized as if there are two spacers but there is only one. - if bottomViewOutsideOfScrollArea { - topViewBottomConstraint?.constant = newSpace / 2 - } else { - topViewBottomConstraint?.constant = newSpace - } - showHeader(width) + headerView?.bottomConstraint?.constant = newSpace + collectionView?.invalidateIntrinsicContentSize() } else if fillBottom { // Only bottom is spaced. - bottomViewTopConstraint?.constant = newSpace - showFooter(width) + print("newSpace \(newSpace)") + footerView?.topConstraint?.constant = newSpace + collectionView?.invalidateIntrinsicContentSize() } } } @@ -135,113 +128,99 @@ import Foundation //MARK: - Header Footer /// Gets the top view and adds it to a spacing view, headerView, and then calls showHeader. open func createViewForTableHeader() { - let topView = viewForTop() + guard let topView = viewForTop() else { + self.topView = nil + self.headerView = nil + return + } self.topView = topView - - let headerView = MVMCoreUICommonViewsUtility.commonView() - headerView.addSubview(topView) - topView.topAnchor.constraint(equalTo: headerView.topAnchor).isActive = true - topView.leftAnchor.constraint(equalTo: headerView.leftAnchor).isActive = true - headerView.rightAnchor.constraint(equalTo: topView.rightAnchor).isActive = true - topViewBottomConstraint = headerView.bottomAnchor.constraint(equalTo: topView.bottomAnchor, constant: spaceBelowTopView() ?? 0) - topViewBottomConstraint?.isActive = true - self.headerView = headerView - showHeader(nil) } /// Gets the bottom view and adds it to a spacing view, footerView, and then calls showFooter. open func createViewForTableFooter() { - let bottomView = viewForBottom() + guard let bottomView = viewForBottom() else { + self.bottomView = nil + self.footerView = nil + return + } self.bottomView = bottomView - - let footerView = MVMCoreUICommonViewsUtility.commonView() - footerView.addSubview(bottomView) - bottomViewTopConstraint = bottomView.topAnchor.constraint(equalTo: footerView.topAnchor, constant: spaceAboveBottomView() ?? 0) - 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).isActive = true - self.footerView = footerView - showFooter(nil) } - /// Takes the current headerView and adds it to the tableHeaderView - func showHeader(_ sizingWidth: CGFloat?) { - headerView?.removeFromSuperview() - tableView?.tableHeaderView = nil - guard let headerView = headerView else { - return - } - - // This extra view is needed because of the wonkiness of apple's table header. Things breaks if using autolayout. - headerView.setNeedsLayout() - headerView.layoutIfNeeded() - MVMCoreUIUtility.sizeView(toFit: headerView) - let tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: MVMCoreUIUtility.getWidth(), height: headerView.frame.height)) - tableHeaderView.addSubview(headerView) - NSLayoutConstraint.constraintPinSubview(toSuperview: headerView) - tableView?.tableHeaderView = tableHeaderView - } - - /// Takes the current footerView and adds it to the tableFooterView - func showFooter(_ sizingWidth: CGFloat?) { - footerView?.removeFromSuperview() - safeAreaView?.removeFromSuperview() - guard let footerView = footerView, let tableView = tableView else { - return - } - - if bottomViewOutsideOfScrollArea { - // put bottom view outside of scrolling area. - bottomConstraint?.isActive = false - view.addSubview(footerView) - footerView.topAnchor.constraint(equalTo: tableView.bottomAnchor).isActive = true - footerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true - view.rightAnchor.constraint(equalTo: footerView.rightAnchor).isActive = true - view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: footerView.bottomAnchor).isActive = true - safeAreaView = MVMCoreUICommonViewsUtility.getAndSetupSafeAreaView(on: view) - safeAreaView?.backgroundColor = bottomView?.backgroundColor - } else { - bottomConstraint?.isActive = true - var y: CGFloat? - if let tableFooterView = tableView.tableFooterView { - // if footer already exists, use the same y location to avoid strange moving animation - y = tableFooterView.frame.minY - } - - // This extra view is needed because of the wonkiness of apple's table footer. Things breaks if using autolayout. - MVMCoreUIUtility.sizeView(toFit: footerView) - let tableFooterView = UIView(frame: CGRect(x: 0, y: y ?? 0, width: MVMCoreUIUtility.getWidth(), height: footerView.frame.height)) - tableFooterView.addSubview(footerView) - NSLayoutConstraint.constraintPinSubview(toSuperview: footerView) - tableView.tableFooterView = tableFooterView - } - }*/ +// /// Takes the current headerView and adds it to the tableHeaderView +// func showHeader(_ sizingWidth: CGFloat?) { +// headerView?.removeFromSuperview() +// tableView?.tableHeaderView = nil +// guard let headerView = headerView else { +// return +// } +// +// // This extra view is needed because of the wonkiness of apple's table header. Things breaks if using autolayout. +// headerView.setNeedsLayout() +// headerView.layoutIfNeeded() +// MVMCoreUIUtility.sizeView(toFit: headerView) +// let tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: MVMCoreUIUtility.getWidth(), height: headerView.frame.height)) +// tableHeaderView.addSubview(headerView) +// NSLayoutConstraint.constraintPinSubview(toSuperview: headerView) +// tableView?.tableHeaderView = tableHeaderView +// } +// +// /// Takes the current footerView and adds it to the tableFooterView +// func showFooter(_ sizingWidth: CGFloat?) { +// footerView?.removeFromSuperview() +// safeAreaView?.removeFromSuperview() +// guard let footerView = footerView, let tableView = tableView else { +// return +// } +// +// if bottomViewOutsideOfScrollArea { +// // put bottom view outside of scrolling area. +// bottomConstraint?.isActive = false +// view.addSubview(footerView) +// footerView.topAnchor.constraint(equalTo: tableView.bottomAnchor).isActive = true +// footerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true +// view.rightAnchor.constraint(equalTo: footerView.rightAnchor).isActive = true +// view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: footerView.bottomAnchor).isActive = true +// safeAreaView = MVMCoreUICommonViewsUtility.getAndSetupSafeAreaView(on: view) +// safeAreaView?.backgroundColor = bottomView?.backgroundColor +// } else { +// bottomConstraint?.isActive = true +// var y: CGFloat? +// if let tableFooterView = tableView.tableFooterView { +// // if footer already exists, use the same y location to avoid strange moving animation +// y = tableFooterView.frame.minY +// } +// +// // This extra view is needed because of the wonkiness of apple's table footer. Things breaks if using autolayout. +// MVMCoreUIUtility.sizeView(toFit: footerView) +// let tableFooterView = UIView(frame: CGRect(x: 0, y: y ?? 0, width: MVMCoreUIUtility.getWidth(), height: footerView.frame.height)) +// tableFooterView.addSubview(footerView) +// NSLayoutConstraint.constraintPinSubview(toSuperview: footerView) +// tableView.tableFooterView = tableFooterView +// } +// } //MARK: - Functions to subclass /// Subclass for a top view. - open func viewForTop() -> UIView { - let view = MVMCoreUICommonViewsUtility.commonView() - // 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 + open func viewForTop() -> UIView? { + return nil } /// Subclass for a bottom view. - open func viewForBottom() -> UIView { - // Default spacing is standard when no buttons. - let view = MVMCoreUICommonViewsUtility.commonView() - view.heightAnchor.constraint(equalToConstant: PaddingDefaultVerticalSpacing).isActive = true - return view + open func viewForBottom() -> UIView? { + return nil + } + + open func createCollectionViewLayout() -> UICollectionViewLayout { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .vertical + layout.minimumLineSpacing = 0 + layout.minimumInteritemSpacing = 0 + layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize + return layout } open func createCollectionView() -> UICollectionView { - let layout = UICollectionViewFlowLayout() - layout.scrollDirection = .vertical - layout.minimumLineSpacing = 1 - layout.minimumInteritemSpacing = 0 - - let collection = UICollectionView(frame: .zero, collectionViewLayout: layout) + let collection = UICollectionView(frame: .zero, collectionViewLayout: createCollectionViewLayout()) collection.translatesAutoresizingMaskIntoConstraints = false collection.dataSource = self collection.delegate = self @@ -259,19 +238,20 @@ import Foundation //MARK: - Collection - public func registerCells() { - collectionView?.register(MoleculeCollectionViewCell.self, forCellWithReuseIdentifier: "collectionItem") + open func registerCells() { + collectionView?.register(ContainerCollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerID) + collectionView?.register(ContainerCollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: footerID) } - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - return 2 + open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return 0 } - public func numberOfSections(in collectionView: UICollectionView) -> Int { + open func numberOfSections(in collectionView: UICollectionView) -> Int { return 1 } - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionItem", for: indexPath) as! MoleculeCollectionViewCell let labelModel = LabelModel(text: "hello") let model = MoleculeCollectionItemModel(with: labelModel) @@ -279,11 +259,42 @@ import Foundation return cell } - open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { - return CGSize(width: 200, height: 200) + open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { + guard let view = headerView ?? topView, + section == 0 else { return .zero } + + // Use this view to calculate the optimal size based on the collection view's width + return view.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), + withHorizontalFittingPriority: .required, // Width is fixed + verticalFittingPriority: .fittingSizeLevel) // Height can be as large as needed } - open func collectionView(_ collectionView: UICollectionView, didEndDisplaying cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { - (cell as? CarouselItem)?.setPeaking(false, animated: false) + open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { + guard let view = footerView ?? bottomView, + section == numberOfSections(in: collectionView) - 1 else { return .zero } + + // Use this view to calculate the optimal size based on the collection view's width + let size = view.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), + withHorizontalFittingPriority: .required, // Width is fixed + verticalFittingPriority: .fittingSizeLevel) // Height can be as large as needed + print("SIZEEE \(size.height) \(String(describing: footerView?.topConstraint?.constant))") + return size + } + + open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { + if (kind == UICollectionView.elementKindSectionFooter) { + let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: footerID, for: indexPath) as! ContainerCollectionReusableView + footerView.addAndContain(view: bottomView!) + footerView.topConstraint?.constant = spaceAboveBottomView() ?? 0 + self.footerView = footerView + return footerView + } else if (kind == UICollectionView.elementKindSectionHeader) { + let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerID, for: indexPath) as! ContainerCollectionReusableView + headerView.addAndContain(view: topView!) + headerView.bottomConstraint?.constant = spaceBelowTopView() ?? 0 + self.headerView = headerView + return headerView + } + fatalError() } } diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.m b/MVMCoreUI/Utility/MVMCoreUIUtility.m index bcead7fe..59c55cc6 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.m @@ -164,7 +164,7 @@ CGFloat topInset = scrollview.contentInset.top; CGFloat bottomInset = scrollview.contentInset.bottom; - if (scrollview.contentInsetAdjustmentBehavior == UIScrollViewContentInsetAdjustmentAutomatic) { + if (scrollview.contentInsetAdjustmentBehavior == UIScrollViewContentInsetAdjustmentAutomatic || scrollview.contentInsetAdjustmentBehavior == UIScrollViewContentInsetAdjustmentAlways) { topInset = scrollview.adjustedContentInset.top; bottomInset = scrollview.adjustedContentInset.bottom; } From 3051d38ec5d9860087671e3deb625bcdaccac2b1 Mon Sep 17 00:00:00 2001 From: Kruthika KP <> Date: Wed, 8 Apr 2020 16:02:44 +0530 Subject: [PATCH 32/62] added files --- MVMCoreUI.xcodeproj/project.pbxproj | 16 ++--- MVMCoreUI/Atomic/MoleculeObjectMapping.swift | 1 + .../ListThreeColumnDataUsageDivider.swift | 61 +++++++++++++++++++ ...ListThreeColumnDataUsageDividerModel.swift | 51 ++++++++++++++++ .../ListThreeColumnSpeedTestDivider.swift | 2 +- 5 files changed, 122 insertions(+), 9 deletions(-) create mode 100644 MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift create mode 100644 MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDividerModel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 17df3c34..8a1dfb23 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -128,8 +128,6 @@ 8D070BB2241B56AD0099AC56 /* ListRightVariableTotalData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */; }; 8D084AD02410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */; }; 8D084AD22410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D084AD12410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift */; }; - 8D21E4B924247D1600ACAF24 /* ListThreeColumnDataUsageDividerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D21E4B824247D1600ACAF24 /* ListThreeColumnDataUsageDividerModel.swift */; }; - 8D21E4BB2424887800ACAF24 /* ListThreeColumnDataUsageDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D21E4BA2424887800ACAF24 /* ListThreeColumnDataUsageDivider.swift */; }; 8D24041123E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D24041023E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift */; }; 8D24041523E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D24041423E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift */; }; 8D3BA9BD2433787000D341BA /* ListThreeColumnInternationalDataDividerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D3BA9BC2433787000D341BA /* ListThreeColumnInternationalDataDividerModel.swift */; }; @@ -139,6 +137,8 @@ 8D4687E4242E2DF300802879 /* ListFourColumnDataUsageListItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8D4687E3242E2DF300802879 /* ListFourColumnDataUsageListItem.swift */; }; 8DD1E36E243B3CFB00D8F2DF /* ListThreeColumnInternationalDataModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DD1E36D243B3CFB00D8F2DF /* ListThreeColumnInternationalDataModel.swift */; }; 8DD1E370243B3D0500D8F2DF /* ListThreeColumnInternationalData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DD1E36F243B3D0500D8F2DF /* ListThreeColumnInternationalData.swift */; }; + 8DEFA95C243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DEFA95B243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift */; }; + 8DEFA95E243DAC2F000D27E5 /* ListThreeColumnDataUsageDivider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8DEFA95D243DAC2F000D27E5 /* ListThreeColumnDataUsageDivider.swift */; }; 942C372E241149170066E45E /* NHaasGroteskDSStd-75Bd.otf in Resources */ = {isa = PBXBuildFile; fileRef = 942C372C241149170066E45E /* NHaasGroteskDSStd-75Bd.otf */; }; 942C372F241149170066E45E /* NHaasGroteskDSStd-55Rg.otf in Resources */ = {isa = PBXBuildFile; fileRef = 942C372D241149170066E45E /* NHaasGroteskDSStd-55Rg.otf */; }; 942C378C2412F4FA0066E45E /* ModalMoleculeListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 942C378B2412F4FA0066E45E /* ModalMoleculeListTemplate.swift */; }; @@ -535,8 +535,6 @@ 8D070BB1241B56AD0099AC56 /* ListRightVariableTotalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListRightVariableTotalData.swift; sourceTree = ""; }; 8D084ACF2410BF4800951227 /* ListOneColumnFullWidthTextBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextBodyTextModel.swift; sourceTree = ""; }; 8D084AD12410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListOneColumnFullWidthTextBodyText.swift; sourceTree = ""; }; - 8D21E4B824247D1600ACAF24 /* ListThreeColumnDataUsageDividerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnDataUsageDividerModel.swift; sourceTree = ""; }; - 8D21E4BA2424887800ACAF24 /* ListThreeColumnDataUsageDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnDataUsageDivider.swift; sourceTree = ""; }; 8D24041023E7FB9E009E23BE /* ListLeftVariableIconWithRightCaret.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconWithRightCaret.swift; sourceTree = ""; }; 8D24041423E7FC0B009E23BE /* ListLeftVariableIconWithRightCaretModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconWithRightCaretModel.swift; sourceTree = ""; }; 8D3BA9BC2433787000D341BA /* ListThreeColumnInternationalDataDividerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnInternationalDataDividerModel.swift; sourceTree = ""; }; @@ -546,6 +544,8 @@ 8D4687E3242E2DF300802879 /* ListFourColumnDataUsageListItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListFourColumnDataUsageListItem.swift; sourceTree = ""; }; 8DD1E36D243B3CFB00D8F2DF /* ListThreeColumnInternationalDataModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnInternationalDataModel.swift; sourceTree = ""; }; 8DD1E36F243B3D0500D8F2DF /* ListThreeColumnInternationalData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnInternationalData.swift; sourceTree = ""; }; + 8DEFA95B243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnDataUsageDividerModel.swift; sourceTree = ""; }; + 8DEFA95D243DAC2F000D27E5 /* ListThreeColumnDataUsageDivider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnDataUsageDivider.swift; sourceTree = ""; }; 9402C34F23A2CEA3004B974C /* LeftRightLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LeftRightLabelModel.swift; sourceTree = ""; }; 942C372C241149170066E45E /* NHaasGroteskDSStd-75Bd.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NHaasGroteskDSStd-75Bd.otf"; sourceTree = ""; }; 942C372D241149170066E45E /* NHaasGroteskDSStd-55Rg.otf */ = {isa = PBXFileReference; lastKnownFileType = file; path = "NHaasGroteskDSStd-55Rg.otf"; sourceTree = ""; }; @@ -1332,8 +1332,8 @@ 8D3BA9BE2433789900D341BA /* ListThreeColumnInternationalDataDivider.swift */, AA1EC59624373985003D6F50 /* ListThreeColumnSpeedTestDividerModel.swift */, AA1EC59824373994003D6F50 /* ListThreeColumnSpeedTestDivider.swift */, - 8D21E4B824247D1600ACAF24 /* ListThreeColumnDataUsageDividerModel.swift */, - 8D21E4BA2424887800ACAF24 /* ListThreeColumnDataUsageDivider.swift */, + 8DEFA95B243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift */, + 8DEFA95D243DAC2F000D27E5 /* ListThreeColumnDataUsageDivider.swift */, ); path = ThreeColumn; sourceTree = ""; @@ -1996,7 +1996,6 @@ D29DF29621E7ADB8003B2FB9 /* StackableViewController.m in Sources */, 0116A4E5228B19640094F3ED /* RadioButtonSelectionHelper.swift in Sources */, 017BEB48236230DB0024EF95 /* MoleculeViewProtocol.swift in Sources */, - 8D21E4B924247D1600ACAF24 /* ListThreeColumnDataUsageDividerModel.swift in Sources */, D2E1FADB2260D3D200AEFD8C /* MVMCoreUIDelegateObject.swift in Sources */, 94382086243238D100B43AF3 /* WebViewModel.swift in Sources */, D27CD40E2322EEAF00C1DC07 /* TabsTableViewCell.swift in Sources */, @@ -2094,7 +2093,6 @@ EA5124FF2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift in Sources */, D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */, DBEFFA04225A829700230692 /* Label.swift in Sources */, - 8D21E4BB2424887800ACAF24 /* ListThreeColumnDataUsageDivider.swift in Sources */, D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */, 0A7EF85F23D8ABC500B2AAD1 /* MdnEntryFieldModel.swift in Sources */, 011D959B240451E3000E3791 /* RuleRequiredModel.swift in Sources */, @@ -2106,6 +2104,7 @@ 5248BFEC23F12E350059236A /* ListThreeColumnPlanDataDivider.swift in Sources */, 0ABD136D237CAD1E0081388D /* DateDropdownEntryField.swift in Sources */, 0A7EF85B23D8A52800B2AAD1 /* EntryFieldModel.swift in Sources */, + 8DEFA95C243DAC20000D27E5 /* ListThreeColumnDataUsageDividerModel.swift in Sources */, 94F217B723E0BF6100A47C06 /* PrimaryButtonView.m in Sources */, 0A1B4A96233BB18F005B3FB4 /* CheckboxLabel.swift in Sources */, 0A21DB8B235E06EF00C160A2 /* MFDigitTextBox.m in Sources */, @@ -2184,6 +2183,7 @@ D2FB151B23A2B65B00C20E10 /* MoleculeContainer.swift in Sources */, 279B1569242BBC2F00921D6C /* ActionModelAdapter.swift in Sources */, BB6C6AC0242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTallModel.swift in Sources */, + 8DEFA95E243DAC2F000D27E5 /* ListThreeColumnDataUsageDivider.swift in Sources */, D2A638FD22CA98280052ED1F /* HeadlineBody.swift in Sources */, D29DF16121E69996003B2FB9 /* MFViewController.m in Sources */, AAA74A172410C04600080241 /* HeadersH2NoButtonsBodyText.swift in Sources */, diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index f8c81052..cccefc85 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -154,6 +154,7 @@ import Foundation MoleculeObjectMapping.shared()?.register(viewClass: ListThreeColumnInternationalDataDivider.self, viewModelClass: ListThreeColumnInternationalDataDividerModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListThreeColumnSpeedTestDivider.self, viewModelClass: ListThreeColumnSpeedTestDividerModel.self) MoleculeObjectMapping.shared()?.register(viewClass: ListThreeColumnBillChangesDivider.self, viewModelClass: ListThreeColumnBillChangesDividerModel.self) + MoleculeObjectMapping.shared()?.register(viewClass: ListThreeColumnDataUsageDivider.self, viewModelClass: ListThreeColumnDataUsageDividerModel.self) // Designed Headers MoleculeObjectMapping.shared()?.register(viewClass: HeadersH2NoButtonsBodyText.self, viewModelClass: HeadersH2NoButtonsBodyTextModel.self) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift new file mode 100644 index 00000000..113be5f1 --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift @@ -0,0 +1,61 @@ +// +// ListThreeColumnDataUsageDivider.swift +// MVMCoreUI +// +// Created by Kruthika KP on 20/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers open class ListThreeColumnDataUsageDivider: TableViewCell { + + //----------------------------------------------------- + // MARK: - Outlets + //------------------------------------------------------- + public let leftLabel = Label.createLabelBoldBodySmall(true) + public let centerLabel = Label.createLabelBoldBodySmall(true) + public let rightLabel = Label.createLabelBoldBodySmall(true) + var stack: Stack + + //------------------------------------------------------ + // MARK: - Initializers + //------------------------------------------------------ + public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { + stack = Stack.createStack(with: [(view: leftLabel, model: StackItemModel(percent: 32, horizontalAlignment: .leading)), + (view: centerLabel, model: StackItemModel(percent: 33, horizontalAlignment: .center)), + (view: rightLabel, model: StackItemModel(percent: 35, horizontalAlignment: .center))], + axis: .horizontal) + super.init(style: style, reuseIdentifier: reuseIdentifier) + } + + public required init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + open override func setupView() { + super.setupView() + addMolecule(stack) + stack.restack() + } + + // MARK: - ModelMoleculeViewProtocol + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + super.set(with: model, delegateObject, additionalData) + guard let model = model as? ListThreeColumnDataUsageDividerModel else { return } + leftLabel.set(with: model.leftLabel, delegateObject, additionalData) + centerLabel.set(with: model.centerLabel, delegateObject, additionalData) + rightLabel.set(with: model.rightLabel, delegateObject, additionalData) + } + + open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { + return 121 + } + + open override func reset() { + super.reset() + leftLabel.styleBoldBodySmall(true) + centerLabel.styleBoldBodySmall(true) + rightLabel.styleBoldBodySmall(true) + } +} diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDividerModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDividerModel.swift new file mode 100644 index 00000000..f57bdf01 --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDividerModel.swift @@ -0,0 +1,51 @@ +// +// ListThreeColumnDataUsageDividerModel.swift +// MVMCoreUI +// +// Created by Kruthika KP on 20/03/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class ListThreeColumnDataUsageDividerModel: ListItemModel, MoleculeModelProtocol { + public static var identifier: String = "list3CDataUsgDiv" + public let leftLabel: LabelModel + public let centerLabel: LabelModel + public let rightLabel: LabelModel + + public init(leftLabel: LabelModel, centerLabel: LabelModel, rightLabel: LabelModel) { + self.leftLabel = leftLabel + self.centerLabel = centerLabel + self.rightLabel = rightLabel + super.init() + } + + override public func setDefaults() { + super.setDefaults() + style = "tallDivider" + } + + private enum CodingKeys: String, CodingKey { + case moleculeName + case leftLabel + case centerLabel + case rightLabel + } + + required init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + leftLabel = try typeContainer.decode(LabelModel.self, forKey: .leftLabel) + centerLabel = try typeContainer.decode(LabelModel.self, forKey: .centerLabel) + rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel) + try super.init(from:decoder) + } + + public override func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encode(leftLabel, forKey: .leftLabel) + try container.encode(centerLabel, forKey: .centerLabel) + try container.encode(rightLabel, forKey: .rightLabel) + } +} diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnSpeedTestDivider.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnSpeedTestDivider.swift index aa9fbc2d..ad9f0740 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnSpeedTestDivider.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnSpeedTestDivider.swift @@ -22,7 +22,7 @@ import Foundation // MARK: - Initializers //------------------------------------------------------- public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - stack = Stack.createStack(with: [(view: leftLabel, model: StackItemModel(percent: 37, horizontalAlignment: .leading)), (view: centerLabel, model: StackItemModel(percent: 33, horizontalAlignment: .leading)), (view: rightLabel, model: StackItemModel(percent: 30, horizontalAlignment: .leading))], axis: .horizontal) + stack = Stack.createStack(with: [(view: leftLabel, model: StackItemModel(percent: 37, horizontalAlignment: .leading)), (view: centerLabel, model: StackItemModel(percent: 33, horizontalAlignment: .center)), (view: rightLabel, model: StackItemModel(percent: 30, horizontalAlignment: .leading))], axis: .horizontal) super.init(style: style, reuseIdentifier: reuseIdentifier) } From 3e38234d123a4282cdfda1ffeae3e4f4436559ac Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 8 Apr 2020 08:09:30 -0400 Subject: [PATCH 33/62] green --- MVMCoreUI/Categories/UIColor+MFConvenience.h | 1 + MVMCoreUI/Categories/UIColor+MFConvenience.m | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/MVMCoreUI/Categories/UIColor+MFConvenience.h b/MVMCoreUI/Categories/UIColor+MFConvenience.h index c3c78c7a..92b28a36 100644 --- a/MVMCoreUI/Categories/UIColor+MFConvenience.h +++ b/MVMCoreUI/Categories/UIColor+MFConvenience.h @@ -24,6 +24,7 @@ + (nonnull UIColor *)mvmOrange; + (nonnull UIColor *)mfPumpkinColor; + (nonnull UIColor *)mfShamrock; ++ (nonnull UIColor *)mvmGreen; + (nonnull UIColor *)mfCerulean; + (nonnull UIColor *)mfWhiteTwo; diff --git a/MVMCoreUI/Categories/UIColor+MFConvenience.m b/MVMCoreUI/Categories/UIColor+MFConvenience.m index 6ff8f70f..33df3848 100644 --- a/MVMCoreUI/Categories/UIColor+MFConvenience.m +++ b/MVMCoreUI/Categories/UIColor+MFConvenience.m @@ -61,6 +61,10 @@ return [UIColor mfColor8bitsWithRed:0 green:134 blue:49 alpha:1.0]; } ++ (nonnull UIColor *)mvmGreen { + return [UIColor mfColor8bitsWithRed:0 green:134 blue:48 alpha:1.0]; +} + + (nonnull UIColor *)mfCerulean { return [UIColor mfColor8bitsWithRed:0 green:122 blue:184 alpha:1.0]; } From dcf168b53ecec3030eaddf717e8446ee400c35cc Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 8 Apr 2020 08:19:06 -0400 Subject: [PATCH 34/62] rolaback --- MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift | 3 --- MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift | 3 --- MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChart.swift | 2 +- 3 files changed, 1 insertion(+), 7 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift index c12b7dd3..da46c26e 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift @@ -215,9 +215,6 @@ import UIKit feedbackLabelTrailing = layoutMarginsGuide.trailingAnchor.constraint(equalTo: feedbackLabel.trailingAnchor) feedbackLabelTrailing?.isActive = true layoutMarginsGuide.bottomAnchor.constraint(equalTo: feedbackLabel.bottomAnchor).isActive = true - - container.trailingAnchor.constraint(equalTo: dropDownCaretView.trailingAnchor, constant: 16).isActive = true - dropDownCaretView.centerYAnchor.constraint(equalTo: container.centerYAnchor).isActive = true } @objc open override func layoutSubviews() { diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift index cf927c03..de0d1789 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/TextEntryField.swift @@ -79,9 +79,7 @@ import UIKit if error { textField.accessibilityValue = String(format: MVMCoreUIUtility.hardcodedString(withKey: "textfield_error_message") ?? "", textField.text ?? "", errorMessage ?? "") - errorIconWidthContraint?.constant = 20 } else { - errorIconWidthContraint?.constant = 0 textField.accessibilityValue = nil } @@ -143,7 +141,6 @@ import UIKit //-------------------------------------------------- public var textFieldTrailingConstraint: NSLayoutConstraint? - public var errorIconWidthContraint: NSLayoutConstraint? //-------------------------------------------------- // MARK: - Initializers diff --git a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChart.swift b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChart.swift index 2908a90d..bad0492d 100644 --- a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChart.swift +++ b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChart.swift @@ -17,7 +17,7 @@ open class DoughnutChart: View { public var doughnutLayer = CALayer() public var titleLabel = Label.createLabelBoldTitleLarge(true) public var subTitleLabel = Label.createLabelRegularMicro(true) - public var labelContainer = View() + public var labelContainer = MVMCoreUICommonViewsUtility.commonView() public static let heightConstant: CGFloat = 136 private var sizeObject = MFStyler.sizeObjectGeneric(forCurrentDevice: heightConstant)! From d755709daa37b4bd4b01ee0c125001e876a35923 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 8 Apr 2020 08:35:21 -0400 Subject: [PATCH 35/62] remove code for later change --- MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift | 6 ------ 1 file changed, 6 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift b/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift index da46c26e..658af357 100644 --- a/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/TextFields/EntryField.swift @@ -57,12 +57,6 @@ import UIKit } } - public var accessoryInput: View? { - didSet { - - } - } - //-------------------------------------------------- // MARK: - Computed Properties //-------------------------------------------------- From fd31ca294bbb108f1b4b59eaf2017bb22f3b4718 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 8 Apr 2020 09:22:32 -0400 Subject: [PATCH 36/62] update made --- MVMCoreUI/Styles/Padding.swift | 16 ++++++++-------- MVMCoreUI/Styles/Styler.swift | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/MVMCoreUI/Styles/Padding.swift b/MVMCoreUI/Styles/Padding.swift index ca99d5dc..3ed0922e 100644 --- a/MVMCoreUI/Styles/Padding.swift +++ b/MVMCoreUI/Styles/Padding.swift @@ -11,7 +11,7 @@ import Foundation public struct Padding { - public static let One: CGFloat = 6 + public static let One: CGFloat = 8 public static let Two: CGFloat = 12 public static let Three: CGFloat = 18 public static let Four: CGFloat = 24 @@ -24,24 +24,24 @@ public struct Padding { public struct Default { public static let Standard: CGFloat = 24 - public static let HorizontalSpacing: CGFloat = 32 - public static let VerticalSpacing: CGFloat = 32 - public static let VerticalSpacing3: CGFloat = 24 + public static let HorizontalMarginSpacing: CGFloat = 32 + public static let LargeVerticalMarginSpacing: CGFloat = 32 + public static let VerticalMarginSpacing: CGFloat = 24 public static var horizontalPaddingForApplicationWidth: CGFloat { - return MFSizeObject(scalingStandardSize: HorizontalSpacing)?.getValueBasedOnApplicationWidth() ?? HorizontalSpacing + return MFSizeObject(scalingStandardSize: HorizontalMarginSpacing)?.getValueBasedOnApplicationWidth() ?? HorizontalMarginSpacing } public static var verticalPaddingForApplicationWidth: CGFloat { - return MFSizeObject(scalingStandardSize: VerticalSpacing)?.getValueBasedOnApplicationWidth() ?? VerticalSpacing + return MFSizeObject(scalingStandardSize: VerticalMarginSpacing)?.getValueBasedOnApplicationWidth() ?? VerticalMarginSpacing } public static func horizontalPaddingForSize(_ size: CGFloat) -> CGFloat { - return MFSizeObject(scalingStandardSize: HorizontalSpacing)?.getValueBased(onSize: size) ?? HorizontalSpacing + return MFSizeObject(scalingStandardSize: HorizontalMarginSpacing)?.getValueBased(onSize: size) ?? HorizontalMarginSpacing } public static func verticalPaddingForSize(_ size: CGFloat) -> CGFloat { - return MFSizeObject(scalingStandardSize: VerticalSpacing)?.getValueBased(onSize: size) ?? VerticalSpacing + return MFSizeObject(scalingStandardSize: VerticalMarginSpacing)?.getValueBased(onSize: size) ?? VerticalMarginSpacing } } } diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift index 75d0b9ee..e6675b1d 100644 --- a/MVMCoreUI/Styles/Styler.swift +++ b/MVMCoreUI/Styles/Styler.swift @@ -167,10 +167,10 @@ open class Styler { } /// Styles the provided label to the declared enum Font case. - public func styleLabel(_ label: UILabel, genericScaling: Bool = true) { + public func styleLabel(_ label: UILabel, textColor: UIColor = .mvmBlack, genericScaling: Bool = true) { label.font = getFont(genericScaling) - label.textColor = .black + label.textColor = textColor } } From de084aa89987af29d5a9db2b4b0fd1170a1eb1ec Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 8 Apr 2020 09:24:31 -0400 Subject: [PATCH 37/62] margin in styler --- MVMCoreUI/Styles/Styler.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift index e6675b1d..e5ac19b7 100644 --- a/MVMCoreUI/Styles/Styler.swift +++ b/MVMCoreUI/Styles/Styler.swift @@ -197,8 +197,8 @@ open class Styler { open class func setDefaultMarginsFor(_ view: UIView?, size: CGFloat?, horizontal: Bool = true, vertical: Bool = false) { - var horizontalPadding: CGFloat = Padding.Default.HorizontalSpacing - let verticalPadding: CGFloat = vertical ? Padding.Default.VerticalSpacing3 : 0 + var horizontalPadding: CGFloat = Padding.Default.HorizontalMarginSpacing + let verticalPadding: CGFloat = vertical ? Padding.Default.VerticalMarginSpacing : 0 if let size = size { horizontalPadding = horizontal ? Padding.Default.horizontalPaddingForSize(size) : 0 From 8b957b1d4969ea0c96a600cb288aed2a966efedd Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 8 Apr 2020 10:10:39 -0400 Subject: [PATCH 38/62] padding updates --- MVMCoreUI/Styles/Padding.swift | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/MVMCoreUI/Styles/Padding.swift b/MVMCoreUI/Styles/Padding.swift index 3ed0922e..0dd9ff6e 100644 --- a/MVMCoreUI/Styles/Padding.swift +++ b/MVMCoreUI/Styles/Padding.swift @@ -9,20 +9,21 @@ import Foundation +/// Padding is a multiple based on the number 4. public struct Padding { - public static let One: CGFloat = 8 - public static let Two: CGFloat = 12 - public static let Three: CGFloat = 18 - public static let Four: CGFloat = 24 - public static let Five: CGFloat = 30 - public static let Six: CGFloat = 36 - public static let Seven: CGFloat = 42 - public static let Eight: CGFloat = 48 - public static let Nine: CGFloat = 54 - public static let Ten: CGFloat = 60 + public static let OneHalf: CGFloat = 2 + public static let One: CGFloat = 4 + public static let Two: CGFloat = 8 + public static let Three: CGFloat = 12 + public static let Four: CGFloat = 16 + public static let Five: CGFloat = 24 + public static let Eight: CGFloat = 32 + public static let Ten: CGFloat = 40 + public static let Twelve: CGFloat = 48 + public static let Eighteen: CGFloat = 72 - public struct Default { + public struct Component { public static let Standard: CGFloat = 24 public static let HorizontalMarginSpacing: CGFloat = 32 public static let LargeVerticalMarginSpacing: CGFloat = 32 From c52337a08beb9e795b03f7f92ceaa0d34f10a1d3 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Wed, 8 Apr 2020 10:28:14 -0400 Subject: [PATCH 39/62] name change --- MVMCoreUI/Styles/Styler.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift index e5ac19b7..96bd558c 100644 --- a/MVMCoreUI/Styles/Styler.swift +++ b/MVMCoreUI/Styles/Styler.swift @@ -197,11 +197,11 @@ open class Styler { open class func setDefaultMarginsFor(_ view: UIView?, size: CGFloat?, horizontal: Bool = true, vertical: Bool = false) { - var horizontalPadding: CGFloat = Padding.Default.HorizontalMarginSpacing - let verticalPadding: CGFloat = vertical ? Padding.Default.VerticalMarginSpacing : 0 + var horizontalPadding: CGFloat = Padding.Component.HorizontalMarginSpacing + let verticalPadding: CGFloat = vertical ? Padding.Component.VerticalMarginSpacing : 0 if let size = size { - horizontalPadding = horizontal ? Padding.Default.horizontalPaddingForSize(size) : 0 + horizontalPadding = horizontal ? Padding.Component.horizontalPaddingForSize(size) : 0 } DispatchQueue.main.async { @@ -215,7 +215,7 @@ open class Styler { open class func setMarginsFor(_ view: UIView?, size: CGFloat, defaultHorizontal horizontal: Bool, top: CGFloat, bottom: CGFloat) { - let horizontalPadding: CGFloat = horizontal ? Padding.Default.horizontalPaddingForSize(size) : 0 + let horizontalPadding: CGFloat = horizontal ? Padding.Component.horizontalPaddingForSize(size) : 0 DispatchQueue.main.async { MVMCoreUIUtility.setMarginsFor(view, From c2e52ea31330c3c9c0921aa6440bf1773cd48731 Mon Sep 17 00:00:00 2001 From: "Pan, Xinlei (Ryan)" Date: Wed, 8 Apr 2020 11:51:14 -0400 Subject: [PATCH 40/62] Revert "Merge branch 'feature/usenewfont' into 'develop'" This reverts merge request !353 --- MVMCoreUI/Utility/MFFonts.m | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/MVMCoreUI/Utility/MFFonts.m b/MVMCoreUI/Utility/MFFonts.m index 24c62a9a..533b3a87 100644 --- a/MVMCoreUI/Utility/MFFonts.m +++ b/MVMCoreUI/Utility/MFFonts.m @@ -85,20 +85,14 @@ NSString * const DS55Rg = @"NHaasGroteskDSStd-55Rg"; + (nonnull UIFont *)mfFont75Bd:(CGFloat)size { [self loadMVMFonts]; - if (size >= 15) { - return [MFFonts mfFontDSBold:size]; - } else { - return [MFFonts mfFontTXBold:size]; - } + UIFont *font = [UIFont fontWithName:DS75Bd size:size]; + return font ?: [UIFont boldSystemFontOfSize:size]; } + (nonnull UIFont *)mfFont55Rg:(CGFloat)size { [self loadMVMFonts]; - if (size >= 15) { - return [MFFonts mfFontDSRegular:size]; - } else { - return [MFFonts mfFontTXRegular:size]; - } + UIFont *font = [UIFont fontWithName:DS55Rg size:size]; + return font ?: [UIFont systemFontOfSize:size]; } + (nullable UIFont *)mfFontOcratxt:(CGFloat)size { From 8c9ab45951a935c30d97bd055c8d34ed3af5116f Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 8 Apr 2020 16:14:40 -0400 Subject: [PATCH 41/62] Fixes for sizing and base classes --- MVMCoreUI.xcodeproj/project.pbxproj | 4 + .../Atomic/Templates/CollectionTemplate.swift | 11 +- .../BaseClasses/CollectionViewCell.swift | 2 +- .../ContainerCollectionReusableView.swift | 10 +- ...ProgrammaticCollectionViewController.swift | 80 ++++++ .../ProgrammaticTableViewController.swift | 5 + .../ThreeLayerCollectionViewController.swift | 249 ++++++------------ .../BaseControllers/ViewController.swift | 18 +- MVMCoreUI/Utility/MVMCoreUIUtility.m | 2 +- 9 files changed, 193 insertions(+), 188 deletions(-) create mode 100644 MVMCoreUI/BaseControllers/ProgrammaticCollectionViewController.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 6db35f4e..df6cdbf6 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -250,6 +250,7 @@ D264FA8E243BCD9A00D98315 /* CollectionTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FA8D243BCD9A00D98315 /* CollectionTemplate.swift */; }; D264FA90243BCE6800D98315 /* ThreeLayerCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FA8F243BCE6800D98315 /* ThreeLayerCollectionViewController.swift */; }; D264FAA1243CF66B00D98315 /* ContainerCollectionReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FAA0243CF66B00D98315 /* ContainerCollectionReusableView.swift */; }; + D264FAA3243E632F00D98315 /* ProgrammaticCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FAA2243E632F00D98315 /* ProgrammaticCollectionViewController.swift */; }; D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368A23609801006832FA /* MoleculeStackItemModel.swift */; }; D268C70E238C22D7007F2C1C /* DropDownFilterTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */; }; D26C5A6B23F4A40D007AEECE /* ListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */; }; @@ -656,6 +657,7 @@ D264FA8D243BCD9A00D98315 /* CollectionTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionTemplate.swift; sourceTree = ""; }; D264FA8F243BCE6800D98315 /* ThreeLayerCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerCollectionViewController.swift; sourceTree = ""; }; D264FAA0243CF66B00D98315 /* ContainerCollectionReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerCollectionReusableView.swift; sourceTree = ""; }; + D264FAA2243E632F00D98315 /* ProgrammaticCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgrammaticCollectionViewController.swift; sourceTree = ""; }; D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropDownFilterTableViewCell.swift; sourceTree = ""; }; D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemModel.swift; sourceTree = ""; }; D274CA322236A78900B01B62 /* FooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FooterView.swift; sourceTree = ""; }; @@ -1485,6 +1487,7 @@ D2A92881241AAB67004E01C6 /* ScrollingViewController.swift */, D2A92883241ACB25004E01C6 /* ProgrammaticScrollViewController.swift */, D2A92885241ACD99004E01C6 /* ProgrammaticTableViewController.swift */, + D264FAA2243E632F00D98315 /* ProgrammaticCollectionViewController.swift */, ); path = BaseControllers; sourceTree = ""; @@ -2162,6 +2165,7 @@ C6FA7D5323C77A4A00A3614A /* StringAndMoleculeStack.swift in Sources */, 011D958524042432000E3791 /* RulesProtocol.swift in Sources */, 94AF4A3F23E9D13900676048 /* MFCaretButton.m in Sources */, + D264FAA3243E632F00D98315 /* ProgrammaticCollectionViewController.swift in Sources */, D29DF27A21E7A533003B2FB9 /* MVMCoreUISession.m in Sources */, D2A5146B2214905000345BFB /* ThreeLayerViewController.swift in Sources */, 526A265E240D200500B0D828 /* ListTwoColumnCompareChanges.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift index 11142532..d8812119 100644 --- a/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift @@ -64,7 +64,6 @@ import Foundation } open override func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject, error: AutoreleasingUnsafeMutablePointer) -> Bool { - guard super.shouldFinishProcessingLoad(loadObject, error: error) else { return false } // This template requires atleast one of the three layers. @@ -103,8 +102,8 @@ import Foundation } open override func numberOfSections(in collectionView: UICollectionView) -> Int { - return 1 - } + return 1 + } open override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { guard let moleculeInfo = moleculesInfo?[indexPath.row] @@ -124,7 +123,7 @@ import Foundation //-------------------------------------------------- /// Returns the (identifier, class) of the molecule for the given map. - func getMoleculeInfo(with item: (CollectionItemModelProtocol & MoleculeModelProtocol)?) -> (identifier: String, class: AnyClass, molecule: CollectionItemModelProtocol & MoleculeModelProtocol)? { + open func getMoleculeInfo(with item: (CollectionItemModelProtocol & MoleculeModelProtocol)?) -> (identifier: String, class: AnyClass, molecule: CollectionItemModelProtocol & MoleculeModelProtocol)? { guard let item = item, let moleculeClass = MoleculeObjectMapping.shared()?.getMoleculeClass(item) else { return nil } let moleculeName = moleculeClass.nameForReuse(with: item, delegateObjectIVar) ?? item.moleculeName @@ -132,7 +131,7 @@ import Foundation } /// Sets up the molecule list and ensures no errors loading all content. - func getMoleculeInfoList() -> [(identifier: String, class: AnyClass, molecule: (CollectionItemModelProtocol & MoleculeModelProtocol))]? { + open func getMoleculeInfoList() -> [(identifier: String, class: AnyClass, molecule: (CollectionItemModelProtocol & MoleculeModelProtocol))]? { var moleculeList: [(identifier: String, class: AnyClass, molecule: CollectionItemModelProtocol & MoleculeModelProtocol)] = [] @@ -148,7 +147,7 @@ import Foundation } /// Sets up the header, footer, molecule list and ensures no errors loading all content. - func setup() { + open func setup() { moleculesInfo = getMoleculeInfoList() } diff --git a/MVMCoreUI/BaseClasses/CollectionViewCell.swift b/MVMCoreUI/BaseClasses/CollectionViewCell.swift index 50cece5d..fb5b1a5e 100644 --- a/MVMCoreUI/BaseClasses/CollectionViewCell.swift +++ b/MVMCoreUI/BaseClasses/CollectionViewCell.swift @@ -46,7 +46,7 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo open func updateView(_ size: CGFloat) { containerHelper.updateViewMargins(contentView, model: model, size: size) DispatchQueue.main.async { - print("\(self.contentView.directionalLayoutMargins.leading)") + print("leading \(self.contentView.directionalLayoutMargins.leading)") } } diff --git a/MVMCoreUI/BaseControllers/ContainerCollectionReusableView.swift b/MVMCoreUI/BaseControllers/ContainerCollectionReusableView.swift index c578c273..a0e80f21 100644 --- a/MVMCoreUI/BaseControllers/ContainerCollectionReusableView.swift +++ b/MVMCoreUI/BaseControllers/ContainerCollectionReusableView.swift @@ -14,12 +14,16 @@ public class ContainerCollectionReusableView: UICollectionReusableView { var bottomConstraint: NSLayoutConstraint? public func addAndContain(view: UIView) { + guard self.view != view else { return } self.view?.removeFromSuperview() view.setContentCompressionResistancePriority(.required, for: .vertical) addSubview(view) self.view = view - let constraints = NSLayoutConstraint.constraintPinSubview(toSuperview: view) - topConstraint = constraints?[ConstraintTop] as? NSLayoutConstraint - bottomConstraint = constraints?[ConstraintBot] as? NSLayoutConstraint + topConstraint = view.topAnchor.constraint(equalTo: topAnchor) + topConstraint?.isActive = true + bottomConstraint = bottomAnchor.constraint(equalTo: view.bottomAnchor) + bottomConstraint?.isActive = true + rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true + view.leftAnchor.constraint(equalTo: leftAnchor).isActive = true } } diff --git a/MVMCoreUI/BaseControllers/ProgrammaticCollectionViewController.swift b/MVMCoreUI/BaseControllers/ProgrammaticCollectionViewController.swift new file mode 100644 index 00000000..0dd473e2 --- /dev/null +++ b/MVMCoreUI/BaseControllers/ProgrammaticCollectionViewController.swift @@ -0,0 +1,80 @@ +// +// ProgrammaticCollectionViewController.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 4/8/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objc open class ProgrammaticCollectionViewController: ScrollingViewController { + + public var collectionView: UICollectionView? + + open override func loadView() { + let view = UIView() + view.backgroundColor = .white + + let collection = createCollectionView() + view.addSubview(collection) + NSLayoutConstraint.constraintPinSubview(toSuperview: collection) + + collectionView = collection + scrollView = collectionView + self.view = view + } + + /// A place to register cells with the collectionView + open func registerCells() {} + + open override func viewDidLoad() { + super.viewDidLoad() + registerCells() + } + + /// Creates the layout for the collection. + open func createCollectionViewLayout() -> UICollectionViewLayout { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .vertical + layout.minimumLineSpacing = 0 + layout.minimumInteritemSpacing = 0 + layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize + return layout + } + + /// Creates the collection view. + open func createCollectionView() -> UICollectionView { + let collection = UICollectionView(frame: .zero, collectionViewLayout: createCollectionViewLayout()) + collection.translatesAutoresizingMaskIntoConstraints = false + collection.dataSource = self + collection.delegate = self + collection.showsHorizontalScrollIndicator = false + collection.backgroundColor = .white + collection.isAccessibilityElement = false + collection.contentInsetAdjustmentBehavior = .always + return collection + } + + deinit { + collectionView?.delegate = nil + collectionView?.dataSource = nil + } +} + +extension ProgrammaticCollectionViewController: UICollectionViewDataSource { + open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return 0 + } + + open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + return UICollectionViewCell() + } + + open func numberOfSections(in collectionView: UICollectionView) -> Int { + return 1 + } +} + +extension ProgrammaticCollectionViewController: UICollectionViewDelegate { +} diff --git a/MVMCoreUI/BaseControllers/ProgrammaticTableViewController.swift b/MVMCoreUI/BaseControllers/ProgrammaticTableViewController.swift index 4e262398..b27845b3 100644 --- a/MVMCoreUI/BaseControllers/ProgrammaticTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ProgrammaticTableViewController.swift @@ -42,6 +42,11 @@ open class ProgrammaticTableViewController: ProgrammaticScrollViewController, UI self.view = view } + open override func viewDidLoad() { + super.viewDidLoad() + registerWithTable() + } + /// This class should create the table view that will be used here. Subclass this for different table styles. open func createTableView() -> UITableView { let tableView = UITableView(frame: .zero, style: .grouped) diff --git a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift index 74877925..62c47d6e 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift @@ -8,73 +8,18 @@ import Foundation -@objc open class ThreeLayerCollectionViewController: ScrollingViewController, UICollectionViewDataSource, UICollectionViewDelegate, UICollectionViewDelegateFlowLayout { - public var collectionView: UICollectionView? +@objc open class ThreeLayerCollectionViewController: ProgrammaticCollectionViewController, UICollectionViewDelegateFlowLayout { // The three main views private var topView: UIView? private var bottomView: UIView? private var headerView: ContainerCollectionReusableView? private var footerView: ContainerCollectionReusableView? - var useMargins: Bool = true private let headerID = "header" private let footerID = "footer" - //MARK: - MFViewController - open override func updateViews() { - super.updateViews() - let width = view.bounds.width - if let topView = topView as? MVMCoreViewProtocol { - topView.updateView(width) - // showHeader(width) - } - if let bottomView = bottomView as? MVMCoreViewProtocol { - bottomView.updateView(width) - //showFooter(width) - } - self.collectionView?.collectionViewLayout.invalidateLayout() - } - - open override func handleNewData() { - super.handleNewData() - createViewForTableHeader() - createViewForTableFooter() - collectionView?.reloadData() - } - - override open func viewDidLoad() { - let collection = createCollectionView() - collectionView = collection - view.addSubview(collection) - NSLayoutConstraint.constraintPinSubview(toSuperview: collection) - scrollView = collectionView - - registerCells() - - super.viewDidLoad() - // Do any additional setup after loading the view. - } - - //MARK: - Spacing - // If both are subclassed to return a value, then the buttons will not be pinned towards the bottom because neither spacing would try to fill the screen. - /// Space between the top view and the table sections, nil to fill. 0 default - open func spaceBelowTopView() -> CGFloat? { - return 0 - } - - /// Space between the bottom view and the table sections, nil to fill. nil default - open func spaceAboveBottomView() -> CGFloat? { - return nil - } - - /// can override to return a minimum fill space. - open func minimumFillSpace() -> CGFloat { - return 0 - } - - open override func updateViewConstraints() { - super.updateViewConstraints() - + /// Updates the padding for flexible space (header or footer) + private func updateFlexibleSpace() { guard let tableView = collectionView else { return } let minimumSpace: CGFloat = minimumFillSpace() @@ -105,29 +50,70 @@ import Foundation currentSpaceForCompare = currentSpace * 2; } - if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpaceForCompare, 0.1) { + if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpaceForCompare, 2) { if fillTop && fillBottom { // space both let half = newSpace / 2 headerView?.bottomConstraint?.constant = half footerView?.topConstraint?.constant = half - collectionView?.invalidateIntrinsicContentSize() + collectionView?.collectionViewLayout.invalidateLayout() } else if fillTop { // Only top is spaced (half the size if the bottom view is out of the scroll because it needs to be sized as if there are two spacers but there is only one. headerView?.bottomConstraint?.constant = newSpace - collectionView?.invalidateIntrinsicContentSize() + collectionView?.collectionViewLayout.invalidateLayout() } else if fillBottom { // Only bottom is spaced. - print("newSpace \(newSpace)") footerView?.topConstraint?.constant = newSpace - collectionView?.invalidateIntrinsicContentSize() + collectionView?.collectionViewLayout.invalidateLayout() } } } + + //MARK: - MFViewController + open override func updateViews() { + super.updateViews() + let width = view.bounds.width + if let topView = topView as? MVMCoreViewProtocol { + topView.updateView(width) + } + if let bottomView = bottomView as? MVMCoreViewProtocol { + bottomView.updateView(width) + } + invalidateCollectionLayout() + } + + open override func handleNewData() { + super.handleNewData() + createViewForHeader() + createViewForFooter() + reloadCollectionData() + } + + override open func viewDidLoad() { + super.viewDidLoad() + // Do any additional setup after loading the view. + } + + //MARK: - Spacing + // If both are subclassed to return a value, then the buttons will not be pinned towards the bottom because neither spacing would try to fill the screen. + /// Space between the top view and the collection rows, nil to fill. 0 default + open func spaceBelowTopView() -> CGFloat? { + return 0 + } + + /// Space between the bottom view and the collection rows, nil to fill. nil default + open func spaceAboveBottomView() -> CGFloat? { + return nil + } + + /// can override to return a minimum fill space. + open func minimumFillSpace() -> CGFloat { + return 0 + } //MARK: - Header Footer - /// Gets the top view and adds it to a spacing view, headerView, and then calls showHeader. - open func createViewForTableHeader() { + /// Creates the top view. + open func createViewForHeader() { guard let topView = viewForTop() else { self.topView = nil self.headerView = nil @@ -136,8 +122,8 @@ import Foundation self.topView = topView } - /// Gets the bottom view and adds it to a spacing view, footerView, and then calls showFooter. - open func createViewForTableFooter() { + /// Creates the footer + open func createViewForFooter() { guard let bottomView = viewForBottom() else { self.bottomView = nil self.footerView = nil @@ -145,60 +131,7 @@ import Foundation } self.bottomView = bottomView } - -// /// Takes the current headerView and adds it to the tableHeaderView -// func showHeader(_ sizingWidth: CGFloat?) { -// headerView?.removeFromSuperview() -// tableView?.tableHeaderView = nil -// guard let headerView = headerView else { -// return -// } -// -// // This extra view is needed because of the wonkiness of apple's table header. Things breaks if using autolayout. -// headerView.setNeedsLayout() -// headerView.layoutIfNeeded() -// MVMCoreUIUtility.sizeView(toFit: headerView) -// let tableHeaderView = UIView(frame: CGRect(x: 0, y: 0, width: MVMCoreUIUtility.getWidth(), height: headerView.frame.height)) -// tableHeaderView.addSubview(headerView) -// NSLayoutConstraint.constraintPinSubview(toSuperview: headerView) -// tableView?.tableHeaderView = tableHeaderView -// } -// -// /// Takes the current footerView and adds it to the tableFooterView -// func showFooter(_ sizingWidth: CGFloat?) { -// footerView?.removeFromSuperview() -// safeAreaView?.removeFromSuperview() -// guard let footerView = footerView, let tableView = tableView else { -// return -// } -// -// if bottomViewOutsideOfScrollArea { -// // put bottom view outside of scrolling area. -// bottomConstraint?.isActive = false -// view.addSubview(footerView) -// footerView.topAnchor.constraint(equalTo: tableView.bottomAnchor).isActive = true -// footerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true -// view.rightAnchor.constraint(equalTo: footerView.rightAnchor).isActive = true -// view.safeAreaLayoutGuide.bottomAnchor.constraint(equalTo: footerView.bottomAnchor).isActive = true -// safeAreaView = MVMCoreUICommonViewsUtility.getAndSetupSafeAreaView(on: view) -// safeAreaView?.backgroundColor = bottomView?.backgroundColor -// } else { -// bottomConstraint?.isActive = true -// var y: CGFloat? -// if let tableFooterView = tableView.tableFooterView { -// // if footer already exists, use the same y location to avoid strange moving animation -// y = tableFooterView.frame.minY -// } -// -// // This extra view is needed because of the wonkiness of apple's table footer. Things breaks if using autolayout. -// MVMCoreUIUtility.sizeView(toFit: footerView) -// let tableFooterView = UIView(frame: CGRect(x: 0, y: y ?? 0, width: MVMCoreUIUtility.getWidth(), height: footerView.frame.height)) -// tableFooterView.addSubview(footerView) -// NSLayoutConstraint.constraintPinSubview(toSuperview: footerView) -// tableView.tableFooterView = tableFooterView -// } -// } - + //MARK: - Functions to subclass /// Subclass for a top view. open func viewForTop() -> UIView? { @@ -210,85 +143,65 @@ import Foundation return nil } - open func createCollectionViewLayout() -> UICollectionViewLayout { - let layout = UICollectionViewFlowLayout() - layout.scrollDirection = .vertical - layout.minimumLineSpacing = 0 - layout.minimumInteritemSpacing = 0 - layout.estimatedItemSize = UICollectionViewFlowLayout.automaticSize - return layout - } - - open func createCollectionView() -> UICollectionView { - let collection = UICollectionView(frame: .zero, collectionViewLayout: createCollectionViewLayout()) - collection.translatesAutoresizingMaskIntoConstraints = false - collection.dataSource = self - collection.delegate = self - collection.showsHorizontalScrollIndicator = false - collection.backgroundColor = .white - collection.isAccessibilityElement = false - collection.contentInsetAdjustmentBehavior = .always - return collection - } - - deinit { - collectionView?.delegate = nil - collectionView?.dataSource = nil - } - //MARK: - Collection - open func registerCells() { + /// Should be used to refresh the layout of the collection view. Updates flexible padding. + open func invalidateCollectionLayout() { + self.collectionView?.collectionViewLayout.invalidateLayout() + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1, execute: { + self.updateFlexibleSpace() + }) + } + + /// Should be used to reload the data of the collection view. Updates flexible padding. + open func reloadCollectionData() { + collectionView?.reloadData() + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1, execute: { + self.updateFlexibleSpace() + }) + } + + open override func registerCells() { + super.registerCells() collectionView?.register(ContainerCollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerID) collectionView?.register(ContainerCollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, withReuseIdentifier: footerID) } - open func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + open override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return 0 } - open func numberOfSections(in collectionView: UICollectionView) -> Int { - return 1 - } - - open func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionItem", for: indexPath) as! MoleculeCollectionViewCell - let labelModel = LabelModel(text: "hello") - let model = MoleculeCollectionItemModel(with: labelModel) - cell.set(with: model, delegateObjectIVar, nil) - return cell - } - open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { - guard let view = headerView ?? topView, + guard let _ = topView, section == 0 else { return .zero } + let header = headerView ?? self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionHeader, at: IndexPath(row: 0, section: section)) // Use this view to calculate the optimal size based on the collection view's width - return view.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), + return header.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), withHorizontalFittingPriority: .required, // Width is fixed verticalFittingPriority: .fittingSizeLevel) // Height can be as large as needed } open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { - guard let view = footerView ?? bottomView, + guard let _ = bottomView, section == numberOfSections(in: collectionView) - 1 else { return .zero } + let footer = footerView ?? self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionFooter, at: IndexPath(row: 0, section: section)) // Use this view to calculate the optimal size based on the collection view's width - let size = view.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), + let size = footer.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), withHorizontalFittingPriority: .required, // Width is fixed verticalFittingPriority: .fittingSizeLevel) // Height can be as large as needed - print("SIZEEE \(size.height) \(String(describing: footerView?.topConstraint?.constant))") return size } open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { - if (kind == UICollectionView.elementKindSectionFooter) { + if kind == UICollectionView.elementKindSectionFooter { let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: footerID, for: indexPath) as! ContainerCollectionReusableView footerView.addAndContain(view: bottomView!) footerView.topConstraint?.constant = spaceAboveBottomView() ?? 0 self.footerView = footerView return footerView - } else if (kind == UICollectionView.elementKindSectionHeader) { + } else if kind == UICollectionView.elementKindSectionHeader { let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerID, for: indexPath) as! ContainerCollectionReusableView headerView.addAndContain(view: topView!) headerView.bottomConstraint?.constant = spaceBelowTopView() ?? 0 diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index 5bc66109..4e4d289d 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -24,7 +24,7 @@ import UIKit public var formValidator: FormValidator? - public var needsUpdateUI = true + public var needsUpdateUI = false private var observingForResponses = false private var initialLoadFinished = false private var previousScreenSize = CGSize.zero @@ -155,8 +155,8 @@ import UIKit /// Calls processNewData and then sets the ui to update with updateView open func handleNewDataAndUpdateUI() { handleNewData() - self.needsUpdateUI = true - self.view.setNeedsLayout() + needsUpdateUI = true + view.setNeedsLayout() } /// Processes any new data. Called after the page is loaded the first time and on response updates for this page, @@ -170,9 +170,9 @@ import UIKit navigationModel.line = LineModel(type: .none) } pageModel?.navigationItem = navigationModel - if self.formValidator == nil { + if formValidator == nil { let rules = pageModel?.formRules - self.formValidator = FormValidator(rules) + formValidator = FormValidator(rules) } } @@ -268,10 +268,10 @@ import UIKit initialLoad() } - // Handle data on load - handleNewData() - - view.setNeedsLayout() + // Handle data for first load. Dispatched to allow subclasses to finish their view did load implementations. + DispatchQueue.main.async { + self.handleNewDataAndUpdateUI() + } } open override func viewDidLayoutSubviews() { diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.m b/MVMCoreUI/Utility/MVMCoreUIUtility.m index 59c55cc6..b502467d 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.m @@ -168,8 +168,8 @@ topInset = scrollview.adjustedContentInset.top; bottomInset = scrollview.adjustedContentInset.bottom; } - CGFloat remainingSpace = frameHeight - contentSizeHeight - topInset - bottomInset; + NSLog(@"scc SPACCEEE remaining: %f frame: %f, content: %f, insets:(%f,%f)",remainingSpace,frameHeight,contentSizeHeight,topInset,bottomInset); return remainingSpace - 1; } From 9178385e6d9ab2d85aa1bb400412efb76eb08b19 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 8 Apr 2020 16:16:16 -0400 Subject: [PATCH 42/62] comments --- .../BaseControllers/ThreeLayerCollectionViewController.swift | 2 ++ 1 file changed, 2 insertions(+) diff --git a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift index 62c47d6e..af9fce4c 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift @@ -148,6 +148,7 @@ import Foundation /// Should be used to refresh the layout of the collection view. Updates flexible padding. open func invalidateCollectionLayout() { self.collectionView?.collectionViewLayout.invalidateLayout() + // TODO: Improve this workaround (autolayout for cells happens async so contentSize isn't accurate immediately) DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1, execute: { self.updateFlexibleSpace() }) @@ -156,6 +157,7 @@ import Foundation /// Should be used to reload the data of the collection view. Updates flexible padding. open func reloadCollectionData() { collectionView?.reloadData() + // TODO: Improve this workaround (autolayout for cells happens async so contentSize isn't accurate immediately) DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 0.1, execute: { self.updateFlexibleSpace() }) From e4a6a1ddf0816a0f610c646a95109fb3affaa0ad Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 8 Apr 2020 16:18:05 -0400 Subject: [PATCH 43/62] remove code for kevin pr --- .../Atomic/Molecules/Doughnut/DoughnutChartModel.swift | 7 ------- 1 file changed, 7 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartModel.swift b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartModel.swift index 2b64d1ae..ff9b1bf6 100644 --- a/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartModel.swift +++ b/MVMCoreUI/Atomic/Molecules/Doughnut/DoughnutChartModel.swift @@ -35,11 +35,4 @@ import Foundation self.color = color self.label = label } - - private enum CodingKeys: String, CodingKey { - case backgroundColor - case label - case percent - case color - } } From 8a9d85a83c8523cd9df2dadcdd3dfd72e78a17fe Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 8 Apr 2020 16:24:17 -0400 Subject: [PATCH 44/62] comments --- .../BaseControllers/ContainerCollectionReusableView.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/MVMCoreUI/BaseControllers/ContainerCollectionReusableView.swift b/MVMCoreUI/BaseControllers/ContainerCollectionReusableView.swift index a0e80f21..d7fb0ed4 100644 --- a/MVMCoreUI/BaseControllers/ContainerCollectionReusableView.swift +++ b/MVMCoreUI/BaseControllers/ContainerCollectionReusableView.swift @@ -8,10 +8,11 @@ import Foundation +/// CollectionReusableView that can contains any other view. public class ContainerCollectionReusableView: UICollectionReusableView { - var view: UIView? - var topConstraint: NSLayoutConstraint? - var bottomConstraint: NSLayoutConstraint? + public var view: UIView? + public var topConstraint: NSLayoutConstraint? + public var bottomConstraint: NSLayoutConstraint? public func addAndContain(view: UIView) { guard self.view != view else { return } From c6b8eacff48343620b23ac6a5bc4c8b9ce24bfbd Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 8 Apr 2020 16:36:46 -0400 Subject: [PATCH 45/62] update fix --- MVMCoreUI/BaseClasses/CollectionViewCell.swift | 4 +--- .../ThreeLayerCollectionViewController.swift | 11 ++++++++--- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/MVMCoreUI/BaseClasses/CollectionViewCell.swift b/MVMCoreUI/BaseClasses/CollectionViewCell.swift index fb5b1a5e..e7bb7893 100644 --- a/MVMCoreUI/BaseClasses/CollectionViewCell.swift +++ b/MVMCoreUI/BaseClasses/CollectionViewCell.swift @@ -45,9 +45,7 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo open func updateView(_ size: CGFloat) { containerHelper.updateViewMargins(contentView, model: model, size: size) - DispatchQueue.main.async { - print("leading \(self.contentView.directionalLayoutMargins.leading)") - } + (molecule as? MVMCoreViewProtocol)?.updateView(size) } open func reset() { diff --git a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift index af9fce4c..bf5520b9 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift @@ -8,9 +8,9 @@ import Foundation +/// A view controller that has three main layers, a header, collection rows, and a footer. The header is added as a supplement header to the first section, and the footer is added as a supplement footer to the last section. This view controller allows for flexible space between the three layers to fit the screeen. @objc open class ThreeLayerCollectionViewController: ProgrammaticCollectionViewController, UICollectionViewDelegateFlowLayout { - // The three main views private var topView: UIView? private var bottomView: UIView? private var headerView: ContainerCollectionReusableView? @@ -69,7 +69,7 @@ import Foundation } } - //MARK: - MFViewController + //MARK: - ViewController open override func updateViews() { super.updateViews() let width = view.bounds.width @@ -79,6 +79,11 @@ import Foundation if let bottomView = bottomView as? MVMCoreViewProtocol { bottomView.updateView(width) } + if let cells = collectionView?.visibleCells { + for cell in cells { + (cell as? MVMCoreViewProtocol)?.updateView(width) + } + } invalidateCollectionLayout() } @@ -106,7 +111,7 @@ import Foundation return nil } - /// can override to return a minimum fill space. + /// can override to return a minimum fill space. 0 default open func minimumFillSpace() -> CGFloat { return 0 } From 4941c51be3627eb2f5fa8da8a2c0f36524b9efdd Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 8 Apr 2020 16:47:20 -0400 Subject: [PATCH 46/62] update to make collection less restrictive --- .../Items/CollectionItemModelProtocol.swift | 2 +- .../Items/MoleculeCollectionItemModel.swift | 2 +- .../BaseClasses/CollectionViewCell.swift | 9 +++++-- ...ProgrammaticCollectionViewController.swift | 1 + .../ThreeLayerCollectionViewController.swift | 25 ++++++++----------- 5 files changed, 20 insertions(+), 19 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/Items/CollectionItemModelProtocol.swift b/MVMCoreUI/Atomic/Molecules/Items/CollectionItemModelProtocol.swift index c8bfb7d7..9361ab1e 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/CollectionItemModelProtocol.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/CollectionItemModelProtocol.swift @@ -8,6 +8,6 @@ import Foundation -public protocol CollectionItemModelProtocol: ContainerModelProtocol { +public protocol CollectionItemModelProtocol { } diff --git a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift index 8d236f4b..b3d2aba6 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift @@ -9,7 +9,7 @@ import Foundation -@objcMembers open class MoleculeCollectionItemModel: CollectionItemModelProtocol, MoleculeModelProtocol { +@objcMembers open class MoleculeCollectionItemModel: CollectionItemModelProtocol, ContainerModelProtocol, MoleculeModelProtocol { open class var identifier: String { return "collectionItem" } diff --git a/MVMCoreUI/BaseClasses/CollectionViewCell.swift b/MVMCoreUI/BaseClasses/CollectionViewCell.swift index e7bb7893..e9857808 100644 --- a/MVMCoreUI/BaseClasses/CollectionViewCell.swift +++ b/MVMCoreUI/BaseClasses/CollectionViewCell.swift @@ -8,6 +8,7 @@ import Foundation +/// A base collection view cell with basic mvm functionality. open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCoreViewProtocol { // Convenience helpers @@ -44,7 +45,9 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo } open func updateView(_ size: CGFloat) { - containerHelper.updateViewMargins(contentView, model: model, size: size) + if let model = model as? ContainerModelProtocol { + containerHelper.updateViewMargins(contentView, model: model, size: size) + } (molecule as? MVMCoreViewProtocol)?.updateView(size) } @@ -63,7 +66,9 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo } // align if needed. - containerHelper.set(with: model, for: molecule as? MVMCoreUIViewConstrainingProtocol) + if let model = model as? ContainerModelProtocol { + containerHelper.set(with: model, for: molecule as? MVMCoreUIViewConstrainingProtocol) + } } /// Convenience function. Adds the molecule to the view. diff --git a/MVMCoreUI/BaseControllers/ProgrammaticCollectionViewController.swift b/MVMCoreUI/BaseControllers/ProgrammaticCollectionViewController.swift index 0dd473e2..9d279d79 100644 --- a/MVMCoreUI/BaseControllers/ProgrammaticCollectionViewController.swift +++ b/MVMCoreUI/BaseControllers/ProgrammaticCollectionViewController.swift @@ -8,6 +8,7 @@ import Foundation +/// A base view controller with a collection view. @objc open class ProgrammaticCollectionViewController: ScrollingViewController { public var collectionView: UICollectionView? diff --git a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift index bf5520b9..82dda260 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift @@ -181,35 +181,30 @@ import Foundation open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForHeaderInSection section: Int) -> CGSize { guard let _ = topView, section == 0 else { return .zero } + + // Calculate the height of the header since apple doesn't support autolayout. Width is fixed, height is tall as content. let header = headerView ?? self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionHeader, at: IndexPath(row: 0, section: section)) - - // Use this view to calculate the optimal size based on the collection view's width - return header.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), - withHorizontalFittingPriority: .required, // Width is fixed - verticalFittingPriority: .fittingSizeLevel) // Height can be as large as needed + return header.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel) } open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, referenceSizeForFooterInSection section: Int) -> CGSize { guard let _ = bottomView, section == numberOfSections(in: collectionView) - 1 else { return .zero } + + // Calculate the height of the footr since apple doesn't support autolayout. Width is fixed, height is tall as content. let footer = footerView ?? self.collectionView(collectionView, viewForSupplementaryElementOfKind: UICollectionView.elementKindSectionFooter, at: IndexPath(row: 0, section: section)) - - // Use this view to calculate the optimal size based on the collection view's width - let size = footer.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), - withHorizontalFittingPriority: .required, // Width is fixed - verticalFittingPriority: .fittingSizeLevel) // Height can be as large as needed - return size + return footer.systemLayoutSizeFitting(CGSize(width: collectionView.frame.width, height: UIView.layoutFittingExpandedSize.height), withHorizontalFittingPriority: .required, verticalFittingPriority: .fittingSizeLevel) } open func collectionView(_ collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, at indexPath: IndexPath) -> UICollectionReusableView { - if kind == UICollectionView.elementKindSectionFooter { - let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: footerID, for: indexPath) as! ContainerCollectionReusableView + if kind == UICollectionView.elementKindSectionFooter, + let footerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: footerID, for: indexPath) as? ContainerCollectionReusableView { footerView.addAndContain(view: bottomView!) footerView.topConstraint?.constant = spaceAboveBottomView() ?? 0 self.footerView = footerView return footerView - } else if kind == UICollectionView.elementKindSectionHeader { - let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerID, for: indexPath) as! ContainerCollectionReusableView + } else if kind == UICollectionView.elementKindSectionHeader, + let headerView = collectionView.dequeueReusableSupplementaryView(ofKind: kind, withReuseIdentifier: headerID, for: indexPath) as? ContainerCollectionReusableView { headerView.addAndContain(view: topView!) headerView.bottomConstraint?.constant = spaceBelowTopView() ?? 0 self.headerView = headerView From ce8cc3d430e7ae7f0161d66fcfe9aa22ac3dcde4 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 8 Apr 2020 16:51:30 -0400 Subject: [PATCH 47/62] comments --- MVMCoreUI.xcodeproj/project.pbxproj | 2 +- .../Atomic/Molecules/Items/MoleculeCollectionItemModel.swift | 2 +- .../Atomic/Molecules/Items/MoleculeCollectionViewCell.swift | 1 + MVMCoreUI/BaseClasses/CollectionViewCell.swift | 5 ++++- .../Protocols}/CollectionItemModelProtocol.swift | 0 5 files changed, 7 insertions(+), 3 deletions(-) rename MVMCoreUI/{Atomic/Molecules/Items => BaseClasses/Protocols}/CollectionItemModelProtocol.swift (100%) diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index df6cdbf6..9c49c057 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -914,6 +914,7 @@ 0A5D59C323AD488600EFD9E9 /* Protocols */ = { isa = PBXGroup; children = ( + D21B7F72243BAC6800051ABF /* CollectionItemModelProtocol.swift */, 0A5D59C123AD2F5700EFD9E9 /* AppleGuidelinesProtocol.swift */, ); path = Protocols; @@ -1265,7 +1266,6 @@ D260105E23D0BFFC00764D80 /* StackItem.swift */, 01EB368A23609801006832FA /* MoleculeStackItemModel.swift */, D2FB151C23A40F1500C20E10 /* MoleculeStackItem.swift */, - D21B7F72243BAC6800051ABF /* CollectionItemModelProtocol.swift */, D21B7F76243BB70700051ABF /* MoleculeCollectionItemModel.swift */, D2A6390422CBCE160052ED1F /* MoleculeCollectionViewCell.swift */, 012A88C1238D7BCA00FE3DA1 /* CarouselItemModel.swift */, diff --git a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift index b3d2aba6..b9ac345b 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift @@ -8,7 +8,7 @@ import Foundation - +/// A model for a collection item that is a container for any molecule. @objcMembers open class MoleculeCollectionItemModel: CollectionItemModelProtocol, ContainerModelProtocol, MoleculeModelProtocol { open class var identifier: String { return "collectionItem" diff --git a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift index 0ae515f5..1f615732 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift @@ -8,6 +8,7 @@ import UIKit +/// A collection item that is a container for any molecule. open class MoleculeCollectionViewCell: CollectionViewCell { open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { diff --git a/MVMCoreUI/BaseClasses/CollectionViewCell.swift b/MVMCoreUI/BaseClasses/CollectionViewCell.swift index e9857808..a559c93e 100644 --- a/MVMCoreUI/BaseClasses/CollectionViewCell.swift +++ b/MVMCoreUI/BaseClasses/CollectionViewCell.swift @@ -18,6 +18,7 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo private var initialSetupPerformed = false + // MARK: - Inits public override init(frame: CGRect) { super.init(frame: .zero) initialSetup() @@ -35,6 +36,7 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo } } + // MARK: - MVMCoreViewProtocol open func setupView() { isAccessibilityElement = false contentView.isAccessibilityElement = false @@ -56,6 +58,7 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo backgroundColor = .white } + // MARK: - MoleculeViewProtocol open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { guard let model = model as? CollectionItemModelProtocol else { return } self.model = model @@ -71,7 +74,7 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo } } - /// Convenience function. Adds the molecule to the view. + /// Convenience function. Adds a molecule to the view. open func addMolecule(_ molecule: MoleculeViewProtocol) { contentView.addSubview(molecule) containerHelper.constrainView(molecule) diff --git a/MVMCoreUI/Atomic/Molecules/Items/CollectionItemModelProtocol.swift b/MVMCoreUI/BaseClasses/Protocols/CollectionItemModelProtocol.swift similarity index 100% rename from MVMCoreUI/Atomic/Molecules/Items/CollectionItemModelProtocol.swift rename to MVMCoreUI/BaseClasses/Protocols/CollectionItemModelProtocol.swift From 40efdc4968e23493376aac7c9f0018e1a133ea3f Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 8 Apr 2020 17:24:38 -0400 Subject: [PATCH 48/62] re-order --- MVMCoreUI/Atomic/Templates/CollectionTemplate.swift | 4 ++-- MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift index d8812119..0bbcd45f 100644 --- a/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift @@ -79,9 +79,9 @@ import Foundation open override func handleNewData() { - super.handleNewData() setup() - registerCells() + registerCells() + super.handleNewData() } //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift index 7575faf1..b236e332 100644 --- a/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/MoleculeListTemplate.swift @@ -81,9 +81,9 @@ open class MoleculeListTemplate: ThreeLayerTableViewController, TemplateProtocol } open override func handleNewData() { - super.handleNewData() setup() registerWithTable() + super.handleNewData() } //-------------------------------------------------- From eccfa4db62a2d6a8bb61afa7eaf3b47e37f2cfa5 Mon Sep 17 00:00:00 2001 From: Kruthika KP <> Date: Thu, 9 Apr 2020 11:54:00 +0530 Subject: [PATCH 49/62] removed duplicate files --- .../ListThreeColumnDataUsageDivider.swift | 61 -------- ...ListThreeColumnDataUsageDividerModel.swift | 51 ------- .../OtherHandlers/MoleculeObjectMapping.swift | 144 ------------------ 3 files changed, 256 deletions(-) delete mode 100644 MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift delete mode 100644 MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDividerModel.swift delete mode 100644 MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift diff --git a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift deleted file mode 100644 index c4944e3e..00000000 --- a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift +++ /dev/null @@ -1,61 +0,0 @@ -// -// ListThreeColumnDataUsageDivider.swift -// MVMCoreUI -// -// Created by Kruthika KP on 20/03/20. -// Copyright © 2020 Verizon Wireless. All rights reserved. -// - -import Foundation - -@objcMembers open class ListThreeColumnDataUsageDivider: TableViewCell { - - //----------------------------------------------------- - // MARK: - Outlets - //------------------------------------------------------- - public let leftLabel = Label.createLabelBoldBodySmall(true) - public let centerLabel = Label.createLabelBoldBodySmall(true) - public let rightLabel = Label.createLabelBoldBodySmall(true) - var stack: Stack - - //------------------------------------------------------ - // MARK: - Initializers - //------------------------------------------------------ - public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - stack = Stack.createStack(with: [(view: leftLabel, model: StackItemModel(percent: 33, horizontalAlignment: .leading)), - (view: centerLabel, model: StackItemModel(percent: 33, horizontalAlignment: .center)), - (view: rightLabel, model: StackItemModel(percent: 34, horizontalAlignment: .center))], - axis: .horizontal) - super.init(style: style, reuseIdentifier: reuseIdentifier) - } - - public required init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - open override func setupView() { - super.setupView() - addMolecule(stack) - stack.restack() - } - - // MARK: - ModelMoleculeViewProtocol - open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { - super.set(with: model, delegateObject, additionalData) - guard let model = model as? ListThreeColumnDataUsageDividerModel else { return } - leftLabel.set(with: model.leftLabel, delegateObject, additionalData) - centerLabel.set(with: model.centerLabel, delegateObject, additionalData) - rightLabel.set(with: model.rightLabel, delegateObject, additionalData) - } - - open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat { - return 121 - } - - open override func reset() { - super.reset() - leftLabel.styleBoldBodySmall(true) - centerLabel.styleBoldBodySmall(true) - rightLabel.styleBoldBodySmall(true) - } -} diff --git a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDividerModel.swift b/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDividerModel.swift deleted file mode 100644 index f57bdf01..00000000 --- a/MVMCoreUI/Atomic/Molecules/HorizontalCombinationViews/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDividerModel.swift +++ /dev/null @@ -1,51 +0,0 @@ -// -// ListThreeColumnDataUsageDividerModel.swift -// MVMCoreUI -// -// Created by Kruthika KP on 20/03/20. -// Copyright © 2020 Verizon Wireless. All rights reserved. -// - -import Foundation - -public class ListThreeColumnDataUsageDividerModel: ListItemModel, MoleculeModelProtocol { - public static var identifier: String = "list3CDataUsgDiv" - public let leftLabel: LabelModel - public let centerLabel: LabelModel - public let rightLabel: LabelModel - - public init(leftLabel: LabelModel, centerLabel: LabelModel, rightLabel: LabelModel) { - self.leftLabel = leftLabel - self.centerLabel = centerLabel - self.rightLabel = rightLabel - super.init() - } - - override public func setDefaults() { - super.setDefaults() - style = "tallDivider" - } - - private enum CodingKeys: String, CodingKey { - case moleculeName - case leftLabel - case centerLabel - case rightLabel - } - - required init(from decoder: Decoder) throws { - let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - leftLabel = try typeContainer.decode(LabelModel.self, forKey: .leftLabel) - centerLabel = try typeContainer.decode(LabelModel.self, forKey: .centerLabel) - rightLabel = try typeContainer.decode(LabelModel.self, forKey: .rightLabel) - try super.init(from:decoder) - } - - public override func encode(to encoder: Encoder) throws { - var container = encoder.container(keyedBy: CodingKeys.self) - try container.encode(moleculeName, forKey: .moleculeName) - try container.encode(leftLabel, forKey: .leftLabel) - try container.encode(centerLabel, forKey: .centerLabel) - try container.encode(rightLabel, forKey: .rightLabel) - } -} diff --git a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift b/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift deleted file mode 100644 index a33e298e..00000000 --- a/MVMCoreUI/OtherHandlers/MoleculeObjectMapping.swift +++ /dev/null @@ -1,144 +0,0 @@ -// -// MVMCoreUIMoleculeMappingObject+ModelMapping.swift -// MVMCoreUI -// -// Created by Suresh, Kamlesh on 10/28/19. -// Copyright © 2019 Verizon Wireless. All rights reserved. -// - -import Foundation - -@objcMembers public class MoleculeObjectMapping: NSObject { - public static func registerObjects() { - // Stacks - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: MoleculeStackView.self, viewModelClass: MoleculeStackModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Stack.self, viewModelClass: StackModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: UnOrderedList.self, viewModelClass: UnOrderedListModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: NumberedList.self, viewModelClass: NumberedListModel.self) - - // Label - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Label.self, viewModelClass: LabelModel.self) - // need to move labelattributemodel to different method - try? ModelRegistry.register(LabelAttributeFontModel.self) - try? ModelRegistry.register(LabelAttributeColorModel.self) - try? ModelRegistry.register(LabelAttributeImageModel.self) // We need to separate the registry by types due to collisions... - try? ModelRegistry.register(LabelAttributeUnderlineModel.self) - try? ModelRegistry.register(LabelAttributeStrikeThroughModel.self) - try? ModelRegistry.register(LabelAttributeActionModel.self) - - // Buttons - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: PillButton.self, viewModelClass: ButtonModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: TwoButtonView.self, viewModelClass: TwoButtonViewModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ExternalLink.self, viewModelClass: ExternalLinkModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Link.self, viewModelClass: LinkModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: CaretLink.self, viewModelClass: CaretLinkModel.self) - - // Entry Field - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: TextEntryField.self, viewModelClass: TextEntryFieldModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: MdnEntryField.self, viewModelClass: MdnEntryFieldModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: DigitEntryField.self, viewModelClass: DigitEntryFieldModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ItemDropdownEntryField.self, viewModelClass: ItemDropdownEntryFieldModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: DateDropdownEntryField.self, viewModelClass: DateDropdownEntryFieldModel.self) - - // Other Atoms - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ProgressBar.self, viewModelClass: ProgressBarModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: MultiProgress.self, viewModelClass: MultiProgressBarModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: CaretView.self, viewModelClass: CaretViewModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: DashLine.self, viewModelClass: DashLineModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: MFLoadImageView.self, viewModelClass: ImageViewModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Line.self, viewModelClass: LineModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: GraphView.self, viewModelClass: CircleProgressModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Toggle.self, viewModelClass: ToggleModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Checkbox.self, viewModelClass: CheckboxModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: CheckboxLabel.self, viewModelClass: CheckboxLabelModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Arrow.self, viewModelClass: ArrowModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: RadioButton.self, viewModelClass: RadioButtonModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: RadioButtonLabel.self, viewModelClass: RadioButtonLabelModel.self) - - // Horizontal Combination Molecules - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: StringAndMoleculeView.self, viewModelClass: StringAndMoleculeModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ImageHeadlineBody.self, viewModelClass: ImageHeadlineBodyModel.self) - - // Vertical Combination Molecules - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: HeadlineBody.self, viewModelClass: HeadlineBodyModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: HeadLineBodyCaretLinkImage.self, viewModelClass: HeadlineBodyCaretLinkImageModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: EyebrowHeadlineBodyLink.self, viewModelClass: EyebrowHeadlineBodyLinkModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: HeadlineBodyLink.self, viewModelClass: HeadlineBodyLinkModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: HeadlineBodyButton.self, viewModelClass: HeadlineBodyButtonModel.self) - - // Left Right Molecules - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: CornerLabels.self, viewModelClass: CornerLabelsModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: LeftRightLabelView.self, viewModelClass: LeftRightLabelModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: LabelToggle.self, viewModelClass: LabelToggleModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: HeadlineBodyToggle.self, viewModelClass: HeadlineBodyToggleModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: HeadlineBodyLinkToggle.self, viewModelClass: HeadlineBodyLinkToggleModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ActionDetailWithImage.self, viewModelClass: ActionDetailWithImageModel.self) - - // List items - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: MoleculeTableViewCell.self, viewModelClass: MoleculeListItemModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: DropDownFilterTableViewCell.self, viewModelClass: DropDownListItemModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: AccordionMoleculeTableViewCell.self, viewModelClass: AccordionListItemModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: TabsTableViewCell.self, viewModelClass: TabsListItemModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListProgressBarData.self, viewModelClass: ListProgressBarDataModel.self) - - // Other Items - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: MoleculeStackItem.self, viewModelClass: MoleculeStackItemModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: StackItem.self, viewModelClass: StackItemModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: MoleculeCollectionViewCell.self, viewModelClass: CarouselItemModel.self) - - // Other Container Molecules - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: MoleculeHeaderView.self, viewModelClass: MoleculeHeaderModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: FooterView.self, viewModelClass: FooterModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Scroller.self, viewModelClass: ScrollerModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ModuleMolecule.self, viewModelClass: ModuleMoleculeModel.self) - - // Other Molecules - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: DoughnutChartView.self, viewModelClass: DoughnutChartModel.self) - - // Other Organisms - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: Carousel.self, viewModelClass: CarouselModel.self) - - // Designed List Items - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListLeftVariableIconWithRightCaret.self, viewModelClass: ListLeftVariableIconWithRightCaretModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListLeftVariableCheckboxAllTextAndLinks.self, viewModelClass: ListLeftVariableCheckboxAllTextAndLinksModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListLeftVariableRadioButtonAndPaymentMethod.self, viewModelClass: ListLeftVariableRadioButtonAndPaymentMethodModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListRVWheel.self, viewModelClass: ListRVWheelModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListRightVariablePayments.self, viewModelClass: ListRightVariablePaymentsModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListRightVariableTotalData.self, viewModelClass: ListRightVariableTotalDataModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListOneColumnFullWidthTextAllTextAndLinks.self, viewModelClass: ListOneColumnFullWidthTextAllTextAndLinksModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListOneColumnFullWidthTextBodyText.self, viewModelClass: ListOneColumnFullWidthTextBodyTextModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListTwoColumnCompareChanges.self, viewModelClass: ListTwoColumnCompareChangesModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListTwoColumnPriceDetails.self, viewModelClass: ListTwoColumnPriceDetailsModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListTwoColumnPriceDescription.self, viewModelClass: ListTwoColumnPriceDescriptionModel.self) - - // Designed Section Dividers - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListFourColumnDataUsageDivider.self, viewModelClass: ListFourColumnDataUsageDividerModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListThreeColumnPlanDataDivider.self, viewModelClass: ListThreeColumnPlanDataDividerModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListOneColumnTextWithWhitespaceDividerShort.self, viewModelClass: ListOneColumnTextWithWhitespaceDividerShortModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListOneColumnTextWithWhitespaceDividerTall.self, viewModelClass: ListOneColumnTextWithWhitespaceDividerTallModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListOneColumnFullWidthTextDividerSubsection.self, viewModelClass: ListOneColumnFullWidthTextDividerSubsectionModel.self) - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: ListThreeColumnDataUsageDivider.self, viewModelClass: ListThreeColumnDataUsageDividerModel.self) - - // Designed Headers - MVMCoreUIMoleculeMappingObject.shared()?.register(viewClass: HeadersH2NoButtonsBodyText.self, viewModelClass: HeadersH2NoButtonsBodyTextModel.self) - - // TODO: Need model - MVMCoreUIMoleculeMappingObject.shared()?.moleculeMapping.setObject(MVMCoreUIPageControl.self, forKey: "barsPager" as NSString) - - // TODO: Need View - try? ModelRegistry.register(TabsModel.self) - - // Helper models - try? ModelRegistry.register(RuleRequiredModel.self) - try? ModelRegistry.register(RuleAnyRequiredModel.self) - try? ModelRegistry.register(RuleAnyValueChangedModel.self) - try? ModelRegistry.register(RuleAllValueChangedModel.self) - try? ModelRegistry.register(RuleEqualsModel.self) - try? ModelRegistry.register(RuleRegexModel.self) - - // Actions - try? ModelRegistry.register(ActionTopAlertModel.self) - try? ModelRegistry.register(ActionCollapseNotificationModel.self) - try? ModelRegistry.register(ActionOpenPanelModel.self) - } -} From 76d4a3975780b2a945502beae04a879efcfb5bb0 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 9 Apr 2020 10:25:02 -0400 Subject: [PATCH 50/62] change for git --- MVMCoreUI/Styles/Styler.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Styles/Styler.swift b/MVMCoreUI/Styles/Styler.swift index 96bd558c..b5d6627c 100644 --- a/MVMCoreUI/Styles/Styler.swift +++ b/MVMCoreUI/Styles/Styler.swift @@ -213,9 +213,9 @@ open class Styler { } } - open class func setMarginsFor(_ view: UIView?, size: CGFloat, defaultHorizontal horizontal: Bool, top: CGFloat, bottom: CGFloat) { + open class func setMarginsFor(_ view: UIView?, size: CGFloat, horizontal: CGFloat?, top: CGFloat, bottom: CGFloat) { - let horizontalPadding: CGFloat = horizontal ? Padding.Component.horizontalPaddingForSize(size) : 0 + let horizontalPadding: CGFloat = horizontal ?? Padding.Component.horizontalPaddingForSize(size) DispatchQueue.main.async { MVMCoreUIUtility.setMarginsFor(view, From b7edafc5d885a21f98754411d98f74dcf1e6746d Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 9 Apr 2020 11:17:10 -0400 Subject: [PATCH 51/62] columns --- MVMCoreUI.xcodeproj/project.pbxproj | 4 +++ .../Atomic/Templates/CollectionTemplate.swift | 25 +++++++++++++-- .../CollectionTemplateItemProtocol.swift | 29 +++++++++++++++++ .../BaseClasses/CollectionViewCell.swift | 15 ++++++++- .../ThreeLayerCollectionViewController.swift | 32 ++++++++++++------- MVMCoreUI/Utility/MVMCoreUIUtility.m | 1 - 6 files changed, 89 insertions(+), 17 deletions(-) create mode 100644 MVMCoreUI/Atomic/Templates/CollectionTemplateItemProtocol.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 4dd0bb20..eeb8862a 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -257,6 +257,7 @@ D264FA90243BCE6800D98315 /* ThreeLayerCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FA8F243BCE6800D98315 /* ThreeLayerCollectionViewController.swift */; }; D264FAA1243CF66B00D98315 /* ContainerCollectionReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FAA0243CF66B00D98315 /* ContainerCollectionReusableView.swift */; }; D264FAA3243E632F00D98315 /* ProgrammaticCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FAA2243E632F00D98315 /* ProgrammaticCollectionViewController.swift */; }; + D264FAA5243F66A500D98315 /* CollectionTemplateItemProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D264FAA4243F66A500D98315 /* CollectionTemplateItemProtocol.swift */; }; D268C70C2386DFFD007F2C1C /* MoleculeStackItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 01EB368A23609801006832FA /* MoleculeStackItemModel.swift */; }; D268C70E238C22D7007F2C1C /* DropDownFilterTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */; }; D26C5A6B23F4A40D007AEECE /* ListItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */; }; @@ -670,6 +671,7 @@ D264FA8F243BCE6800D98315 /* ThreeLayerCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerCollectionViewController.swift; sourceTree = ""; }; D264FAA0243CF66B00D98315 /* ContainerCollectionReusableView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContainerCollectionReusableView.swift; sourceTree = ""; }; D264FAA2243E632F00D98315 /* ProgrammaticCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProgrammaticCollectionViewController.swift; sourceTree = ""; }; + D264FAA4243F66A500D98315 /* CollectionTemplateItemProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollectionTemplateItemProtocol.swift; sourceTree = ""; }; D268C70D238C22D7007F2C1C /* DropDownFilterTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DropDownFilterTableViewCell.swift; sourceTree = ""; }; D26C5A6A23F4A40D007AEECE /* ListItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListItemModel.swift; sourceTree = ""; }; D274CA322236A78900B01B62 /* FooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FooterView.swift; sourceTree = ""; }; @@ -1442,6 +1444,7 @@ 942C378B2412F4FA0066E45E /* ModalMoleculeListTemplate.swift */, 014AA72A23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift */, D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */, + D264FAA4243F66A500D98315 /* CollectionTemplateItemProtocol.swift */, D264FA8B243BCD8E00D98315 /* CollectionTemplateModel.swift */, D264FA8D243BCD9A00D98315 /* CollectionTemplate.swift */, ); @@ -2237,6 +2240,7 @@ 01EB3684236097C0006832FA /* MoleculeModelProtocol.swift in Sources */, D27CD4102339057800C1DC07 /* EyebrowHeadlineBodyLink.swift in Sources */, 8D070BB2241B56AD0099AC56 /* ListRightVariableTotalData.swift in Sources */, + D264FAA5243F66A500D98315 /* CollectionTemplateItemProtocol.swift in Sources */, D29DF11D21E684A9003B2FB9 /* MVMCoreUISplitViewController.m in Sources */, 8DD1E36E243B3CFB00D8F2DF /* ListThreeColumnInternationalDataModel.swift in Sources */, D243859923A16B1800332775 /* Container.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift index 0bbcd45f..1d2f07a6 100644 --- a/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift +++ b/MVMCoreUI/Atomic/Templates/CollectionTemplate.swift @@ -83,11 +83,23 @@ import Foundation registerCells() super.handleNewData() } - + //-------------------------------------------------- // MARK: - Collection //-------------------------------------------------- + open override func update(cell: UICollectionViewCell, size: CGFloat) { + super.update(cell: cell, size: size) + + // Update the width for columns. + if let collectionView = collectionView, + let columns = templateModel?.columns, columns > 0, + let cell = cell as? CollectionTemplateItemProtocol { + let width = (size - collectionView.adjustedContentInset.left - collectionView.adjustedContentInset.right) / CGFloat(columns) + cell.set(width: width) + } + } + open override func registerCells() { super.registerCells() guard let moleculesInfo = moleculesInfo else { return } @@ -111,13 +123,20 @@ import Foundation let cell = collectionView.dequeueReusableCell(withReuseIdentifier: moleculeInfo.identifier, for: indexPath) (cell as? MoleculeViewProtocol)?.reset() (cell as? MoleculeViewProtocol)?.set(with: moleculeInfo.molecule, delegateObjectIVar, nil) - (cell as? MVMCoreViewProtocol)?.updateView(view.bounds.width) - + update(cell: cell, size: view.frame.width) // Neded to fix an apple defect where the cell is not the correct size on certain devices for certain cells cell.layoutIfNeeded() return cell } + public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { + (collectionView.cellForItem(at: indexPath) as? CollectionTemplateItemProtocol)?.didSelectCell(at: indexPath, delegateObject: delegateObjectIVar, additionalData: nil) + } + + public func collectionView(_ collectionView: UICollectionView, willDisplay cell: UICollectionViewCell, forItemAt indexPath: IndexPath) { + (cell as? CollectionTemplateItemProtocol)?.willDisplay() + } + //-------------------------------------------------- // MARK: - Convenience //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Templates/CollectionTemplateItemProtocol.swift b/MVMCoreUI/Atomic/Templates/CollectionTemplateItemProtocol.swift new file mode 100644 index 00000000..55db2c6d --- /dev/null +++ b/MVMCoreUI/Atomic/Templates/CollectionTemplateItemProtocol.swift @@ -0,0 +1,29 @@ +// +// CollectionTemplateItemProtocol.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 4/9/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +/// A protocol that items of the CollectionTemplate must conform to. +public protocol CollectionTemplateItemProtocol: UICollectionViewCell { + + /// Set the width of the item. Used for the columns functionality + func set(width: CGFloat) + + /// Handle action when cell is pressed + func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) + + /// Called when the cell will display. + func willDisplay() +} + +// Default implementation does nothing +extension CollectionTemplateItemProtocol { + public func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {} + + public func willDisplay() {} +} diff --git a/MVMCoreUI/BaseClasses/CollectionViewCell.swift b/MVMCoreUI/BaseClasses/CollectionViewCell.swift index a559c93e..58bd06ff 100644 --- a/MVMCoreUI/BaseClasses/CollectionViewCell.swift +++ b/MVMCoreUI/BaseClasses/CollectionViewCell.swift @@ -9,12 +9,13 @@ import Foundation /// A base collection view cell with basic mvm functionality. -open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCoreViewProtocol { +open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCoreViewProtocol, CollectionTemplateItemProtocol { // Convenience helpers open var molecule: MoleculeViewProtocol? public let containerHelper = ContainerHelper() open var model: CollectionItemModelProtocol? + open var widthConstraint: NSLayoutConstraint? private var initialSetupPerformed = false @@ -56,6 +57,7 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo open func reset() { molecule?.reset() backgroundColor = .white + widthConstraint?.isActive = false } // MARK: - MoleculeViewProtocol @@ -80,4 +82,15 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo containerHelper.constrainView(molecule) self.molecule = molecule } + + // MARK: - CollectionTemplateItemProtocol + public func set(width: CGFloat) { + if let widthConstraint = widthConstraint { + widthConstraint.constant = width + widthConstraint.isActive = true + } else { + widthConstraint = contentView.widthAnchor.constraint(equalToConstant: width) + widthConstraint?.isActive = true + } + } } diff --git a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift index 82dda260..aa34f2f2 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerCollectionViewController.swift @@ -50,7 +50,7 @@ import Foundation currentSpaceForCompare = currentSpace * 2; } - if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpaceForCompare, 2) { + if !MVMCoreGetterUtility.cgfequalwiththreshold(newSpace, currentSpaceForCompare, 1) { if fillTop && fillBottom { // space both let half = newSpace / 2 @@ -72,19 +72,22 @@ import Foundation //MARK: - ViewController open override func updateViews() { super.updateViews() - let width = view.bounds.width - if let topView = topView as? MVMCoreViewProtocol { - topView.updateView(width) - } - if let bottomView = bottomView as? MVMCoreViewProtocol { - bottomView.updateView(width) - } - if let cells = collectionView?.visibleCells { - for cell in cells { - (cell as? MVMCoreViewProtocol)?.updateView(width) + // Needed due to dispatch in reloadCollectionData. + DispatchQueue.main.async { + let width = self.view.bounds.width + if let topView = self.topView as? MVMCoreViewProtocol { + topView.updateView(width) } + if let bottomView = self.bottomView as? MVMCoreViewProtocol { + bottomView.updateView(width) + } + if let cells = self.collectionView?.visibleCells { + for cell in cells { + self.update(cell: cell, size: width) + } + } + self.invalidateCollectionLayout() } - invalidateCollectionLayout() } open override func handleNewData() { @@ -168,6 +171,11 @@ import Foundation }) } + /// Called in updateView, updates the cell. + open func update(cell: UICollectionViewCell, size: CGFloat) { + (cell as? MVMCoreViewProtocol)?.updateView(size) + } + open override func registerCells() { super.registerCells() collectionView?.register(ContainerCollectionReusableView.self, forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, withReuseIdentifier: headerID) diff --git a/MVMCoreUI/Utility/MVMCoreUIUtility.m b/MVMCoreUI/Utility/MVMCoreUIUtility.m index b502467d..0841e248 100644 --- a/MVMCoreUI/Utility/MVMCoreUIUtility.m +++ b/MVMCoreUI/Utility/MVMCoreUIUtility.m @@ -169,7 +169,6 @@ bottomInset = scrollview.adjustedContentInset.bottom; } CGFloat remainingSpace = frameHeight - contentSizeHeight - topInset - bottomInset; - NSLog(@"scc SPACCEEE remaining: %f frame: %f, content: %f, insets:(%f,%f)",remainingSpace,frameHeight,contentSizeHeight,topInset,bottomInset); return remainingSpace - 1; } From 4cac288e5ba420b71524db3d47cc17eaa34174d9 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 9 Apr 2020 11:29:05 -0400 Subject: [PATCH 52/62] carousel loop fix --- MVMCoreUI/Atomic/Organisms/Carousel.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Organisms/Carousel.swift b/MVMCoreUI/Atomic/Organisms/Carousel.swift index 05a28a51..18c2978a 100644 --- a/MVMCoreUI/Atomic/Organisms/Carousel.swift +++ b/MVMCoreUI/Atomic/Organisms/Carousel.swift @@ -294,7 +294,7 @@ extension Carousel: UIScrollViewDelegate { return } - let lastPageIndex = numberOfPages + 1 + let lastPageIndex = numberOfPages + 2 let goToIndex = {(index: Int) in self.goTo(index, animated: false) self.collectionView.layoutIfNeeded() From 4eb4cf97417d2ba2cb590afbe3000d74f483ee47 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 9 Apr 2020 11:37:22 -0400 Subject: [PATCH 53/62] temporary fix loop --- MVMCoreUI/Atomic/Organisms/Carousel.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/MVMCoreUI/Atomic/Organisms/Carousel.swift b/MVMCoreUI/Atomic/Organisms/Carousel.swift index 18c2978a..54dc37e7 100644 --- a/MVMCoreUI/Atomic/Organisms/Carousel.swift +++ b/MVMCoreUI/Atomic/Organisms/Carousel.swift @@ -294,7 +294,7 @@ extension Carousel: UIScrollViewDelegate { return } - let lastPageIndex = numberOfPages + 2 + let lastPageIndex = numberOfPages + 1 let goToIndex = {(index: Int) in self.goTo(index, animated: false) self.collectionView.layoutIfNeeded() @@ -332,7 +332,7 @@ extension Carousel: UIScrollViewDelegate { open func scrollViewDidScroll(_ scrollView: UIScrollView) { // Check if the user is dragging the card even further past the next card. - checkForDraggingOutOfBounds(scrollView) + //checkForDraggingOutOfBounds(scrollView) // Let the pager know our progress if needed. pagingView?.scrollViewDidScroll?(collectionView) From 7a1c0dd0fd9f411e063676305abdebf17e81e6ae Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 9 Apr 2020 12:49:20 -0400 Subject: [PATCH 54/62] mild changes --- .../Atomic/Atoms/Buttons/RadioButton.swift | 8 ++++---- .../Buttons/RadioButtonSelectionHelper.swift | 20 +++++++++++++++---- .../Molecules/Items/ListItemModel.swift | 1 + MVMCoreUI/FormUIHelpers/FormValidator.swift | 1 + .../Rules/RuleAnyValueChangedModel.swift | 17 ++++++++++++---- 5 files changed, 35 insertions(+), 12 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/RadioButton.swift b/MVMCoreUI/Atomic/Atoms/Buttons/RadioButton.swift index 98532549..fa17d85c 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/RadioButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/RadioButton.swift @@ -19,8 +19,8 @@ import UIKit } } - public var enabledColor: UIColor = .black - public var disabledColor: UIColor = .mfSilver() + public var enabledColor: UIColor = .mvmBlack + public var disabledColor: UIColor = .mvmCoolGray3 public var delegateObject: MVMCoreUIDelegateObject? public var radioModel: RadioButtonModel? { @@ -108,7 +108,7 @@ import UIKit open override func setupView() { super.setupView() - backgroundColor = .white + backgroundColor = .mvmWhite clipsToBounds = true widthConstraint = widthAnchor.constraint(equalToConstant: 30) widthConstraint?.isActive = true @@ -133,6 +133,6 @@ import UIKit public override func reset() { super.reset() - backgroundColor = .white + backgroundColor = .mvmWhite } } diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/RadioButtonSelectionHelper.swift b/MVMCoreUI/Atomic/Atoms/Buttons/RadioButtonSelectionHelper.swift index 3decadb5..76a58db8 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/RadioButtonSelectionHelper.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/RadioButtonSelectionHelper.swift @@ -7,24 +7,35 @@ // import Foundation -import UIKit + @objcMembers public class RadioButtonSelectionHelper: FormFieldProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public var fieldKey: String? public var groupName: String = FormValidator.defaultGroupName private var selectedRadioButton: RadioButton? private var fieldGroupName: String? public var baseValue: AnyHashable? + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + init(_ fieldKey: String?) { self.fieldKey = fieldKey } + //-------------------------------------------------- + // MARK: - FUnctions + //-------------------------------------------------- + public static func setupForRadioButtonGroup(_ radioButtonModel: RadioButtonModel, _ radioButton: RadioButton, delegateObject: MVMCoreUIDelegateObject?) { guard let groupName = radioButtonModel.fieldKey, - let formValidator = delegateObject?.formHolderDelegate?.formValidator else { - return - } + let formValidator = delegateObject?.formHolderDelegate?.formValidator + else { return } let radioButtonSelectionHelper = formValidator.radioButtonsModelByGroup[groupName] ?? RadioButtonSelectionHelper(radioButtonModel.fieldKey) radioButtonSelectionHelper.fieldGroupName = radioButtonModel.fieldKey @@ -45,6 +56,7 @@ import UIKit // MARK: - FormValidationFormFieldProtocol extension RadioButtonSelectionHelper { + public func formFieldGroupName() -> String? { return selectedRadioButton?.formFieldGroupName() ?? self.fieldGroupName } diff --git a/MVMCoreUI/Atomic/Molecules/Items/ListItemModel.swift b/MVMCoreUI/Atomic/Molecules/Items/ListItemModel.swift index 9365125a..9a00a94d 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/ListItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/ListItemModel.swift @@ -9,6 +9,7 @@ import Foundation + @objcMembers open class ListItemModel: ContainerModel, ListItemModelProtocol { //-------------------------------------------------- // MARK: - Properties diff --git a/MVMCoreUI/FormUIHelpers/FormValidator.swift b/MVMCoreUI/FormUIHelpers/FormValidator.swift index 592132f5..f1d0855e 100644 --- a/MVMCoreUI/FormUIHelpers/FormValidator.swift +++ b/MVMCoreUI/FormUIHelpers/FormValidator.swift @@ -9,6 +9,7 @@ import UIKit import MVMCore + @objcMembers public class FormValidator: NSObject { static var defaultGroupName: String = "default" diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyValueChangedModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyValueChangedModel.swift index 042243db..7cf24cd5 100644 --- a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyValueChangedModel.swift +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleAnyValueChangedModel.swift @@ -8,25 +8,34 @@ import Foundation -public class RuleAnyValueChangedModel: RulesProtocol { +public class RuleAnyValueChangedModel: RulesProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + public static var identifier: String = "anyValueChanged" public var type: String = RuleAnyValueChangedModel.identifier public var fields: [String] + //-------------------------------------------------- + // MARK: - Validation + //-------------------------------------------------- + public func isValid(_ formField: FormFieldProtocol) -> Bool { return formField.baseValue != formField.formFieldValue() } public func isValid(_ fieldMolecules: [String: FormFieldProtocol]) -> Bool { + for formKey in fields { - guard let formField = fieldMolecules[formKey] else { - continue - } + guard let formField = fieldMolecules[formKey] else { continue } + if isValid(formField) { return true } } + return false } } From 020030e669b9bc0caec7576bd830431065934655 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 9 Apr 2020 12:53:37 -0400 Subject: [PATCH 55/62] comments --- MVMCoreUI/FormUIHelpers/FormValidator.swift | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/FormUIHelpers/FormValidator.swift b/MVMCoreUI/FormUIHelpers/FormValidator.swift index f1d0855e..06c8cdf1 100644 --- a/MVMCoreUI/FormUIHelpers/FormValidator.swift +++ b/MVMCoreUI/FormUIHelpers/FormValidator.swift @@ -11,7 +11,10 @@ import MVMCore @objcMembers public class FormValidator: NSObject { - + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + static var defaultGroupName: String = "default" var formRules: [FormGroupRule]? weak var delegate: FormHolderProtocol? @@ -19,10 +22,18 @@ import MVMCore var groupWatchers: [FormGroupWatcherFieldProtocol] = [] var radioButtonsModelByGroup: [String: RadioButtonSelectionHelper] = [:] + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + public init(_ formRules: [FormGroupRule]?) { self.formRules = formRules } + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + /// Adds the form field to the validator. public func add(_ field: FormFieldProtocol) { if let fieldKey = field.fieldKey { From f3224b371ed2a2b0528c59b69b915fa128d299fc Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 9 Apr 2020 12:54:17 -0400 Subject: [PATCH 56/62] comment fix --- .../Items/MoleculeCollectionItemModel.swift | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift index b9ac345b..ed9467fd 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionItemModel.swift @@ -9,22 +9,14 @@ import Foundation /// A model for a collection item that is a container for any molecule. -@objcMembers open class MoleculeCollectionItemModel: CollectionItemModelProtocol, ContainerModelProtocol, MoleculeModelProtocol { +@objcMembers public class MoleculeCollectionItemModel: MoleculeContainerModel, CollectionItemModelProtocol, MoleculeModelProtocol { open class var identifier: String { return "collectionItem" } - open var molecule: MoleculeModelProtocol public var backgroundColor: Color? - - public var horizontalAlignment: UIStackView.Alignment? - public var verticalAlignment: UIStackView.Alignment? - public var useHorizontalMargins: Bool? - public var useVerticalMargins: Bool? - public var topMarginPadding: CGFloat? - public var bottomMarginPadding: CGFloat? - + /// Defaults to set - open func setDefaults() { + public func setDefaults() { if useHorizontalMargins == nil { useHorizontalMargins = true } @@ -41,26 +33,25 @@ import Foundation private enum CodingKeys: String, CodingKey { case moleculeName - case molecule case backgroundColor } - public init(with moleculeModel: MoleculeModelProtocol) { - molecule = moleculeModel + public override init(with moleculeModel: MoleculeModelProtocol) { + super.init(with: moleculeModel) setDefaults() } required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - molecule = try typeContainer.decodeModel(codingKey: .molecule) backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + try super.init(from: decoder) setDefaults() } - open func encode(to encoder: Encoder) throws { + public override func encode(to encoder: Encoder) throws { + try super.encode(to: encoder) var container = encoder.container(keyedBy: CodingKeys.self) try container.encode(moleculeName, forKey: .moleculeName) - try container.encodeModel(molecule, forKey: .molecule) try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) } } From 57a5dbb064b1f8c10eac1baf4ebf8ff87ba6fec0 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 9 Apr 2020 12:58:26 -0400 Subject: [PATCH 57/62] dress feedback --- MVMCoreUI/Atomic/Molecules/Items/CarouselItem.swift | 5 +++++ .../Atomic/Molecules/Items/MoleculeCollectionViewCell.swift | 1 - 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Molecules/Items/CarouselItem.swift b/MVMCoreUI/Atomic/Molecules/Items/CarouselItem.swift index 9cf2a246..3089596a 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/CarouselItem.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/CarouselItem.swift @@ -15,6 +15,11 @@ open class CarouselItem: MoleculeCollectionViewCell { var peakingRightArrow = UIImageView(image: MVMCoreUIUtility.imageNamed("peakingRightArrow")?.withRenderingMode(.alwaysTemplate)) var peakingCover = MVMCoreUICommonViewsUtility.commonView() + open override func addMolecule(_ molecule: MoleculeViewProtocol) { + super.addMolecule(molecule) + contentView.sendSubviewToBack(molecule) + } + open override func setupView() { super.setupView() diff --git a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift index 1f615732..42af1a53 100644 --- a/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift +++ b/MVMCoreUI/Atomic/Molecules/Items/MoleculeCollectionViewCell.swift @@ -17,7 +17,6 @@ open class MoleculeCollectionViewCell: CollectionViewCell { if molecule == nil { if let moleculeView = MoleculeObjectMapping.shared()?.createMolecule(collectionModel.molecule, delegateObject: delegateObject, additionalData: additionalData) { addMolecule(moleculeView) - contentView.sendSubviewToBack(moleculeView) } } else { molecule?.set(with: collectionModel.molecule, delegateObject, additionalData) From 5f000598a69abc800adbddae79f95233b516503f Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 9 Apr 2020 14:19:47 -0400 Subject: [PATCH 58/62] layout fix --- .../ThreeColumn/ListThreeColumnDataUsageDivider.swift | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift index 113be5f1..eab5e8be 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnDataUsageDivider.swift @@ -22,10 +22,10 @@ import Foundation // MARK: - Initializers //------------------------------------------------------ public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - stack = Stack.createStack(with: [(view: leftLabel, model: StackItemModel(percent: 32, horizontalAlignment: .leading)), - (view: centerLabel, model: StackItemModel(percent: 33, horizontalAlignment: .center)), - (view: rightLabel, model: StackItemModel(percent: 35, horizontalAlignment: .center))], - axis: .horizontal) + stack = Stack.createStack(with: [(view: leftLabel, model: StackItemModel(percent: 40, horizontalAlignment: .leading)), + (view: centerLabel, model: StackItemModel(percent: 37, horizontalAlignment: .leading)), + (view: rightLabel, model: StackItemModel(percent: 23, horizontalAlignment: .leading))], + axis: .horizontal) super.init(style: style, reuseIdentifier: reuseIdentifier) } From 0c7b7a2e8b98999c778220bd68d645238b5dc4c1 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 9 Apr 2020 14:22:20 -0400 Subject: [PATCH 59/62] undo change --- .../ThreeColumn/ListThreeColumnSpeedTestDivider.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnSpeedTestDivider.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnSpeedTestDivider.swift index ad9f0740..aa9fbc2d 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnSpeedTestDivider.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/ThreeColumn/ListThreeColumnSpeedTestDivider.swift @@ -22,7 +22,7 @@ import Foundation // MARK: - Initializers //------------------------------------------------------- public override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - stack = Stack.createStack(with: [(view: leftLabel, model: StackItemModel(percent: 37, horizontalAlignment: .leading)), (view: centerLabel, model: StackItemModel(percent: 33, horizontalAlignment: .center)), (view: rightLabel, model: StackItemModel(percent: 30, horizontalAlignment: .leading))], axis: .horizontal) + stack = Stack.createStack(with: [(view: leftLabel, model: StackItemModel(percent: 37, horizontalAlignment: .leading)), (view: centerLabel, model: StackItemModel(percent: 33, horizontalAlignment: .leading)), (view: rightLabel, model: StackItemModel(percent: 30, horizontalAlignment: .leading))], axis: .horizontal) super.init(style: style, reuseIdentifier: reuseIdentifier) } From 97b1ac48ddfbc5a342f99389a39db37adf2d8ab0 Mon Sep 17 00:00:00 2001 From: Kevin G Christiano Date: Thu, 9 Apr 2020 15:46:01 -0400 Subject: [PATCH 60/62] latest --- MVMCoreUI/Atomic/Atoms/Buttons/RadioButton.swift | 14 +++++++++++--- .../Atomic/Atoms/Buttons/RadioButtonModel.swift | 2 +- ...stLeftVariableRadioButtonAndPaymentMethod.swift | 12 ++++++++---- MVMCoreUI/BaseClasses/Control.swift | 1 + 4 files changed, 21 insertions(+), 8 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/RadioButton.swift b/MVMCoreUI/Atomic/Atoms/Buttons/RadioButton.swift index fa17d85c..6eb00959 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/RadioButton.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/RadioButton.swift @@ -40,6 +40,13 @@ import UIKit } }() + public override var isEnabled: Bool { + didSet { + isUserInteractionEnabled = isEnabled + setNeedsDisplay() + } + } + //-------------------------------------------------- // MARK: - Constraints //-------------------------------------------------- @@ -71,7 +78,7 @@ import UIKit } //-------------------------------------------------- - // MARK: - Methods + // MARK: - Validation //-------------------------------------------------- /// The action performed when tapped. @@ -128,11 +135,12 @@ import UIKit self.delegateObject = delegateObject isSelected = model.state + isEnabled = model.enabled RadioButtonSelectionHelper.setupForRadioButtonGroup(model, self, delegateObject: delegateObject) } public override func reset() { - super.reset() - backgroundColor = .mvmWhite + super.reset() + backgroundColor = .mvmWhite } } diff --git a/MVMCoreUI/Atomic/Atoms/Buttons/RadioButtonModel.swift b/MVMCoreUI/Atomic/Atoms/Buttons/RadioButtonModel.swift index 579c0ed9..ee408bb4 100644 --- a/MVMCoreUI/Atomic/Atoms/Buttons/RadioButtonModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Buttons/RadioButtonModel.swift @@ -51,7 +51,7 @@ open class RadioButtonModel: MoleculeModelProtocol, FormFieldProtocol { } //-------------------------------------------------- - // MARK: - Method + // MARK: - Validation //-------------------------------------------------- public func formFieldValue() -> AnyHashable? { diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift index 9517acf0..4597a0b9 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/LeftVariable/ListLeftVariableRadioButtonAndPaymentMethod.swift @@ -8,12 +8,13 @@ import UIKit + @objcMembers open class ListLeftVariableRadioButtonAndPaymentMethod: TableViewCell { //----------------------------------------------------- // MARK: - Outlets //----------------------------------------------------- - let radioButton = RadioButton(frame: .zero) + let radioButton = RadioButton() let leftImage = MFLoadImageView(pinnedEdges: .all) let eyebrowHeadlineBodyLink = EyebrowHeadlineBodyLink() var stack: Stack @@ -57,7 +58,7 @@ import UIKit // MARK: - Molecule //---------------------------------------------------- - open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { + open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) guard let model = model as? ListLeftVariableRadioButtonAndPaymentMethodModel else { return} radioButton.set(with: model.radioButton, delegateObject, additionalData) @@ -69,7 +70,10 @@ import UIKit return 90 } - public override func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable : Any]?) { - radioButton.tapAction() + public override func didSelectCell(at index: IndexPath, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) { + + if radioButton.isEnabled { + radioButton.tapAction() + } } } diff --git a/MVMCoreUI/BaseClasses/Control.swift b/MVMCoreUI/BaseClasses/Control.swift index ebb88977..d8acb6f6 100644 --- a/MVMCoreUI/BaseClasses/Control.swift +++ b/MVMCoreUI/BaseClasses/Control.swift @@ -8,6 +8,7 @@ import UIKit + @objcMembers open class Control: UIControl, MoleculeViewProtocol { //-------------------------------------------------- // MARK: - Properties From 185efa547e98df67bd8fab1c1a07e09d3f7bbc9f Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 10 Apr 2020 09:38:00 -0400 Subject: [PATCH 61/62] Feedback push --- .../BaseClasses/CollectionViewCell.swift | 26 ++++++++++++------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/MVMCoreUI/BaseClasses/CollectionViewCell.swift b/MVMCoreUI/BaseClasses/CollectionViewCell.swift index 58bd06ff..e11b350c 100644 --- a/MVMCoreUI/BaseClasses/CollectionViewCell.swift +++ b/MVMCoreUI/BaseClasses/CollectionViewCell.swift @@ -15,7 +15,9 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo open var molecule: MoleculeViewProtocol? public let containerHelper = ContainerHelper() open var model: CollectionItemModelProtocol? - open var widthConstraint: NSLayoutConstraint? + + /// The width, used for establishing columns + open var width: CGFloat? private var initialSetupPerformed = false @@ -57,7 +59,7 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo open func reset() { molecule?.reset() backgroundColor = .white - widthConstraint?.isActive = false + width = nil } // MARK: - MoleculeViewProtocol @@ -85,12 +87,18 @@ open class CollectionViewCell: UICollectionViewCell, MoleculeViewProtocol, MVMCo // MARK: - CollectionTemplateItemProtocol public func set(width: CGFloat) { - if let widthConstraint = widthConstraint { - widthConstraint.constant = width - widthConstraint.isActive = true - } else { - widthConstraint = contentView.widthAnchor.constraint(equalToConstant: width) - widthConstraint?.isActive = true - } + self.width = width } + + // Column logic, set width. + override open func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes { + let autoLayoutAttributes = super.preferredLayoutAttributesFitting(layoutAttributes) + guard let width = width else { return autoLayoutAttributes } + + let targetSize = CGSize(width: width, height: 0) + let newSize = contentView.systemLayoutSizeFitting(targetSize, withHorizontalFittingPriority: UILayoutPriority.required, verticalFittingPriority: UILayoutPriority.defaultLow) + let newFrame = CGRect(origin: autoLayoutAttributes.frame.origin, size: newSize) + autoLayoutAttributes.frame = newFrame + return autoLayoutAttributes + } } From 8da03356e416acad252fa685ced0e920ddfcff8c Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 10 Apr 2020 11:15:55 -0400 Subject: [PATCH 62/62] Fixing reuse and sizing issues. --- MVMCoreUI/Atomic/Organisms/Carousel.swift | 70 +++++++++++++------ .../Atomic/Organisms/CarouselModel.swift | 22 +++--- .../ThreeLayerTableViewController.swift | 2 +- .../BaseControllers/ViewController.swift | 3 +- 4 files changed, 63 insertions(+), 34 deletions(-) diff --git a/MVMCoreUI/Atomic/Organisms/Carousel.swift b/MVMCoreUI/Atomic/Organisms/Carousel.swift index 54dc37e7..1ed2ecd2 100644 --- a/MVMCoreUI/Atomic/Organisms/Carousel.swift +++ b/MVMCoreUI/Atomic/Organisms/Carousel.swift @@ -54,6 +54,32 @@ open class Carousel: View { private var size: CGFloat? + // Updates the model and index. + public func updateModelIndex() { + (model as? CarouselModel)?.index = pageIndex + } + + open override func layoutSubviews() { + super.layoutSubviews() + // Accounts for any collection size changes + DispatchQueue.main.async { + self.layoutCollection() + } + } + + /// Invalidates the layout and ensures we are paged to the correct cell. + open func layoutCollection() { + collectionView.collectionViewLayout.invalidateLayout() + showPeaking(false) + + // Go to current cell. layoutIfNeeded is needed otherwise cellForItem returns nil for peaking logic. The dispatch is a sad way to ensure the collection view is ready to be scrolled. + DispatchQueue.main.async { + self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: false) + self.collectionView.layoutIfNeeded() + self.showPeaking(true) + } + } + // MARK: - MVMCoreViewProtocol open override func setupView() { super.setupView() @@ -73,15 +99,12 @@ open class Carousel: View { open override func updateView(_ size: CGFloat) { super.updateView(size) self.size = size - collectionView.collectionViewLayout.invalidateLayout() - showPeaking(false) - - // Go to current cell. layoutIfNeeded is needed otherwise cellForItem returns nil for peaking logic. The dispatch is a sad way to ensure the collection view is ready to be scrolled. - DispatchQueue.main.async { - self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: false) - self.collectionView.layoutIfNeeded() - self.showPeaking(true) + + // Update cells and re-layout. + for cell in collectionView.visibleCells { + (cell as? MVMCoreViewProtocol)?.updateView(size) } + layoutCollection() } // MARK: - MoleculeViewProtocol @@ -108,6 +131,9 @@ open class Carousel: View { } setupPagingMolecule(carouselModel.pagingMolecule, delegateObject: delegateObject) + + pageIndex = carouselModel.index + pagingView?.setPage(carouselModel.index) collectionView.reloadData() } @@ -197,6 +223,7 @@ open class Carousel: View { } let currentPage = pager.currentPage() localSelf.pageIndex = currentPage + localSelf.updateModelIndex() localSelf.goTo(localSelf.currentIndex, animated: !UIAccessibility.isVoiceOverRunning) }) } @@ -246,7 +273,7 @@ open class Carousel: View { extension Carousel: UICollectionViewDelegateFlowLayout { open func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { - let itemWidth = (size ?? collectionView.bounds.width) * CGFloat(itemWidthPercent) + let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent) return CGSize(width: itemWidth, height: collectionView.bounds.height) } @@ -280,19 +307,18 @@ extension Carousel: UIScrollViewDelegate { func goTo(_ index: Int, animated: Bool) { showPeaking(false) - setAccessiblity(collectionView.cellForItem(at: IndexPath(row: self.currentIndex, section: 0)), index: index) - self.currentIndex = index - self.collectionView.scrollToItem(at: IndexPath(row: self.currentIndex, section: 0), at: self.itemAlignment, animated: animated) - if let cell = collectionView.cellForItem(at: IndexPath(row: self.currentIndex, section: 0)) { - setAccessiblity(collectionView.cellForItem(at: IndexPath(row: self.currentIndex, section: 0)), index: index) + setAccessiblity(collectionView.cellForItem(at: IndexPath(row: currentIndex, section: 0)), index: index) + currentIndex = index + updateModelIndex() + collectionView.scrollToItem(at: IndexPath(row: currentIndex, section: 0), at: itemAlignment, animated: animated) + if let cell = collectionView.cellForItem(at: IndexPath(row: currentIndex, section: 0)) { + setAccessiblity(collectionView.cellForItem(at: IndexPath(row: currentIndex, section: 0)), index: index) UIAccessibility.post(notification: .layoutChanged, argument: cell) } } func handleUserOnBufferCell() { - guard loop else { - return - } + guard loop else { return } let lastPageIndex = numberOfPages + 1 let goToIndex = {(index: Int) in @@ -320,9 +346,11 @@ extension Carousel: UIScrollViewDelegate { let index = scrollView.contentOffset.x / (itemWidth + separatorWidth) let lastCellIndex = collectionView(collectionView, numberOfItemsInSection: 0) - 1 if index < 1 { - self.currentIndex = 0 + currentIndex = 0 + updateModelIndex() } else if index > CGFloat(lastCellIndex - 1) { - self.currentIndex = lastCellIndex + currentIndex = lastCellIndex + updateModelIndex() } } @@ -348,9 +376,7 @@ extension Carousel: UIScrollViewDelegate { targetContentOffset.pointee = scrollView.contentOffset // This is for setting up smooth custom paging. (Since UICollectionView only handles paging based on collection view size and not cell size). - guard let separatorWidth = (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing else { - return - } + guard let separatorWidth = (collectionView.collectionViewLayout as? UICollectionViewFlowLayout)?.minimumLineSpacing else { return } // We switch cards if we pass the velocity threshold or position threshold (currently 50%). let itemWidth = collectionView.bounds.width * CGFloat(itemWidthPercent) diff --git a/MVMCoreUI/Atomic/Organisms/CarouselModel.swift b/MVMCoreUI/Atomic/Organisms/CarouselModel.swift index 9fb4fe3b..c5f73a01 100644 --- a/MVMCoreUI/Atomic/Organisms/CarouselModel.swift +++ b/MVMCoreUI/Atomic/Organisms/CarouselModel.swift @@ -12,7 +12,7 @@ import UIKit public static var identifier: String = "carousel" public var backgroundColor: Color? public var molecules: [CarouselItemModel] - + public var index: Int = 0 public var spacing: Float? public var border: Bool? public var loop: Bool? @@ -29,6 +29,7 @@ import UIKit case moleculeName case backgroundColor case molecules + case index case spacing case border case loop @@ -40,15 +41,16 @@ import UIKit required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) - self.molecules = try typeContainer.decode([CarouselItemModel].self, forKey: .molecules) - self.backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) - self.spacing = try typeContainer.decodeIfPresent(Float.self, forKey: .spacing) - self.border = try typeContainer.decodeIfPresent(Bool.self, forKey: .border) - self.loop = try typeContainer.decodeIfPresent(Bool.self, forKey: .loop) - self.height = try typeContainer.decodeIfPresent(Float.self, forKey: .height) - self.itemWidthPercent = try typeContainer.decodeIfPresent(Float.self, forKey: .itemWidthPercent) - self.itemAlignment = try typeContainer.decodeIfPresent(UICollectionView.ScrollPosition.self, forKey: .itemAlignment) - self.pagingMolecule = try typeContainer.decodeModelIfPresent(codingKey: .pagingMolecule) + molecules = try typeContainer.decode([CarouselItemModel].self, forKey: .molecules) + index = try typeContainer.decodeIfPresent(Int.self, forKey: .index) ?? 0 + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + spacing = try typeContainer.decodeIfPresent(Float.self, forKey: .spacing) + border = try typeContainer.decodeIfPresent(Bool.self, forKey: .border) + loop = try typeContainer.decodeIfPresent(Bool.self, forKey: .loop) + height = try typeContainer.decodeIfPresent(Float.self, forKey: .height) + itemWidthPercent = try typeContainer.decodeIfPresent(Float.self, forKey: .itemWidthPercent) + itemAlignment = try typeContainer.decodeIfPresent(UICollectionView.ScrollPosition.self, forKey: .itemAlignment) + pagingMolecule = try typeContainer.decodeModelIfPresent(codingKey: .pagingMolecule) } public func encode(to encoder: Encoder) throws { diff --git a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift index c0f267fc..000f2e7f 100644 --- a/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift +++ b/MVMCoreUI/BaseControllers/ThreeLayerTableViewController.swift @@ -33,7 +33,7 @@ open class ThreeLayerTableViewController: ProgrammaticTableViewController { bottomView.updateView(width) showFooter(width) } - self.tableView?.reloadData() + tableView?.reloadData() } open override func handleNewData() { diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index d19ebdaf..eb4be908 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -278,7 +278,8 @@ import UIKit return } - if needsUpdateUI || screenSizeChanged() { + // First update should be explicit (hence the zero check) + if needsUpdateUI || (previousScreenSize != .zero && screenSizeChanged()) { updateViews() needsUpdateUI = false }