From 04bbf58e6ae936e095dccda4203b2d38f09216d3 Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Tue, 8 Sep 2020 13:13:43 +0530 Subject: [PATCH 01/16] Heart atom initial commit. --- MVMCoreUI.xcodeproj/project.pbxproj | 8 ++ MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift | 84 +++++++++++++++++++ .../Atomic/Atoms/Selectors/HeartModel.swift | 61 ++++++++++++++ MVMCoreUI/Atomic/MoleculeObjectMapping.swift | 2 +- 4 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift create mode 100644 MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index b61c3aa1..133e099b 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -236,6 +236,8 @@ AA997252247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift in Sources */ = {isa = PBXBuildFile; fileRef = AA997251247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift */; }; AAA74A172410C04600080241 /* HeadersH2NoButtonsBodyText.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */; }; AAA74A192410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */; }; + AAA7CD69250641F90045B959 /* HeartModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA7CD68250641F90045B959 /* HeartModel.swift */; }; + AAA7CD6B250642080045B959 /* Heart.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA7CD6A250642080045B959 /* Heart.swift */; }; AAA905DF24D1758700D1EFAB /* ListThreeColumnBillHistoryModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA905DE24D1758700D1EFAB /* ListThreeColumnBillHistoryModel.swift */; }; AAA905E124D1759A00D1EFAB /* ListThreeColumnBillHistory.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAA905E024D1759A00D1EFAB /* ListThreeColumnBillHistory.swift */; }; AAB7EDEF246ADA1600E54929 /* ListProgressBarThinModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = AAB7EDEE246ADA1600E54929 /* ListProgressBarThinModel.swift */; }; @@ -717,6 +719,8 @@ AA997251247530B100FC7472 /* ListLeftVariableIconAllTextLinks.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListLeftVariableIconAllTextLinks.swift; sourceTree = ""; }; AAA74A162410C04600080241 /* HeadersH2NoButtonsBodyText.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyText.swift; sourceTree = ""; }; AAA74A182410C05800080241 /* HeadersH2NoButtonsBodyTextModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeadersH2NoButtonsBodyTextModel.swift; sourceTree = ""; }; + AAA7CD68250641F90045B959 /* HeartModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HeartModel.swift; sourceTree = ""; }; + AAA7CD6A250642080045B959 /* Heart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Heart.swift; sourceTree = ""; }; AAA905DE24D1758700D1EFAB /* ListThreeColumnBillHistoryModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnBillHistoryModel.swift; sourceTree = ""; }; AAA905E024D1759A00D1EFAB /* ListThreeColumnBillHistory.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListThreeColumnBillHistory.swift; sourceTree = ""; }; AAB7EDEE246ADA1600E54929 /* ListProgressBarThinModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListProgressBarThinModel.swift; sourceTree = ""; }; @@ -1564,6 +1568,8 @@ D2092348244A51D40044AD09 /* RadioSwatchModel.swift */, AAB9C109243496DD00151545 /* RadioSwatch.swift */, AA85236B244435A20059CC1E /* RadioSwatchCollectionViewCell.swift */, + AAA7CD68250641F90045B959 /* HeartModel.swift */, + AAA7CD6A250642080045B959 /* Heart.swift */, ); path = Selectors; sourceTree = ""; @@ -2187,6 +2193,7 @@ 943784F5236B77BB006A1E82 /* Wheel.swift in Sources */, 31BE15CC23D8924D00452370 /* CheckboxModel.swift in Sources */, 8D3BA9BF2433789900D341BA /* ListThreeColumnInternationalDataDivider.swift in Sources */, + AAA7CD6B250642080045B959 /* Heart.swift in Sources */, 94C661DA23CCF4FB00D9FE5B /* UIColor+Extension.swift in Sources */, D28A838123CCB0D800DFE4FC /* AccordionListItemModel.swift in Sources */, D2509ED62472EE2F001BFB9D /* NavigationImageButtonModel.swift in Sources */, @@ -2205,6 +2212,7 @@ BBC0C4FF24811DCA0087C44F /* TagModel.swift in Sources */, 0A7BAD74232A8DC700FB8E22 /* HeadlineBodyButton.swift in Sources */, 3265B30424BCA749000D154B /* HeadersH1NoButtonsBodyText.swift in Sources */, + AAA7CD69250641F90045B959 /* HeartModel.swift in Sources */, D2FB151D23A40F1500C20E10 /* MoleculeStackItem.swift in Sources */, D28BA7452481652D00B75CB8 /* TabBarProtocol.swift in Sources */, AA11A41F23F15D3100D7962F /* ListRightVariablePayments.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift new file mode 100644 index 00000000..33625303 --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift @@ -0,0 +1,84 @@ +// +// Heart.swift +// MVMCoreUI +// +// Created by Lekshmi S on 07/09/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import UIKit + +open class Heart: Control { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + private var heartLayer: CAShapeLayer? + @objc public override var isSelected: Bool { + didSet { + heartModel?.isActive = isSelected + } + } + public var delegateObject: MVMCoreUIDelegateObject? + public var heartModel: HeartModel? { + return model as? HeartModel + } + + //-------------------------------------------------- + // MARK: - Lifecycle + //-------------------------------------------------- + open override func draw(_ layer: CALayer, in ctx: CGContext) { + //Draw the heart + heartLayer?.removeFromSuperlayer() + let heart = drawHeart() + layer.addSublayer(heart) + heartLayer = heart + } + + func drawHeart() -> CAShapeLayer { + let heart = CAShapeLayer() + let rect = CGRect(x: 0, y: 0, width: 22, height: 22) + let leftArc = rect.width * 0.4 + let rightArc = rect.height * 0.3 + let arcRadius = sqrt(leftArc*leftArc + rightArc*rightArc)/2 + let heartPath = UIBezierPath() + //Left Hand Curve + heartPath.addArc(withCenter: CGPoint(x: rect.width * 0.3, y: rect.height * 0.35), radius: arcRadius, startAngle: 135.degreesToRadians, endAngle: 315.degreesToRadians, clockwise: true) + //Top Centre Dip + heartPath.addLine(to: CGPoint(x: rect.width/2, y: rect.height * 0.2)) + //Right Hand Curve + heartPath.addArc(withCenter: CGPoint(x: rect.width * 0.7, y: rect.height * 0.35), radius: arcRadius, startAngle: 225.degreesToRadians, endAngle: 45.degreesToRadians, clockwise: true) + //Right Bottom Line + heartPath.addLine(to: CGPoint(x: rect.width * 0.5, y: rect.height * 0.95)) + //Left Bottom Line + heartPath.close() + heart.path = heartPath.cgPath + heart.fillColor = isSelected ? heartModel?.activeColor.cgColor : heartModel?.inActiveColor.cgColor + heart.opacity = 1.0 + heart.lineWidth = 1 + heart.strokeColor = isSelected ? UIColor.clear.cgColor : UIColor.mvmBlack.cgColor + return heart + } + + //-------------------------------------------------- + // MARK: - MVMViewProtocol + //-------------------------------------------------- + open override func setupView() { + super.setupView() + } + + open override func updateView(_ size: CGFloat) { + super.updateView(size) + layer.setNeedsDisplay() + } + + public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + super.set(with: model, delegateObject, additionalData) + self.delegateObject = delegateObject + guard let model = model as? HeartModel else { return } + isSelected = model.isActive + } +} + +extension Int { + var degreesToRadians: CGFloat { return CGFloat(self) * .pi / 180 } +} diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift new file mode 100644 index 00000000..469dc4d9 --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift @@ -0,0 +1,61 @@ +// +// HeartModel.swift +// MVMCoreUI +// +// Created by Lekshmi S on 07/09/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +open class HeartModel: MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public static var identifier: String = "heart" + public var backgroundColor: Color? + public var isActive: Bool = false + public var activeColor: Color = Color(uiColor: .mvmRed) + public var inActiveColor: Color = Color(uiColor: .clear) + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case moleculeName + case backgroundColor + case isActive + case activeColor + case inActiveColor + } + + //-------------------------------------------------- + // MARK: - Codec + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + + if let isActive = try typeContainer.decodeIfPresent(Bool.self, forKey: .isActive) { + self.isActive = isActive + } + backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) + if let activeColor = try typeContainer.decodeIfPresent(Color.self, forKey: .activeColor) { + self.activeColor = activeColor + } + if let inActiveColor = try typeContainer.decodeIfPresent(Color.self, forKey: .inActiveColor) { + self.inActiveColor = inActiveColor + } + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) + try container.encode(moleculeName, forKey: .moleculeName) + try container.encodeIfPresent(isActive, forKey: .isActive) + try container.encodeIfPresent(activeColor, forKey: .activeColor) + try container.encodeIfPresent(inActiveColor, forKey: .inActiveColor) + } +} diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index a08347c7..4016ec8a 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -87,7 +87,7 @@ import Foundation MoleculeObjectMapping.shared()?.register(viewClass: RadioSwatches.self, viewModelClass: RadioSwatchesModel.self) MoleculeObjectMapping.shared()?.register(viewClass: Tags.self, viewModelClass: TagsModel.self) MoleculeObjectMapping.shared()?.register(viewClass: Tag.self, viewModelClass: TagModel.self) - + MoleculeObjectMapping.shared()?.register(viewClass: Heart.self, viewModelClass: HeartModel.self) // MARK:- Other Atoms From 06df235fb293b059193b62c63793e0e1c611710f Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Tue, 8 Sep 2020 20:25:46 +0530 Subject: [PATCH 02/16] Code fixes and added accessibility. --- MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift | 48 +++++++++++++++---- .../Strings/en.lproj/Localizable.strings | 5 ++ .../Strings/es-MX.lproj/Localizable.strings | 4 ++ .../Strings/es.lproj/Localizable.strings | 6 +++ 4 files changed, 53 insertions(+), 10 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift index 33625303..46435614 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift @@ -8,7 +8,8 @@ import UIKit -open class Heart: Control { +@objcMembers open class Heart: Control { + //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -16,6 +17,7 @@ open class Heart: Control { @objc public override var isSelected: Bool { didSet { heartModel?.isActive = isSelected + updateAccessibilityLabel() } } public var delegateObject: MVMCoreUIDelegateObject? @@ -24,9 +26,15 @@ open class Heart: Control { } //-------------------------------------------------- - // MARK: - Lifecycle + // MARK: - Constraints //-------------------------------------------------- - open override func draw(_ layer: CALayer, in ctx: CGContext) { + public var widthConstraint: NSLayoutConstraint? + public var heightConstraint: NSLayoutConstraint? + + //------------------------------------------------------ + // MARK: - State Handling + //------------------------------------------------------ + open override func draw(_ rect: CGRect) { //Draw the heart heartLayer?.removeFromSuperlayer() let heart = drawHeart() @@ -36,7 +44,7 @@ open class Heart: Control { func drawHeart() -> CAShapeLayer { let heart = CAShapeLayer() - let rect = CGRect(x: 0, y: 0, width: 22, height: 22) + let rect = CGRect(x: 0, y: 0, width: 10, height: 10) let leftArc = rect.width * 0.4 let rightArc = rect.height * 0.3 let arcRadius = sqrt(leftArc*leftArc + rightArc*rightArc)/2 @@ -60,15 +68,19 @@ open class Heart: Control { } //-------------------------------------------------- - // MARK: - MVMViewProtocol + // MARK: - Lifecycle //-------------------------------------------------- open override func setupView() { super.setupView() - } - - open override func updateView(_ size: CGFloat) { - super.updateView(size) - layer.setNeedsDisplay() + addTarget(self, action: #selector(tapAction), for: .touchUpInside) + widthConstraint = widthAnchor.constraint(equalToConstant: 10) + widthConstraint?.isActive = true + heightConstraint = heightAnchor.constraint(equalTo: widthAnchor, multiplier: 1) + heightConstraint?.isActive = true + isAccessibilityElement = true + accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "heart_action_hint") + accessibilityTraits = .button + updateAccessibilityLabel() } public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { @@ -77,6 +89,22 @@ open class Heart: Control { guard let model = model as? HeartModel else { return } isSelected = model.isActive } + + //-------------------------------------------------- + // MARK: - Methods + //-------------------------------------------------- + /// Adjust accessibility label based on selection of Heart. + func updateAccessibilityLabel() { + if let message = MVMCoreUIUtility.hardcodedString(withKey: "heart"), + let selectedState = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_selected_state" : "heart_not_selected_state") { + accessibilityLabel = message + selectedState + } + } + + func tapAction() { + isSelected = !isSelected + setNeedsDisplay() + } } extension Int { diff --git a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings index c280b737..2f8b642b 100644 --- a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings @@ -67,6 +67,11 @@ "AccOff" = "off"; "AccToggleHint" = "double tap to toggle"; +// MARK: Heart +"heart" = "Heart"; +"heart_action_hint" = "Double tap to select"; +"heart_selected_state" = "Selected"; +"heart_not_selected_state" = "Not Selected"; // MARK: Carousel "MVMCoreUIPageControl_currentpage_index" = "page %@ of %d"; diff --git a/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings index f21df078..4917f6ee 100644 --- a/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings @@ -49,6 +49,10 @@ "AccOn" = "encendido"; "AccOff" = "apagado"; "AccToggleHint" = "toca dos veces para alternar"; +// Heart +"heart_action_hint" = "Toca dos veces para seleccionar."; +"heart_selected_state" = "Seleccionado"; +"heart_not_selected_state" = "No Seleccionado"; // Carousel "MVMCoreUIPageControl_currentpage_index" = "página %@ de %d"; "MVMCoreUIPageControlslides_currentpage_index" = "diapositiva %@ of %d"; diff --git a/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings index 47d124a9..5bf02ca0 100644 --- a/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings @@ -51,6 +51,12 @@ "AccOn" = "encendido"; "AccOff" = "apagado"; "AccToggleHint" = "toca dos veces para alternar"; + +// Heart +"heart_action_hint" = "Toca dos veces para seleccionar."; +"heart_selected_state" = "Seleccionado"; +"heart_not_selected_state" = "No Seleccionado"; + // Carousel "MVMCoreUIPageControl_currentpage_index" = "página %@ de %d"; "MVMCoreUIPageControlslides_currentpage_index" = "diapositiva %@ of %d"; From 884f2ad69fac5f33ec1dd9a5f8cb41b39e3dd0d9 Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Mon, 14 Sep 2020 17:38:20 +0530 Subject: [PATCH 03/16] Added action key. --- MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift | 4 ++-- MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift | 8 +++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift index 46435614..5270fa62 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift @@ -44,7 +44,7 @@ import UIKit func drawHeart() -> CAShapeLayer { let heart = CAShapeLayer() - let rect = CGRect(x: 0, y: 0, width: 10, height: 10) + let rect = self.bounds let leftArc = rect.width * 0.4 let rightArc = rect.height * 0.3 let arcRadius = sqrt(leftArc*leftArc + rightArc*rightArc)/2 @@ -73,7 +73,7 @@ import UIKit open override func setupView() { super.setupView() addTarget(self, action: #selector(tapAction), for: .touchUpInside) - widthConstraint = widthAnchor.constraint(equalToConstant: 10) + widthConstraint = widthAnchor.constraint(equalToConstant: 22) widthConstraint?.isActive = true heightConstraint = heightAnchor.constraint(equalTo: widthAnchor, multiplier: 1) heightConstraint?.isActive = true diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift index 469dc4d9..3fe696f8 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift @@ -9,32 +9,32 @@ import Foundation open class HeartModel: MoleculeModelProtocol { + //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - public static var identifier: String = "heart" public var backgroundColor: Color? public var isActive: Bool = false public var activeColor: Color = Color(uiColor: .mvmRed) public var inActiveColor: Color = Color(uiColor: .clear) + public var action: ActionModelProtocol? //-------------------------------------------------- // MARK: - Keys //-------------------------------------------------- - private enum CodingKeys: String, CodingKey { case moleculeName case backgroundColor case isActive case activeColor case inActiveColor + case action } //-------------------------------------------------- // MARK: - Codec //-------------------------------------------------- - required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) @@ -48,6 +48,7 @@ open class HeartModel: MoleculeModelProtocol { if let inActiveColor = try typeContainer.decodeIfPresent(Color.self, forKey: .inActiveColor) { self.inActiveColor = inActiveColor } + action = try typeContainer.decodeModelIfPresent(codingKey: .action) } public func encode(to encoder: Encoder) throws { @@ -57,5 +58,6 @@ open class HeartModel: MoleculeModelProtocol { try container.encodeIfPresent(isActive, forKey: .isActive) try container.encodeIfPresent(activeColor, forKey: .activeColor) try container.encodeIfPresent(inActiveColor, forKey: .inActiveColor) + try container.encodeModelIfPresent(action, forKey: .action) } } From 7c4c9ea43a6e09f4b56a3b53c6df8711af974681 Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Tue, 29 Sep 2020 17:39:16 +0530 Subject: [PATCH 04/16] Code changes based on review comments and added default action noop. --- MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift | 7 ++++++- MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift | 12 +++++++----- .../Strings/en.lproj/Localizable.strings | 2 +- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift index 5270fa62..0cdc1f6d 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift @@ -8,7 +8,7 @@ import UIKit -@objcMembers open class Heart: Control { +@objcMembers open class Heart: Control, MFButtonProtocol { //-------------------------------------------------- // MARK: - Properties @@ -24,6 +24,7 @@ import UIKit public var heartModel: HeartModel? { return model as? HeartModel } + var additionalData: [AnyHashable: Any]? //-------------------------------------------------- // MARK: - Constraints @@ -86,6 +87,7 @@ import UIKit public override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { super.set(with: model, delegateObject, additionalData) self.delegateObject = delegateObject + self.additionalData = additionalData guard let model = model as? HeartModel else { return } isSelected = model.isActive } @@ -103,6 +105,9 @@ import UIKit func tapAction() { isSelected = !isSelected + if let heartModel = heartModel { + Button.performButtonAction(with: heartModel.action, button: self, delegateObject: delegateObject, additionalData: additionalData, sourceModel: heartModel) + } setNeedsDisplay() } } diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift index 3fe696f8..b3d168ef 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift @@ -18,7 +18,7 @@ open class HeartModel: MoleculeModelProtocol { public var isActive: Bool = false public var activeColor: Color = Color(uiColor: .mvmRed) public var inActiveColor: Color = Color(uiColor: .clear) - public var action: ActionModelProtocol? + public var action: ActionModelProtocol = ActionNoopModel() //-------------------------------------------------- // MARK: - Keys @@ -48,16 +48,18 @@ open class HeartModel: MoleculeModelProtocol { if let inActiveColor = try typeContainer.decodeIfPresent(Color.self, forKey: .inActiveColor) { self.inActiveColor = inActiveColor } - action = try typeContainer.decodeModelIfPresent(codingKey: .action) + if let action: ActionModelProtocol = try typeContainer.decodeModelIfPresent(codingKey: .action) { + self.action = action + } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor) try container.encode(moleculeName, forKey: .moleculeName) - try container.encodeIfPresent(isActive, forKey: .isActive) - try container.encodeIfPresent(activeColor, forKey: .activeColor) - try container.encodeIfPresent(inActiveColor, forKey: .inActiveColor) + try container.encode(isActive, forKey: .isActive) + try container.encode(activeColor, forKey: .activeColor) + try container.encode(inActiveColor, forKey: .inActiveColor) try container.encodeModelIfPresent(action, forKey: .action) } } diff --git a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings index 2f8b642b..8cf3e21e 100644 --- a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings @@ -68,7 +68,7 @@ "AccToggleHint" = "double tap to toggle"; // MARK: Heart -"heart" = "Heart"; +"heart" = "Favorite"; "heart_action_hint" = "Double tap to select"; "heart_selected_state" = "Selected"; "heart_not_selected_state" = "Not Selected"; From 223757ab0fae7b0dadf2418c919195a485a483ae Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Wed, 30 Sep 2020 12:16:04 +0530 Subject: [PATCH 05/16] Changed accessibility text for heart. --- MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift | 2 +- .../SupportingFiles/Strings/en.lproj/Localizable.strings | 6 +++--- .../SupportingFiles/Strings/es-MX.lproj/Localizable.strings | 6 +++--- .../SupportingFiles/Strings/es.lproj/Localizable.strings | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift index 0cdc1f6d..eeda08af 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift @@ -45,7 +45,7 @@ import UIKit func drawHeart() -> CAShapeLayer { let heart = CAShapeLayer() - let rect = self.bounds + let rect = bounds let leftArc = rect.width * 0.4 let rightArc = rect.height * 0.3 let arcRadius = sqrt(leftArc*leftArc + rightArc*rightArc)/2 diff --git a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings index 8cf3e21e..db90b9b7 100644 --- a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings @@ -69,9 +69,9 @@ // MARK: Heart "heart" = "Favorite"; -"heart_action_hint" = "Double tap to select"; -"heart_selected_state" = "Selected"; -"heart_not_selected_state" = "Not Selected"; +"heart_action_hint" = "Double tap to favorite"; +"heart_selected_state" = "Favorited"; +"heart_not_selected_state" = "Unfavorited"; // MARK: Carousel "MVMCoreUIPageControl_currentpage_index" = "page %@ of %d"; diff --git a/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings index 4917f6ee..d6bfb89c 100644 --- a/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings @@ -50,9 +50,9 @@ "AccOff" = "apagado"; "AccToggleHint" = "toca dos veces para alternar"; // Heart -"heart_action_hint" = "Toca dos veces para seleccionar."; -"heart_selected_state" = "Seleccionado"; -"heart_not_selected_state" = "No Seleccionado"; +"heart_action_hint" = "Toca dos veces en favorito"; +"heart_selected_state" = "Favoritos"; +"heart_not_selected_state" = "No favorito"; // Carousel "MVMCoreUIPageControl_currentpage_index" = "página %@ de %d"; "MVMCoreUIPageControlslides_currentpage_index" = "diapositiva %@ of %d"; diff --git a/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings index 5bf02ca0..b06c972b 100644 --- a/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings @@ -53,9 +53,9 @@ "AccToggleHint" = "toca dos veces para alternar"; // Heart -"heart_action_hint" = "Toca dos veces para seleccionar."; -"heart_selected_state" = "Seleccionado"; -"heart_not_selected_state" = "No Seleccionado"; +"heart_action_hint" = "Toca dos veces en favorito"; +"heart_selected_state" = "Favoritos"; +"heart_not_selected_state" = "No favorito"; // Carousel "MVMCoreUIPageControl_currentpage_index" = "página %@ de %d"; From 1bf75c99292bd8472b06ac445657f1b48f7a5c5a Mon Sep 17 00:00:00 2001 From: Lekshmi S Date: Tue, 6 Oct 2020 16:13:02 +0530 Subject: [PATCH 06/16] Accessibility label changes for heart. --- MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift | 7 ++----- MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift | 2 +- .../SupportingFiles/Strings/en.lproj/Localizable.strings | 4 ++-- .../Strings/es-MX.lproj/Localizable.strings | 3 ++- .../SupportingFiles/Strings/es.lproj/Localizable.strings | 3 ++- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift index eeda08af..796bf617 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/Heart.swift @@ -79,7 +79,6 @@ import UIKit heightConstraint = heightAnchor.constraint(equalTo: widthAnchor, multiplier: 1) heightConstraint?.isActive = true isAccessibilityElement = true - accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "heart_action_hint") accessibilityTraits = .button updateAccessibilityLabel() } @@ -97,10 +96,8 @@ import UIKit //-------------------------------------------------- /// Adjust accessibility label based on selection of Heart. func updateAccessibilityLabel() { - if let message = MVMCoreUIUtility.hardcodedString(withKey: "heart"), - let selectedState = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_selected_state" : "heart_not_selected_state") { - accessibilityLabel = message + selectedState - } + accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_unfavorite_action_hint" : "heart_favorite_action_hint") + accessibilityLabel = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "heart_selected_state" : "heart_not_selected_state") } func tapAction() { diff --git a/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift b/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift index b3d168ef..8001ddd5 100644 --- a/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Selectors/HeartModel.swift @@ -60,6 +60,6 @@ open class HeartModel: MoleculeModelProtocol { try container.encode(isActive, forKey: .isActive) try container.encode(activeColor, forKey: .activeColor) try container.encode(inActiveColor, forKey: .inActiveColor) - try container.encodeModelIfPresent(action, forKey: .action) + try container.encodeModel(action, forKey: .action) } } diff --git a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings index db90b9b7..bbeadbdb 100644 --- a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings @@ -68,8 +68,8 @@ "AccToggleHint" = "double tap to toggle"; // MARK: Heart -"heart" = "Favorite"; -"heart_action_hint" = "Double tap to favorite"; +"heart_favorite_action_hint" = "Double tap to favorite"; +"heart_unfavorite_action_hint" = "Double tap to unfavorite"; "heart_selected_state" = "Favorited"; "heart_not_selected_state" = "Unfavorited"; diff --git a/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings index d6bfb89c..0a37e1a5 100644 --- a/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/es-MX.lproj/Localizable.strings @@ -50,7 +50,8 @@ "AccOff" = "apagado"; "AccToggleHint" = "toca dos veces para alternar"; // Heart -"heart_action_hint" = "Toca dos veces en favorito"; +"heart_favorite_action_hint" = "Toca dos veces en favorito"; +"heart_unfavorite_action_hint" = "Toca dos veces para dejar de marcar como favorito"; "heart_selected_state" = "Favoritos"; "heart_not_selected_state" = "No favorito"; // Carousel diff --git a/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings index b06c972b..a64c3915 100644 --- a/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/es.lproj/Localizable.strings @@ -53,7 +53,8 @@ "AccToggleHint" = "toca dos veces para alternar"; // Heart -"heart_action_hint" = "Toca dos veces en favorito"; +"heart_favorite_action_hint" = "Toca dos veces en favorito"; +"heart_unfavorite_action_hint" = "Toca dos veces para dejar de marcar como favorito"; "heart_selected_state" = "Favoritos"; "heart_not_selected_state" = "No favorito"; From fc9272d0b782056d250c4d198a81179ac0257bfe Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 7 Oct 2020 15:36:02 -0400 Subject: [PATCH 07/16] MFViewController Model Dynamic Root Non Root navigation item --- MVMCoreUI.xcodeproj/project.pbxproj | 4 +++ MVMCoreUI/Atomic/MoleculeObjectMapping.swift | 4 +-- .../NavigationBar/NavigationItemModel.swift | 28 +++++++-------- MVMCoreUI/Atomic/Protocols/PageProtocol.swift | 28 +++++++++++++++ .../Atomic/Protocols/TemplateProtocol.swift | 2 +- .../BaseControllers/ViewController.swift | 35 +++++++++++-------- .../Containers/NavigationController.swift | 7 ++-- .../MVMCoreUIDetailViewProtocol.h | 6 ++++ ...MCoreUISplitViewController+Extension.swift | 3 +- 9 files changed, 81 insertions(+), 36 deletions(-) create mode 100644 MVMCoreUI/Atomic/Protocols/PageProtocol.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 72326c6c..0b0e49c6 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -303,6 +303,7 @@ D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */; }; D20C7009250BF99B0095B21C /* TopNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20C7008250BF99B0095B21C /* TopNotificationModel.swift */; }; D20C700B250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */; }; + D20F3B44252E00E4004B3F56 /* PageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20F3B43252E00E4004B3F56 /* PageProtocol.swift */; }; D20FB165241A5D75004AFC3A /* NavigationItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20FB164241A5D75004AFC3A /* NavigationItemModel.swift */; }; D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; }; D21B7F602437C5BC00051ABF /* MoleculeStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21B7F5E2437C5BC00051ABF /* MoleculeStackView.swift */; }; @@ -796,6 +797,7 @@ D20A9A5D2243D3E300ADE781 /* TwoButtonView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwoButtonView.swift; sourceTree = ""; }; D20C7008250BF99B0095B21C /* TopNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopNotificationModel.swift; sourceTree = ""; }; D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUITopAlertView+Extension.swift"; sourceTree = ""; }; + D20F3B43252E00E4004B3F56 /* PageProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageProtocol.swift; sourceTree = ""; }; D20FB164241A5D75004AFC3A /* NavigationItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItemModel.swift; sourceTree = ""; }; D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; D21B7F5E2437C5BC00051ABF /* MoleculeStackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeStackView.swift; sourceTree = ""; }; @@ -2077,6 +2079,7 @@ children = ( 012A88C7238DB02000FE3DA1 /* MoleculeDelegateProtocol.swift */, 017BEB47236230DB0024EF95 /* MoleculeViewProtocol.swift */, + D20F3B43252E00E4004B3F56 /* PageProtocol.swift */, 012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */, D28BA7442481652D00B75CB8 /* TabBarProtocol.swift */, 011B58EE23A2AA850085F53C /* ModelProtocols */, @@ -2345,6 +2348,7 @@ 525239C02407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift in Sources */, D2E2A99A23D8D6B4000B42E6 /* HeadlineBodyButtonModel.swift in Sources */, D202AFE6242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift in Sources */, + D20F3B44252E00E4004B3F56 /* PageProtocol.swift in Sources */, 8D084AD22410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift in Sources */, 94C0150C2421564A005811A9 /* ActionCollapseNotificationModel.swift in Sources */, D2CAC7CB251104E100C75681 /* NotificationXButtonModel.swift in Sources */, diff --git a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift index 9ebb8cfb..2e228ee5 100644 --- a/MVMCoreUI/Atomic/MoleculeObjectMapping.swift +++ b/MVMCoreUI/Atomic/MoleculeObjectMapping.swift @@ -35,12 +35,12 @@ import Foundation } /// Convenience function for legacy classes - public func getMoleculeModelForJSON(_ json: [String: Any]) throws -> MoleculeModelProtocol? { + public func getMoleculeModelForJSON(_ json: [String: Any], delegateObject: DelegateObject? = nil) throws -> MoleculeModelProtocol? { guard let moleculeName = json.optionalStringForKey(KeyMoleculeName), let type = ModelRegistry.getType(for: moleculeName, with: MoleculeModelProtocol.self) else { throw ModelRegistry.Error.decoderErrorModelNotMapped() } - guard let model = try type.decode(jsonDict: json) as? MoleculeModelProtocol else { + guard let model = try type.decode(jsonDict: json, delegateObject: delegateObject) as? MoleculeModelProtocol else { throw ModelRegistry.Error.decoderError } return model diff --git a/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift b/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift index d8c8c7ac..15ef632e 100644 --- a/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift +++ b/MVMCoreUI/Atomic/Molecules/NavigationBar/NavigationItemModel.swift @@ -8,25 +8,25 @@ import Foundation -public class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtocol { - public class var identifier: String { +open class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProtocol { + open class var identifier: String { return "navigationBar" } - public var title: String? - public var hidden: Bool - public var backgroundColor: Color? - public var tintColor: Color - public var line: LineModel? - public var hidesSystemBackButton = true + open var title: String? + open var hidden: Bool + open var backgroundColor: Color? + open var tintColor: Color + open var line: LineModel? + open var hidesSystemBackButton = true /// If true, we add the button in the backButton property. If false we do not add the button. If nil, we add the button if the controller is not the bottom of the stack - public var alwaysShowBackButton: Bool? - public var backButton: (NavigationButtonModelProtocol & MoleculeModelProtocol)? + open var alwaysShowBackButton: Bool? + open var backButton: (NavigationButtonModelProtocol & MoleculeModelProtocol)? - public var additionalLeftButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]? - public var additionalRightButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]? - public var titleView: MoleculeModelProtocol? + open var additionalLeftButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]? + open var additionalRightButtons: [(NavigationButtonModelProtocol & MoleculeModelProtocol)]? + open var titleView: MoleculeModelProtocol? public init() { hidden = false @@ -44,8 +44,6 @@ public class NavigationItemModel: NavigationItemModelProtocol, MoleculeModelProt case line case alwaysShowBackButton case backButton - case showLeftPanelButton - case showRightPanelButton case additionalLeftButtons case additionalRightButtons case titleView diff --git a/MVMCoreUI/Atomic/Protocols/PageProtocol.swift b/MVMCoreUI/Atomic/Protocols/PageProtocol.swift new file mode 100644 index 00000000..3c2a338b --- /dev/null +++ b/MVMCoreUI/Atomic/Protocols/PageProtocol.swift @@ -0,0 +1,28 @@ +// +// PageProtocol.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 10/7/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +public protocol PageProtocol { + var pageModel: PageModelProtocol? { get set } + + mutating func updateNavigation(with model: NavigationItemModelProtocol & MoleculeModelProtocol) +} + +public extension PageProtocol where Self: UIViewController { + mutating func updateNavigation(with model: NavigationItemModelProtocol & MoleculeModelProtocol) { + pageModel?.navigationBar = model + if var manager = ((self as? MVMCoreViewManagerViewControllerProtocol)?.manager as? PageProtocol) { + // Go through the manager if possible. + manager.updateNavigation(with: model) + } else if let navigationController = navigationController { + NavigationController.setNavigationItem(navigationController: navigationController, navigationItemModel: model, viewController: self) + MVMCoreUISplitViewController.setNavigationBarUI(for: self, navigationController: navigationController, navigationItemModel: model, leftPanelAccessible: (self as? MVMCoreUIDetailViewProtocol)?.isLeftPanelAccessible?(), rightPanelAccessible: (self as? MVMCoreUIDetailViewProtocol)?.isRightPanelAccessible?()) + } + } +} diff --git a/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift b/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift index 4696ce38..04bc080b 100644 --- a/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/TemplateProtocol.swift @@ -23,7 +23,7 @@ public extension TemplateProtocol where Self: ViewController { let decoder = JSONDecoder() try decoder.add(delegateObject: delegateObjectIVar) self.templateModel = try decodeTemplate(using: decoder, from: data) - self.pageModel = templateModel as? MVMControllerModelProtocol + self.model = templateModel as? MVMControllerModelProtocol } func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> TemplateModel { diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index f0d6ab84..dcd02c40 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -8,15 +8,23 @@ import UIKit - -@objc open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMCoreViewManagerViewControllerProtocol, MoleculeDelegateProtocol, FormHolderProtocol, MVMCoreActionDelegateProtocol, MVMCoreLoadDelegateProtocol, UITextFieldDelegate, UITextViewDelegate, ObservingTextFieldDelegate, MVMCoreUIDetailViewProtocol { +@objc open class ViewController: UIViewController, MVMCoreViewControllerProtocol, MVMCoreViewManagerViewControllerProtocol, MoleculeDelegateProtocol, FormHolderProtocol, MVMCoreActionDelegateProtocol, MVMCoreLoadDelegateProtocol, UITextFieldDelegate, UITextViewDelegate, ObservingTextFieldDelegate, MVMCoreUIDetailViewProtocol, PageProtocol { + //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @objc public var pageType: String? @objc public var loadObject: MVMCoreLoadObject? - public var pageModel: MVMControllerModelProtocol? + public var model: MVMControllerModelProtocol? + public var pageModel: PageModelProtocol? { + get { + return model + } + set { + model = newValue as? MVMControllerModelProtocol + } + } /// Set if this page is containted in a manager. public var manager: (UIViewController & MVMCoreViewManagerProtocol)? @@ -214,18 +222,18 @@ import UIKit /// Creates a legacy navigation model. open func createDefaultLegacyNavigationModel() -> NavigationItemModel { let navigationModel = NavigationItemModel() - navigationModel.title = pageModel?.screenHeading + navigationModel.title = model?.screenHeading return navigationModel } /// Processes any new data. Called after the page is loaded the first time and on response updates for this page, open func handleNewData() { if formValidator == nil { - let rules = pageModel?.formRules + let rules = model?.formRules formValidator = FormValidator(rules) } - if let backgroundColor = pageModel?.backgroundColor { + if let backgroundColor = model?.backgroundColor { view.backgroundColor = backgroundColor.uiColor } @@ -239,11 +247,11 @@ import UIKit open func getNavigationModel() -> NavigationItemModelProtocol? { // TODO: remove legacy. Temporary, convert legacy to navigation model. - if pageModel?.navigationBar == nil { + if model?.navigationBar == nil { let navigationItem = createDefaultLegacyNavigationModel() - pageModel?.navigationBar = navigationItem + model?.navigationBar = navigationItem } - return pageModel?.navigationBar + return model?.navigationBar } /// Sets the navigation item for this view controller. @@ -252,9 +260,6 @@ import UIKit let navigationController = navigationController else { return } - // We additionally want our left items - navigationItem.leftItemsSupplementBackButton = true - // Utilize helper function to set the navigation item state. NavigationController.setNavigationItem(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: self) } @@ -324,7 +329,7 @@ import UIKit guard MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() == self else { return } MVMCoreUISplitViewController.main()?.tabBar?.delegateObject = delegateObjectIVar - if let index = (pageModel as? TabPageModelProtocol)?.tabBarIndex { + if let index = (model as? TabPageModelProtocol)?.tabBarIndex { MVMCoreUISplitViewController.main()?.tabBar?.highlightTab(at: index) } else if let index = loadObject?.requestParameters?.actionMap?["tabBarIndex"] as? Int { MVMCoreUISplitViewController.main()?.tabBar?.highlightTab(at: index) @@ -335,7 +340,7 @@ import UIKit self.tabBarIndex = index } - if let hidden = (pageModel as? TabPageModelProtocol)?.tabBarHidden { + if let hidden = (model as? TabPageModelProtocol)?.tabBarHidden { MVMCoreUISplitViewController.main()?.updateTabBarShowing(!hidden) } else if let hidden = loadObject?.requestParameters?.actionMap?["tabBarHidden"] as? Bool { MVMCoreUISplitViewController.main()?.updateTabBarShowing(!hidden) @@ -594,6 +599,6 @@ import UIKit //-------------------------------------------------- func executeBehaviors(_ behaviorBlock:(_ behavior:T)->Void) { - pageModel?.behaviors?.compactMap({ $0 as? T }).forEach { behaviorBlock($0) } + model?.behaviors?.compactMap({ $0 as? T }).forEach { behaviorBlock($0) } } } diff --git a/MVMCoreUI/Containers/NavigationController.swift b/MVMCoreUI/Containers/NavigationController.swift index 22864027..89ea446c 100644 --- a/MVMCoreUI/Containers/NavigationController.swift +++ b/MVMCoreUI/Containers/NavigationController.swift @@ -48,6 +48,7 @@ import UIKit viewController.navigationItem.title = navigationItemModel.title viewController.navigationItem.accessibilityLabel = navigationItemModel.title viewController.navigationItem.hidesBackButton = navigationItemModel.hidesSystemBackButton + viewController.navigationItem.leftItemsSupplementBackButton = !navigationItemModel.hidesSystemBackButton setNavigationButtons(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController) setNavigationTitleView(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController) } @@ -97,7 +98,8 @@ import UIKit /// Convenience setter for legacy files public static func setNavigationItem(navigationController: UINavigationController, navigationJSON: [String: Any], viewController: UIViewController) throws { - guard let barModel = try MoleculeObjectMapping.shared()?.getMoleculeModelForJSON(navigationJSON) as? (MoleculeModelProtocol & NavigationItemModelProtocol) else { + let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject + guard let barModel = try MoleculeObjectMapping.shared()?.getMoleculeModelForJSON(navigationJSON, delegateObject: delegate) as? (MoleculeModelProtocol & NavigationItemModelProtocol) else { throw ModelRegistry.Error.decoderOther(message: "Model not a bar model") } setNavigationItem(navigationController: navigationController, navigationItemModel: barModel, viewController: viewController) @@ -105,7 +107,8 @@ import UIKit /// Convenience setter for legacy files public static func setNavigationBarUI(navigationController: UINavigationController, navigationJSON: [String: Any], viewController: UIViewController) throws { - guard let barModel = try MoleculeObjectMapping.shared()?.getMoleculeModelForJSON(navigationJSON) as? (MoleculeModelProtocol & NavigationItemModelProtocol) else { + let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject + guard let barModel = try MoleculeObjectMapping.shared()?.getMoleculeModelForJSON(navigationJSON, delegateObject: delegate) as? (MoleculeModelProtocol & NavigationItemModelProtocol) else { throw ModelRegistry.Error.decoderOther(message: "Model not a bar model") } setNavigationBarUI(navigationController: navigationController, navigationItemModel: barModel, viewController: viewController) diff --git a/MVMCoreUI/Containers/SplitViewController/MVMCoreUIDetailViewProtocol.h b/MVMCoreUI/Containers/SplitViewController/MVMCoreUIDetailViewProtocol.h index 2ec18da9..60ce0873 100644 --- a/MVMCoreUI/Containers/SplitViewController/MVMCoreUIDetailViewProtocol.h +++ b/MVMCoreUI/Containers/SplitViewController/MVMCoreUIDetailViewProtocol.h @@ -15,6 +15,12 @@ NS_ASSUME_NONNULL_BEGIN @optional +/// Returns if the left panel should be accessible. +- (BOOL)isLeftPanelAccessible; + +/// Returns if the right panel should be accessible. +- (BOOL)isRightPanelAccessible; + - (void)panelWillAppear:(nonnull NSObject *)panel; - (void)panelWillAppear:(nonnull NSObject *)panel overtakingDetail:(BOOL)willOvertake; - (void)panelDidAppear:(nonnull NSObject *)panel; diff --git a/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController+Extension.swift b/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController+Extension.swift index d37d88f1..8e14720d 100644 --- a/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController+Extension.swift +++ b/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController+Extension.swift @@ -111,7 +111,8 @@ public extension MVMCoreUISplitViewController { // MARK: - Legacy Functions /// Convenience setter for legacy files. Sets the navigation item for the view controller based on the json and splitview controller @objc static func setNavigationBarUI(for viewController: UIViewController, navigationController: UINavigationController, navigationJSON: [String: Any], leftPanelAccessible: Bool, rightPanelAccessible: Bool, progress: NSNumber?) throws { - guard let navigationItemModel = try MoleculeObjectMapping.shared()?.getMoleculeModelForJSON(navigationJSON) as? (MoleculeModelProtocol & NavigationItemModelProtocol) else { + let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject + guard let navigationItemModel = try MoleculeObjectMapping.shared()?.getMoleculeModelForJSON(navigationJSON, delegateObject: delegate) as? (MoleculeModelProtocol & NavigationItemModelProtocol) else { throw ModelRegistry.Error.decoderOther(message: "Model not a bar model") } guard let splitView = MVMCoreUISplitViewController.main(), From e60824ee1b4f38606a1f498396efa3c0d339575a Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Wed, 7 Oct 2020 18:15:52 -0400 Subject: [PATCH 08/16] Navigation Refresh protocol --- MVMCoreUI/Atomic/Protocols/PageProtocol.swift | 37 +++++++++++++++---- .../BaseControllers/ViewController.swift | 7 +++- 2 files changed, 35 insertions(+), 9 deletions(-) diff --git a/MVMCoreUI/Atomic/Protocols/PageProtocol.swift b/MVMCoreUI/Atomic/Protocols/PageProtocol.swift index 3c2a338b..c96742a4 100644 --- a/MVMCoreUI/Atomic/Protocols/PageProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/PageProtocol.swift @@ -11,18 +11,39 @@ import Foundation public protocol PageProtocol { var pageModel: PageModelProtocol? { get set } - mutating func updateNavigation(with model: NavigationItemModelProtocol & MoleculeModelProtocol) + /// Sets the navigationBar property of the pageModel and attempts to refresh the ui. + mutating func updateNavigationBar(with model: NavigationItemModelProtocol & MoleculeModelProtocol) } -public extension PageProtocol where Self: UIViewController { - mutating func updateNavigation(with model: NavigationItemModelProtocol & MoleculeModelProtocol) { +extension PageProtocol { + mutating public func updateNavigationBar(with model: NavigationItemModelProtocol & MoleculeModelProtocol) { pageModel?.navigationBar = model - if var manager = ((self as? MVMCoreViewManagerViewControllerProtocol)?.manager as? PageProtocol) { + (self as? NavigationBarRefreshProtocol)?.refreshNavigationUI() + } +} + +/// A protocol to inform that we should refresh the navigation bar ui. +@objc public protocol NavigationBarRefreshProtocol { + @objc func refreshNavigationUI() +} + +public extension UINavigationBar { + + /// Convenience function to refresh the navigation bar ui. + @objc static func refreshNavigationUI(for viewController: UIViewController) { + guard let model = (viewController as? PageProtocol)?.pageModel?.navigationBar else { return } + if let manager = ((viewController as? MVMCoreViewManagerViewControllerProtocol)?.manager as? NavigationBarRefreshProtocol) { // Go through the manager if possible. - manager.updateNavigation(with: model) - } else if let navigationController = navigationController { - NavigationController.setNavigationItem(navigationController: navigationController, navigationItemModel: model, viewController: self) - MVMCoreUISplitViewController.setNavigationBarUI(for: self, navigationController: navigationController, navigationItemModel: model, leftPanelAccessible: (self as? MVMCoreUIDetailViewProtocol)?.isLeftPanelAccessible?(), rightPanelAccessible: (self as? MVMCoreUIDetailViewProtocol)?.isRightPanelAccessible?()) + manager.refreshNavigationUI() + } else if let navigationController = viewController.navigationController { + NavigationController.setNavigationItem(navigationController: navigationController, navigationItemModel: model, viewController: viewController) + MVMCoreUISplitViewController.setNavigationBarUI(for: viewController, navigationController: navigationController, navigationItemModel: model, leftPanelAccessible: (viewController as? MVMCoreUIDetailViewProtocol)?.isLeftPanelAccessible?(), rightPanelAccessible: (viewController as? MVMCoreUIDetailViewProtocol)?.isRightPanelAccessible?()) } } } + +extension UIViewController: NavigationBarRefreshProtocol { + public func refreshNavigationUI() { + UINavigationBar.refreshNavigationUI(for: self) + } +} diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index dcd02c40..a751f2b1 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -121,7 +121,12 @@ import UIKit // Update navigation bar if showing. if MVMCoreUIUtility.getCurrentVisibleController() == self { - self.setNavigationBar() + if let manager = self.manager { + // Let manager handle + manager.refreshNavigationUI() + } else { + self.setNavigationBar() + } } }) } catch { From 43bd436225293604528326a4cb1799627dd37e32 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 8 Oct 2020 11:31:40 -0400 Subject: [PATCH 09/16] Added view controller getter. --- MVMCoreUI/Containers/NavigationController.swift | 2 +- .../MVMCoreUISplitViewController+Extension.swift | 2 +- .../SplitViewController/MVMCoreUISplitViewController.m | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/MVMCoreUI/Containers/NavigationController.swift b/MVMCoreUI/Containers/NavigationController.swift index 89ea446c..681642f8 100644 --- a/MVMCoreUI/Containers/NavigationController.swift +++ b/MVMCoreUI/Containers/NavigationController.swift @@ -59,7 +59,7 @@ import UIKit var leftItems: [UIBarButtonItem] = [] if navigationItemModel.alwaysShowBackButton != false { if let backButtonModel = navigationItemModel.backButton, - navigationController.viewControllers.count > 1 || navigationItemModel.alwaysShowBackButton ?? false { + MVMCoreNavigationHandler.shared()?.getViewControllers(for: navigationController)?.count ?? 0 > 1 || navigationItemModel.alwaysShowBackButton ?? false { leftItems.append(backButtonModel.createNavigationItemButton(delegateObject: delegate, additionalData: nil)) } if let leftItemModels = navigationItemModel.additionalLeftButtons { diff --git a/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController+Extension.swift b/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController+Extension.swift index 8e14720d..2f452647 100644 --- a/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController+Extension.swift +++ b/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController+Extension.swift @@ -48,7 +48,7 @@ public extension MVMCoreUISplitViewController { if let forceBackButton = navigationItemModel?.alwaysShowBackButton { showBackButton = forceBackButton } else { - showBackButton = navigationController.viewControllers.count > 1 + showBackButton = MVMCoreNavigationHandler.shared()?.getViewControllers(for: navigationController)?.count ?? 0 > 1 } if showBackButton { if let backButtonModel = navigationItemModel?.backButton { diff --git a/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController.m b/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController.m index 177d0b8a..d88641fa 100644 --- a/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController.m +++ b/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController.m @@ -241,7 +241,7 @@ CGFloat const PanelAnimationDuration = 0.2; - (void)setLeftNavigationItemForViewController:(UIViewController * _Nonnull)viewController accessible:(BOOL)accessible extended:(BOOL)extended { NSMutableArray *leftBarButtonItems = [NSMutableArray array]; - if ([viewController.navigationController.viewControllers count] > 1) { + if (viewController.navigationController && [MVMCoreNavigationHandler.sharedNavigationHandler getViewControllersForNavigationController:viewController.navigationController].count > 1) { [leftBarButtonItems addObject:self.backButton]; } if ((accessible && !extended) && self.leftPanelButton) { From 101e1422f3595716d0c560dcd6677ef3409d8185 Mon Sep 17 00:00:00 2001 From: "Khan, Arshad" Date: Thu, 8 Oct 2020 21:01:55 +0530 Subject: [PATCH 10/16] scroll view indicator fix for defect: CXTDT-82115 --- MVMCoreUI/BaseControllers/ScrollingViewController.swift | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/MVMCoreUI/BaseControllers/ScrollingViewController.swift b/MVMCoreUI/BaseControllers/ScrollingViewController.swift index eb1d5999..7b368e2a 100644 --- a/MVMCoreUI/BaseControllers/ScrollingViewController.swift +++ b/MVMCoreUI/BaseControllers/ScrollingViewController.swift @@ -50,6 +50,14 @@ open class ScrollingViewController: ViewController { dismissKeyboardTapGesture?.isEnabled = false scrollView.alwaysBounceVertical = false scrollView.delegate = self + // will change scrollView indicatorStyle automatically on the basis of backgroundColor + var componentWhite:CGFloat = 0 + var componentAlpha:CGFloat = 0 + if let grayScale = view.backgroundColor?.getWhite(&componentWhite, alpha: &componentAlpha), grayScale + { + scrollView.indicatorStyle = componentWhite > 0 ? .black : .white + } + scrollView.flashScrollIndicators() } open override func viewDidLayoutSubviews() { From 2e12464016e406f8be5ff3d18731dfe36f80bfeb Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 8 Oct 2020 15:01:38 -0400 Subject: [PATCH 11/16] decouple manager navigation setting a little better --- MVMCoreUI/Atomic/Protocols/PageProtocol.swift | 21 +-- .../BaseControllers/ViewController.swift | 122 +++++++++--------- ...MCoreUISplitViewController+Extension.swift | 38 ++---- 3 files changed, 77 insertions(+), 104 deletions(-) diff --git a/MVMCoreUI/Atomic/Protocols/PageProtocol.swift b/MVMCoreUI/Atomic/Protocols/PageProtocol.swift index c96742a4..8cd8bf34 100644 --- a/MVMCoreUI/Atomic/Protocols/PageProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/PageProtocol.swift @@ -10,16 +10,6 @@ import Foundation public protocol PageProtocol { var pageModel: PageModelProtocol? { get set } - - /// Sets the navigationBar property of the pageModel and attempts to refresh the ui. - mutating func updateNavigationBar(with model: NavigationItemModelProtocol & MoleculeModelProtocol) -} - -extension PageProtocol { - mutating public func updateNavigationBar(with model: NavigationItemModelProtocol & MoleculeModelProtocol) { - pageModel?.navigationBar = model - (self as? NavigationBarRefreshProtocol)?.refreshNavigationUI() - } } /// A protocol to inform that we should refresh the navigation bar ui. @@ -32,12 +22,13 @@ public extension UINavigationBar { /// Convenience function to refresh the navigation bar ui. @objc static func refreshNavigationUI(for viewController: UIViewController) { guard let model = (viewController as? PageProtocol)?.pageModel?.navigationBar else { return } - if let manager = ((viewController as? MVMCoreViewManagerViewControllerProtocol)?.manager as? NavigationBarRefreshProtocol) { - // Go through the manager if possible. - manager.refreshNavigationUI() - } else if let navigationController = viewController.navigationController { + if let navigationController = viewController.navigationController { NavigationController.setNavigationItem(navigationController: navigationController, navigationItemModel: model, viewController: viewController) - MVMCoreUISplitViewController.setNavigationBarUI(for: viewController, navigationController: navigationController, navigationItemModel: model, leftPanelAccessible: (viewController as? MVMCoreUIDetailViewProtocol)?.isLeftPanelAccessible?(), rightPanelAccessible: (viewController as? MVMCoreUIDetailViewProtocol)?.isRightPanelAccessible?()) + MVMCoreUISplitViewController.setNavigationBarUI(for: viewController, navigationController: navigationController, navigationItemModel: model) + } + if let manager = ((viewController as? MVMCoreViewManagerViewControllerProtocol)?.manager as? NavigationBarRefreshProtocol) { + // Refresh the manager if possible. + manager.refreshNavigationUI() } } } diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index a751f2b1..e7563faa 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -119,14 +119,15 @@ import UIKit MVMCoreDispatchUtility.performBlock(onMainThread: { self.handleNewDataAndUpdateUI() - // Update navigation bar if showing. if MVMCoreUIUtility.getCurrentVisibleController() == self { - if let manager = self.manager { - // Let manager handle - manager.refreshNavigationUI() - } else { - self.setNavigationBar() - } + // Update navigation bar if showing. + self.setNavigationBar() + self.manager?.refreshNavigationUI() + } + // Update splitview properties + if self == MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() { + MVMCoreUISplitViewController.main()?.setBottomProgressBarProgress(self.bottomProgress() ?? 0) + self.updateTabBar() } }) } catch { @@ -140,7 +141,7 @@ import UIKit pageType = loadObject.pageType self.loadObject = loadObject - // Verifies all modules needed are loaded. TODO: change to ViewController + // Verifies all modules needed are loaded. guard ViewController.verifyRequiredModulesLoaded(for: loadObject, error: error) else { return false } // Parse the model for the page. @@ -247,7 +248,7 @@ import UIKit } //-------------------------------------------------- - // MARK: - Navigation Item (Move to model base) + // MARK: - Navigation Item //-------------------------------------------------- open func getNavigationModel() -> NavigationItemModelProtocol? { @@ -271,61 +272,16 @@ import UIKit /// Sets the appearance of the navigation bar based on the model. open func setNavigationBar() { - let viewController = manager ?? self guard let navigationItemModel = getNavigationModel(), - let navigationController = viewController.navigationController else { + let navigationController = navigationController else { MVMCoreUISession.sharedGlobal()?.splitViewController?.parent?.setNeedsStatusBarAppearanceUpdate() return } // Utilize helper function to set the split view and navigation item state. - MVMCoreUISplitViewController.setNavigationBarUI(for: viewController, navigationController: navigationController, navigationItemModel: navigationItemModel, leftPanelAccessible: isMasterInitiallyAccessible(), rightPanelAccessible: isSupportInitiallyAccessible(), progress: bottomProgress() ?? 0) + MVMCoreUISplitViewController.setNavigationBarUI(for: self, navigationController: navigationController, navigationItemModel: navigationItemModel) } - // Eventually will be moved to server - open func isMasterInitiallyAccessible() -> Bool { - if loadObject?.pageJSON?.boolForKey(KeyHideMainMenu) ?? false { - return false - } - return MVMCoreUISession.sharedGlobal()?.launchAppLoadedSuccessfully ?? false - } - - // Eventually will be moved to server - open func isSupportInitiallyAccessible() -> Bool { - if loadObject?.pageJSON?.boolForKey(KeyHideMainMenu) ?? false { - return false - } - return (MVMCoreUISession.sharedGlobal()?.launchAppLoadedSuccessfully ?? false) || showRightPanelForScreenBeforeLaunchApp() - } - - open func showRightPanelForScreenBeforeLaunchApp() -> Bool { - return loadObject?.pageJSON?.lenientBoolForKey("showRightPanel") ?? false - } - - // Eventually will be moved to separate button in navigation item model - open func isOverridingRightButton() -> Bool { - guard let rightPanelLink = loadObject?.pageJSON?.optionalDictionaryForKey("rightPanelButtonLink") - else { return false } - MVMCoreActionHandler.shared()?.handleAction(with: rightPanelLink, additionalData: nil, delegateObject: delegateObject()) - return true - } - - // Eventually will be moved to separate button in navigation item model - open func isOverridingLeftButton() -> Bool { - guard let leftPanelLink = loadObject?.pageJSON?.optionalDictionaryForKey("leftPanelButtonLink") - else { return false } - MVMCoreActionHandler.shared()?.handleAction(with: leftPanelLink, additionalData: nil, delegateObject: delegateObject()) - return true - } - - // Eventually will be moved to Model - open func bottomProgress() -> Float? { - guard let progressString = loadObject?.pageJSON?.optionalStringForKey(KeyProgressPercent), - let progress = Float(progressString) - else { return nil } - - return progress / Float(100) - } //-------------------------------------------------- // MARK: - TabBar //-------------------------------------------------- @@ -408,14 +364,15 @@ import UIKit } open func pageShown() { - // Update the navigation bar ui when view is appearing. + // Update split view properties if this is the current detail controller. if self == MVMCoreUISplitViewController.main()?.getCurrentDetailViewController() { MVMCoreUISplitViewController.main()?.setupPanels() + MVMCoreUISplitViewController.main()?.setBottomProgressBarProgress(bottomProgress() ?? 0) + updateTabBar() } - setNavigationBar() - // Update tab if needed. - updateTabBar() + // Update the navigation bar ui when view is appearing. + setNavigationBar() // Track. MVMCoreUISession.sharedGlobal()?.currentPageType = pageType @@ -536,6 +493,51 @@ import UIKit setNavigationBar() } + public func isLeftPanelAccessible() -> Bool { + // TODO: Remove when hamburger menu is fully phased out. + if loadObject?.pageJSON?.boolForKey(KeyHideMainMenu) ?? false { + return false + } + return MVMCoreUISession.sharedGlobal()?.launchAppLoadedSuccessfully ?? false + } + + public func isRightPanelAccessible() -> Bool { + // TODO: Remove when FAB is 100%. + if loadObject?.pageJSON?.boolForKey(KeyHideMainMenu) ?? false { + return false + } + return (MVMCoreUISession.sharedGlobal()?.launchAppLoadedSuccessfully ?? false) || showRightPanelForScreenBeforeLaunchApp() + } + + open func showRightPanelForScreenBeforeLaunchApp() -> Bool { + return loadObject?.pageJSON?.lenientBoolForKey("showRightPanel") ?? false + } + + // TODO: make molecular + open func isOverridingRightButton() -> Bool { + guard let rightPanelLink = loadObject?.pageJSON?.optionalDictionaryForKey("rightPanelButtonLink") + else { return false } + MVMCoreActionHandler.shared()?.handleAction(with: rightPanelLink, additionalData: nil, delegateObject: delegateObject()) + return true + } + + // TODO: make molecular + open func isOverridingLeftButton() -> Bool { + guard let leftPanelLink = loadObject?.pageJSON?.optionalDictionaryForKey("leftPanelButtonLink") + else { return false } + MVMCoreActionHandler.shared()?.handleAction(with: leftPanelLink, additionalData: nil, delegateObject: delegateObject()) + return true + } + + // Eventually will be moved to Model + open func bottomProgress() -> Float? { + guard let progressString = loadObject?.pageJSON?.optionalStringForKey(KeyProgressPercent), + let progress = Float(progressString) + else { return nil } + + return progress / Float(100) + } + //-------------------------------------------------- // MARK: - UITextFieldDelegate //-------------------------------------------------- diff --git a/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController+Extension.swift b/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController+Extension.swift index 2f452647..eb22eccb 100644 --- a/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController+Extension.swift +++ b/MVMCoreUI/Containers/SplitViewController/MVMCoreUISplitViewController+Extension.swift @@ -10,32 +10,29 @@ import Foundation public extension MVMCoreUISplitViewController { - /// Convenience function. Sets the navigation and split view properties for the view controller. Optional parameters use current value if not set. - static func setNavigationBarUI(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol, leftPanelAccessible: Bool? = nil, rightPanelAccessible: Bool? = nil, progress: Float? = nil) { + /// Convenience function. Sets the navigation and split view properties for the view controller. Panel access is determined if view controller is a detail view protocol. + static func setNavigationBarUI(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) { guard let splitView = MVMCoreUISplitViewController.main(), navigationController == splitView.navigationController, navigationController.topViewController == viewController else { - NavigationController.setNavigationBarUI(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController) - return + /// Not the split view navigation controller, skip split functions. + NavigationController.setNavigationBarUI(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController) + return } - splitView.set(for: viewController, navigationController: navigationController, navigationItemModel: navigationItemModel, leftPanelAccessible: leftPanelAccessible, rightPanelAccessible: rightPanelAccessible, progress: progress) + splitView.set(for: viewController, navigationController: navigationController, navigationItemModel: navigationItemModel) } /// Sets the navigation item for the view controller based on the model and splitview controller - private func set(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol, leftPanelAccessible: Bool? = nil, rightPanelAccessible: Bool? = nil, progress: Float? = nil) { + private func set(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) { NavigationController.setNavigationBarUI(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController) - setLeftPanelIsAccessible(leftPanelAccessible ?? leftPanelIsAccessible, for: viewController, updateNavigationButtons: false) - setRightPanelIsAccessible(rightPanelAccessible ?? rightPanelIsAccessible, for: viewController, updateNavigationButtons: false) + setLeftPanelIsAccessible((viewController as? MVMCoreUIDetailViewProtocol)?.isLeftPanelAccessible?() ?? false, for: viewController, updateNavigationButtons: false) + setRightPanelIsAccessible((viewController as? MVMCoreUIDetailViewProtocol)?.isRightPanelAccessible?() ?? false, for: viewController, updateNavigationButtons: false) setLeftNavigationButtons(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController) setRightNavigationButtons(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController) setNavigationIconColor(navigationItemModel.tintColor.uiColor) - - if let progress = progress { - setBottomProgressBarProgress(progress) - } } /// Sets the left navigation items for the view controller based on model and splitview. @@ -107,21 +104,4 @@ public extension MVMCoreUISplitViewController { viewController.navigationItem.setRightBarButtonItems(rightItems.count > 0 ? rightItems : nil, animated: !DisableAnimations.boolValue) } - - // MARK: - Legacy Functions - /// Convenience setter for legacy files. Sets the navigation item for the view controller based on the json and splitview controller - @objc static func setNavigationBarUI(for viewController: UIViewController, navigationController: UINavigationController, navigationJSON: [String: Any], leftPanelAccessible: Bool, rightPanelAccessible: Bool, progress: NSNumber?) throws { - let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject - guard let navigationItemModel = try MoleculeObjectMapping.shared()?.getMoleculeModelForJSON(navigationJSON, delegateObject: delegate) as? (MoleculeModelProtocol & NavigationItemModelProtocol) else { - throw ModelRegistry.Error.decoderOther(message: "Model not a bar model") - } - guard let splitView = MVMCoreUISplitViewController.main(), - navigationController == splitView.navigationController, - navigationController.topViewController == viewController else { - NavigationController.setNavigationBarUI(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController) - return - } - let progress = progress?.floatValue - splitView.set(for: viewController, navigationController: navigationController, navigationItemModel: navigationItemModel, leftPanelAccessible: leftPanelAccessible, rightPanelAccessible: rightPanelAccessible, progress: progress) - } } From 20369d5a1e959b1d0f4018bcc6705ebeee9cf10f Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 8 Oct 2020 15:10:23 -0400 Subject: [PATCH 12/16] Minor cleanup --- MVMCoreUI.xcodeproj/project.pbxproj | 4 +++ .../NavigationBarRefreshProtocol.swift | 34 +++++++++++++++++++ MVMCoreUI/Atomic/Protocols/PageProtocol.swift | 27 --------------- .../Containers/NavigationController.swift | 20 +---------- 4 files changed, 39 insertions(+), 46 deletions(-) create mode 100644 MVMCoreUI/Atomic/Protocols/NavigationBarRefreshProtocol.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 0b0e49c6..1755d203 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -304,6 +304,7 @@ D20C7009250BF99B0095B21C /* TopNotificationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20C7008250BF99B0095B21C /* TopNotificationModel.swift */; }; D20C700B250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */; }; D20F3B44252E00E4004B3F56 /* PageProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20F3B43252E00E4004B3F56 /* PageProtocol.swift */; }; + D20F3B5E252F9B5E004B3F56 /* NavigationBarRefreshProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20F3B5D252F9B5D004B3F56 /* NavigationBarRefreshProtocol.swift */; }; D20FB165241A5D75004AFC3A /* NavigationItemModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D20FB164241A5D75004AFC3A /* NavigationItemModel.swift */; }; D213347723843825008E41B3 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = D213347623843825008E41B3 /* Line.swift */; }; D21B7F602437C5BC00051ABF /* MoleculeStackView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D21B7F5E2437C5BC00051ABF /* MoleculeStackView.swift */; }; @@ -798,6 +799,7 @@ D20C7008250BF99B0095B21C /* TopNotificationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopNotificationModel.swift; sourceTree = ""; }; D20C700A250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUITopAlertView+Extension.swift"; sourceTree = ""; }; D20F3B43252E00E4004B3F56 /* PageProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PageProtocol.swift; sourceTree = ""; }; + D20F3B5D252F9B5D004B3F56 /* NavigationBarRefreshProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationBarRefreshProtocol.swift; sourceTree = ""; }; D20FB164241A5D75004AFC3A /* NavigationItemModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NavigationItemModel.swift; sourceTree = ""; }; D213347623843825008E41B3 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = ""; }; D21B7F5E2437C5BC00051ABF /* MoleculeStackView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoleculeStackView.swift; sourceTree = ""; }; @@ -2082,6 +2084,7 @@ D20F3B43252E00E4004B3F56 /* PageProtocol.swift */, 012A88AC238C418100FE3DA1 /* TemplateProtocol.swift */, D28BA7442481652D00B75CB8 /* TabBarProtocol.swift */, + D20F3B5D252F9B5D004B3F56 /* NavigationBarRefreshProtocol.swift */, 011B58EE23A2AA850085F53C /* ModelProtocols */, ); path = Protocols; @@ -2431,6 +2434,7 @@ D22479942316AE5E003FCCF9 /* NSLayoutConstraintExtension.swift in Sources */, D2B18B94236214AD00A9AEDC /* NavigationController.swift in Sources */, 0A9D09222433796500D2E6C0 /* CarouselIndicator.swift in Sources */, + D20F3B5E252F9B5E004B3F56 /* NavigationBarRefreshProtocol.swift in Sources */, D29E28DA23D21AFA00ACEA85 /* StringAndMoleculeModel.swift in Sources */, D260105D23D0BCD400764D80 /* Stack.swift in Sources */, 0A7EF85D23D8A95600B2AAD1 /* TextEntryFieldModel.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Protocols/NavigationBarRefreshProtocol.swift b/MVMCoreUI/Atomic/Protocols/NavigationBarRefreshProtocol.swift new file mode 100644 index 00000000..589aa4ab --- /dev/null +++ b/MVMCoreUI/Atomic/Protocols/NavigationBarRefreshProtocol.swift @@ -0,0 +1,34 @@ +// +// NavigationBarRefreshProtocol.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 10/8/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +/// A protocol to inform that we should refresh the navigation bar ui. +@objc public protocol NavigationBarRefreshProtocol { + @objc func refreshNavigationUI() +} + +extension UIViewController: NavigationBarRefreshProtocol { + + /// Convenience function to refresh the navigation bar ui. A separate function for others to use. + @objc static func refreshNavigationUI(for viewController: UIViewController) { + guard let model = (viewController as? PageProtocol)?.pageModel?.navigationBar else { return } + if let navigationController = viewController.navigationController { + NavigationController.setNavigationItem(navigationController: navigationController, navigationItemModel: model, viewController: viewController) + MVMCoreUISplitViewController.setNavigationBarUI(for: viewController, navigationController: navigationController, navigationItemModel: model) + } + if let manager = ((viewController as? MVMCoreViewManagerViewControllerProtocol)?.manager as? NavigationBarRefreshProtocol) { + // Refresh the manager if possible. + manager.refreshNavigationUI() + } + } + + public func refreshNavigationUI() { + UIViewController.refreshNavigationUI(for: self) + } +} diff --git a/MVMCoreUI/Atomic/Protocols/PageProtocol.swift b/MVMCoreUI/Atomic/Protocols/PageProtocol.swift index 8cd8bf34..4117604e 100644 --- a/MVMCoreUI/Atomic/Protocols/PageProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/PageProtocol.swift @@ -11,30 +11,3 @@ import Foundation public protocol PageProtocol { var pageModel: PageModelProtocol? { get set } } - -/// A protocol to inform that we should refresh the navigation bar ui. -@objc public protocol NavigationBarRefreshProtocol { - @objc func refreshNavigationUI() -} - -public extension UINavigationBar { - - /// Convenience function to refresh the navigation bar ui. - @objc static func refreshNavigationUI(for viewController: UIViewController) { - guard let model = (viewController as? PageProtocol)?.pageModel?.navigationBar else { return } - if let navigationController = viewController.navigationController { - NavigationController.setNavigationItem(navigationController: navigationController, navigationItemModel: model, viewController: viewController) - MVMCoreUISplitViewController.setNavigationBarUI(for: viewController, navigationController: navigationController, navigationItemModel: model) - } - if let manager = ((viewController as? MVMCoreViewManagerViewControllerProtocol)?.manager as? NavigationBarRefreshProtocol) { - // Refresh the manager if possible. - manager.refreshNavigationUI() - } - } -} - -extension UIViewController: NavigationBarRefreshProtocol { - public func refreshNavigationUI() { - UINavigationBar.refreshNavigationUI(for: self) - } -} diff --git a/MVMCoreUI/Containers/NavigationController.swift b/MVMCoreUI/Containers/NavigationController.swift index 681642f8..7a403338 100644 --- a/MVMCoreUI/Containers/NavigationController.swift +++ b/MVMCoreUI/Containers/NavigationController.swift @@ -95,25 +95,7 @@ import UIKit navigationController.separatorView?.isHidden = navigationItemModel.line?.type ?? .standard == .none } } - - /// Convenience setter for legacy files - public static func setNavigationItem(navigationController: UINavigationController, navigationJSON: [String: Any], viewController: UIViewController) throws { - let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject - guard let barModel = try MoleculeObjectMapping.shared()?.getMoleculeModelForJSON(navigationJSON, delegateObject: delegate) as? (MoleculeModelProtocol & NavigationItemModelProtocol) else { - throw ModelRegistry.Error.decoderOther(message: "Model not a bar model") - } - setNavigationItem(navigationController: navigationController, navigationItemModel: barModel, viewController: viewController) - } - - /// Convenience setter for legacy files - public static func setNavigationBarUI(navigationController: UINavigationController, navigationJSON: [String: Any], viewController: UIViewController) throws { - let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject - guard let barModel = try MoleculeObjectMapping.shared()?.getMoleculeModelForJSON(navigationJSON, delegateObject: delegate) as? (MoleculeModelProtocol & NavigationItemModelProtocol) else { - throw ModelRegistry.Error.decoderOther(message: "Model not a bar model") - } - setNavigationBarUI(navigationController: navigationController, navigationItemModel: barModel, viewController: viewController) - } - + /// Convenience function for setting the navigation titleView. public static func setNavigationTitleView(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol?, viewController: UIViewController) { let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject From b89e414cb79b3401f0129dc88b9130cf79a5e952 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 8 Oct 2020 15:27:47 -0400 Subject: [PATCH 13/16] missed commits --- MVMCoreUI/Atomic/Protocols/NavigationBarRefreshProtocol.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/Atomic/Protocols/NavigationBarRefreshProtocol.swift b/MVMCoreUI/Atomic/Protocols/NavigationBarRefreshProtocol.swift index 589aa4ab..2d4002e3 100644 --- a/MVMCoreUI/Atomic/Protocols/NavigationBarRefreshProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/NavigationBarRefreshProtocol.swift @@ -16,7 +16,7 @@ import Foundation extension UIViewController: NavigationBarRefreshProtocol { /// Convenience function to refresh the navigation bar ui. A separate function for others to use. - @objc static func refreshNavigationUI(for viewController: UIViewController) { + @objc public static func refreshNavigationUI(for viewController: UIViewController) { guard let model = (viewController as? PageProtocol)?.pageModel?.navigationBar else { return } if let navigationController = viewController.navigationController { NavigationController.setNavigationItem(navigationController: navigationController, navigationItemModel: model, viewController: viewController) From 6c1a8ba330bb8f52b7d07cd39f22d2232eb8b917 Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Thu, 8 Oct 2020 19:52:46 -0400 Subject: [PATCH 14/16] modal section list --- MVMCoreUI.xcodeproj/project.pbxproj | 20 ++++++++---- .../Templates/ModalSectionListTemplate.swift | 30 +++++++++++++++++ .../ModalSectionListTemplateModel.swift | 32 +++++++++++++++++++ ...iewControllerMappingObject+Extension.swift | 1 + 4 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 MVMCoreUI/Atomic/Templates/ModalSectionListTemplate.swift create mode 100644 MVMCoreUI/Atomic/Templates/ModalSectionListTemplateModel.swift diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index 45211c90..f9ec5dc4 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -469,6 +469,8 @@ D2CAC7D3251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2CAC7D2251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift */; }; D2D2FCF0252B72AF0033EAAA /* MoleculeSectionFooterModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D2FCEF252B72AF0033EAAA /* MoleculeSectionFooterModel.swift */; }; D2D2FCF3252B72CF0033EAAA /* MoleculeSectionFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D2FCF2252B72CF0033EAAA /* MoleculeSectionFooter.swift */; }; + D2D3957A252FDBB300047B11 /* ModalSectionListTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D39579252FDBB300047B11 /* ModalSectionListTemplate.swift */; }; + D2D3957D252FDBCD00047B11 /* ModalSectionListTemplateModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D3957C252FDBCD00047B11 /* ModalSectionListTemplateModel.swift */; }; D2D6CD4022E78C1A00D701B8 /* Scroller.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */; }; D2D6CD4222E78FAB00D701B8 /* ThreeLayerTemplate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */; }; D2D90B42240463E100DD6EC9 /* MoleculeHeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2D90B41240463E100DD6EC9 /* MoleculeHeaderModel.swift */; }; @@ -486,12 +488,12 @@ D2E2A99F23E07F8A000B42E6 /* PillButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2A99E23E07F8A000B42E6 /* PillButton.swift */; }; D2E2A9A123E095AB000B42E6 /* ButtonModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2A9A023E095AB000B42E6 /* ButtonModelProtocol.swift */; }; D2E2A9A323E096B1000B42E6 /* DisableableModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2E2A9A223E096B1000B42E6 /* DisableableModelProtocol.swift */; }; - D2FA83D22513EA6900564112 /* NotificationXButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D12513EA6900564112 /* NotificationXButton.swift */; }; - D2FA83D42514F80C00564112 /* CollapsableNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D32514F80C00564112 /* CollapsableNotification.swift */; }; - D2FA83D62515021F00564112 /* CollapsableNotificationTopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */; }; D2EC7BD52527B7A600F540AF /* MoleculeSectionHeaderModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EC7BD42527B7A600F540AF /* MoleculeSectionHeaderModel.swift */; }; D2EC7BD92527B7CF00F540AF /* MoleculeSectionHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EC7BD82527B7CF00F540AF /* MoleculeSectionHeader.swift */; }; D2EC7BDD2527B83700F540AF /* SectionHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2EC7BDC2527B83700F540AF /* SectionHeaderFooterView.swift */; }; + D2FA83D22513EA6900564112 /* NotificationXButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D12513EA6900564112 /* NotificationXButton.swift */; }; + D2FA83D42514F80C00564112 /* CollapsableNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D32514F80C00564112 /* CollapsableNotification.swift */; }; + D2FA83D62515021F00564112 /* CollapsableNotificationTopView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */; }; D2FB151B23A2B65B00C20E10 /* MoleculeContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */; }; D2FB151D23A40F1500C20E10 /* MoleculeStackItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FB151C23A40F1500C20E10 /* MoleculeStackItem.swift */; }; D2FD4A4925199BD9000C28A9 /* AccessibilityProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2FD4A4825199BD9000C28A9 /* AccessibilityProtocol.swift */; }; @@ -971,6 +973,8 @@ D2CAC7D2251105A700C75681 /* MVMCoreUITopAlertExpandableView+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "MVMCoreUITopAlertExpandableView+Extension.swift"; sourceTree = ""; }; D2D2FCEF252B72AF0033EAAA /* MoleculeSectionFooterModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionFooterModel.swift; sourceTree = ""; }; D2D2FCF2252B72CF0033EAAA /* MoleculeSectionFooter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionFooter.swift; sourceTree = ""; }; + D2D39579252FDBB300047B11 /* ModalSectionListTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalSectionListTemplate.swift; sourceTree = ""; }; + D2D3957C252FDBCD00047B11 /* ModalSectionListTemplateModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModalSectionListTemplateModel.swift; sourceTree = ""; }; D2D6CD3F22E78C1A00D701B8 /* Scroller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scroller.swift; sourceTree = ""; }; D2D6CD4122E78FAB00D701B8 /* ThreeLayerTemplate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThreeLayerTemplate.swift; sourceTree = ""; }; D2D90B41240463E100DD6EC9 /* MoleculeHeaderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeHeaderModel.swift; sourceTree = ""; }; @@ -987,12 +991,12 @@ D2E2A99E23E07F8A000B42E6 /* PillButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PillButton.swift; sourceTree = ""; }; D2E2A9A023E095AB000B42E6 /* ButtonModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonModelProtocol.swift; sourceTree = ""; }; D2E2A9A223E096B1000B42E6 /* DisableableModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisableableModelProtocol.swift; sourceTree = ""; }; - D2FA83D12513EA6900564112 /* NotificationXButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationXButton.swift; sourceTree = ""; }; - D2FA83D32514F80C00564112 /* CollapsableNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotification.swift; sourceTree = ""; }; - D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotificationTopView.swift; sourceTree = ""; }; D2EC7BD42527B7A600F540AF /* MoleculeSectionHeaderModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionHeaderModel.swift; sourceTree = ""; }; D2EC7BD82527B7CF00F540AF /* MoleculeSectionHeader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeSectionHeader.swift; sourceTree = ""; }; D2EC7BDC2527B83700F540AF /* SectionHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SectionHeaderFooterView.swift; sourceTree = ""; }; + D2FA83D12513EA6900564112 /* NotificationXButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationXButton.swift; sourceTree = ""; }; + D2FA83D32514F80C00564112 /* CollapsableNotification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotification.swift; sourceTree = ""; }; + D2FA83D52515021F00564112 /* CollapsableNotificationTopView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CollapsableNotificationTopView.swift; sourceTree = ""; }; D2FB151A23A2B65B00C20E10 /* MoleculeContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeContainer.swift; sourceTree = ""; }; D2FB151C23A40F1500C20E10 /* MoleculeStackItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MoleculeStackItem.swift; sourceTree = ""; }; D2FD4A4825199BD9000C28A9 /* AccessibilityProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AccessibilityProtocol.swift; sourceTree = ""; }; @@ -1707,6 +1711,8 @@ D264FA8D243BCD9A00D98315 /* CollectionTemplate.swift */, D2169302251E53D9002A6324 /* SectionListTemplateModel.swift */, D2169300251E51E7002A6324 /* SectionListTemplate.swift */, + D2D3957C252FDBCD00047B11 /* ModalSectionListTemplateModel.swift */, + D2D39579252FDBB300047B11 /* ModalSectionListTemplate.swift */, ); path = Templates; sourceTree = ""; @@ -2559,6 +2565,7 @@ 0AE98BB323FF0934004C5109 /* ExternalLinkModel.swift in Sources */, D20FB165241A5D75004AFC3A /* NavigationItemModel.swift in Sources */, AA2AD118244EE48C00BBFFE3 /* ListDeviceComplexLinkMediumModel.swift in Sources */, + D2D3957A252FDBB300047B11 /* ModalSectionListTemplate.swift in Sources */, DB06250B2293456500B72DD3 /* LeftRightLabelView.swift in Sources */, D28BA741248025A300B75CB8 /* TabBarModel.swift in Sources */, D224798A2314445E003FCCF9 /* LabelToggle.swift in Sources */, @@ -2671,6 +2678,7 @@ D260105923D0A92900764D80 /* ContainerProtocol.swift in Sources */, BB6C6AC924225290005F7224 /* ListOneColumnTextWithWhitespaceDividerShortModel.swift in Sources */, C695A69423C9909000BFB94E /* DoughnutChartModel.swift in Sources */, + D2D3957D252FDBCD00047B11 /* ModalSectionListTemplateModel.swift in Sources */, 8D4687E2242E2DE400802879 /* ListFourColumnDataUsageListItemModel.swift in Sources */, D29E28DD23D7404C00ACEA85 /* ContainerHelper.swift in Sources */, 012A88C2238D7BCA00FE3DA1 /* CarouselItemModel.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Templates/ModalSectionListTemplate.swift b/MVMCoreUI/Atomic/Templates/ModalSectionListTemplate.swift new file mode 100644 index 00000000..77ee705c --- /dev/null +++ b/MVMCoreUI/Atomic/Templates/ModalSectionListTemplate.swift @@ -0,0 +1,30 @@ +// +// ModalSectionListTemplate.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 10/8/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +open class ModalSectionListTemplate: SectionListTemplate { + + // For subclassing the model. + open override func decodeTemplate(using decoder: JSONDecoder, from data: Data) throws -> ModalSectionListTemplateModel { + return try decoder.decode(ModalSectionListTemplateModel.self, from: data) + } + + override open func handleNewData() { + super.handleNewData() + _ = MVMCoreUICommonViewsUtility.addCloseButton(to: view, action: {[weak self] _ in + guard let self = self else { return } + guard let model = self.templateModel as? ModalSectionListTemplateModel, + let actionMap = model.closeAction else { + MVMCoreActionHandler.shared()?.handleAction(with: ActionBackModel().toJSON(), additionalData: nil, delegateObject: self.delegateObjectIVar) + return + } + MVMCoreActionHandler.shared()?.handleAction(with: actionMap.toJSON(), additionalData: nil, delegateObject: self.delegateObjectIVar) + }) + } +} diff --git a/MVMCoreUI/Atomic/Templates/ModalSectionListTemplateModel.swift b/MVMCoreUI/Atomic/Templates/ModalSectionListTemplateModel.swift new file mode 100644 index 00000000..83f2bb98 --- /dev/null +++ b/MVMCoreUI/Atomic/Templates/ModalSectionListTemplateModel.swift @@ -0,0 +1,32 @@ +// +// ModalSectionListTemplateModel.swift +// MVMCoreUI +// +// Created by Scott Pfeil on 10/8/20. +// Copyright © 2020 Verizon Wireless. All rights reserved. +// + +import Foundation + +@objcMembers public class ModalSectionListTemplateModel: SectionListTemplateModel { + public override class var identifier: String { + return "modalSectionList" + } + public var closeAction: ActionModelProtocol? + + private enum CodingKeys: String, CodingKey { + case closeAction + } + + required public init(from decoder: Decoder) throws { + let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + closeAction = try typeContainer.decodeModelIfPresent(codingKey: .closeAction) + 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.encodeModelIfPresent(closeAction, forKey: .closeAction) + } +} diff --git a/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject+Extension.swift b/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject+Extension.swift index efd70570..f126799c 100644 --- a/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject+Extension.swift +++ b/MVMCoreUI/OtherHandlers/MVMCoreUIViewControllerMappingObject+Extension.swift @@ -21,6 +21,7 @@ public extension MVMCoreUIViewControllerMappingObject { register(template: MoleculeListTemplate.self) add(toTemplateViewControllerMapping: ["modalList": MVMCoreViewControllerProgrammaticMappingObject(with: ModalMoleculeListTemplate.self)!]) add(toTemplateViewControllerMapping: [SectionListTemplateModel.identifier: MVMCoreViewControllerProgrammaticMappingObject(with: SectionListTemplate.self)!]) + add(toTemplateViewControllerMapping: [ModalSectionListTemplateModel.identifier: MVMCoreViewControllerProgrammaticMappingObject(with: ModalSectionListTemplate.self)!]) register(template: ThreeLayerTemplate.self) register(template: ThreeLayerCenterTemplate.self) From 16f8989036d5898cd504e480ac33a01ccc953a0a Mon Sep 17 00:00:00 2001 From: "Khan, Arshad" Date: Fri, 9 Oct 2020 23:03:02 +0530 Subject: [PATCH 15/16] implemented review feedback --- .../ScrollingViewController.swift | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/MVMCoreUI/BaseControllers/ScrollingViewController.swift b/MVMCoreUI/BaseControllers/ScrollingViewController.swift index 7b368e2a..fcbcf878 100644 --- a/MVMCoreUI/BaseControllers/ScrollingViewController.swift +++ b/MVMCoreUI/BaseControllers/ScrollingViewController.swift @@ -50,14 +50,6 @@ open class ScrollingViewController: ViewController { dismissKeyboardTapGesture?.isEnabled = false scrollView.alwaysBounceVertical = false scrollView.delegate = self - // will change scrollView indicatorStyle automatically on the basis of backgroundColor - var componentWhite:CGFloat = 0 - var componentAlpha:CGFloat = 0 - if let grayScale = view.backgroundColor?.getWhite(&componentWhite, alpha: &componentAlpha), grayScale - { - scrollView.indicatorStyle = componentWhite > 0 ? .black : .white - } - scrollView.flashScrollIndicators() } open override func viewDidLayoutSubviews() { @@ -71,6 +63,16 @@ open class ScrollingViewController: ViewController { registerForKeyboardNotifications() } + open override func handleNewData() { + super.handleNewData() + // will change scrollView indicatorStyle automatically on the basis of backgroundColor + var greyScale: CGFloat = 0 + if view.backgroundColor?.getWhite(&greyScale, alpha: nil) ?? false { + scrollView.indicatorStyle = greyScale > 0.5 ? .black : .white + } + scrollView.flashScrollIndicators() + } + //-------------------------------------------------- // MARK: - Keyboard Handling //-------------------------------------------------- From 35468f592e4956275642e2aef2c6bd6d638a7f9d Mon Sep 17 00:00:00 2001 From: "Pfeil, Scott Robert" Date: Fri, 9 Oct 2020 14:19:56 -0400 Subject: [PATCH 16/16] accessibility adjustment --- MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings index bbeadbdb..ee0b1849 100644 --- a/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings +++ b/MVMCoreUI/SupportingFiles/Strings/en.lproj/Localizable.strings @@ -71,7 +71,7 @@ "heart_favorite_action_hint" = "Double tap to favorite"; "heart_unfavorite_action_hint" = "Double tap to unfavorite"; "heart_selected_state" = "Favorited"; -"heart_not_selected_state" = "Unfavorited"; +"heart_not_selected_state" = "Un-favorited"; // MARK: Carousel "MVMCoreUIPageControl_currentpage_index" = "page %@ of %d";