diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index d475e062..8dc2e960 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -22,9 +22,9 @@ download_artifacts: - bash_shell environment: name: oneartifactory - url: https://oneartifactoryprod.verizon.com/artifactory + url: https://oneartifactoryci.verizon.com/artifactory variables: - ARTIFACTORY_URL: https://oneartifactoryprod.verizon.com/artifactory + ARTIFACTORY_URL: https://oneartifactoryci.verizon.com/artifactory build_project: stage: build @@ -47,9 +47,9 @@ deploy_snapshot: - bash_shell environment: name: oneartifactory - url: https://oneartifactoryprod.verizon.com/artifactory + url: https://oneartifactoryci.verizon.com/artifactory variables: - ARTIFACTORY_URL: https://oneartifactoryprod.verizon.com/artifactory + ARTIFACTORY_URL: https://oneartifactoryci.verizon.com/artifactory #promote_snapshot: # stage: go live @@ -65,9 +65,9 @@ deploy_snapshot: # - bash_shell # environment: # name: oneartifactory -# url: https://oneartifactoryprod.verizon.com/artifactory +# url: https://oneartifactoryci.verizon.com/artifactory # variables: -# ARTIFACTORY_URL: https://oneartifactoryprod.verizon.com/artifactory +# ARTIFACTORY_URL: https://oneartifactoryci.verizon.com/artifactory # #create_version_tag: # stage: tag diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index df9843e1..eb5327be 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -602,6 +602,7 @@ EAB14BC327D9378D0012AB2C /* RuleAnyModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB14BC227D9378D0012AB2C /* RuleAnyModelProtocol.swift */; }; EABFC1412763BB8D00E78B40 /* FormLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC1402763BB8D00E78B40 /* FormLabel.swift */; }; EABFC152276913E800E78B40 /* FormLabelModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC151276913E800E78B40 /* FormLabelModel.swift */; }; + FD99130028E21E4900542CC3 /* RuleNotEqualsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD9912FF28E21E4900542CC3 /* RuleNotEqualsModel.swift */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ @@ -1203,6 +1204,7 @@ EAB14BC227D9378D0012AB2C /* RuleAnyModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyModelProtocol.swift; sourceTree = ""; }; EABFC1402763BB8D00E78B40 /* FormLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormLabel.swift; sourceTree = ""; }; EABFC151276913E800E78B40 /* FormLabelModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormLabelModel.swift; sourceTree = ""; }; + FD9912FF28E21E4900542CC3 /* RuleNotEqualsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleNotEqualsModel.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -1257,6 +1259,7 @@ 0A69F610241BDEA700F7231B /* RuleAnyRequiredModel.swift */, 011D95A0240453D0000E3791 /* RuleEqualsModel.swift */, 0A849EFD246F1775009F277F /* RuleEqualsIgnoreCaseModel.swift */, + FD9912FF28E21E4900542CC3 /* RuleNotEqualsModel.swift */, ); name = Rules; path = Rules/Rules; @@ -2956,6 +2959,7 @@ D2509ED12472ED9B001BFB9D /* NavigationItemModelProtocol.swift in Sources */, EA05EFAB278DE53600828819 /* ClearableModelProtocol.swift in Sources */, 8D448E5524050A46006211BB /* ListOneColumnFullWidthTextAllTextAndLinksModel.swift in Sources */, + FD99130028E21E4900542CC3 /* RuleNotEqualsModel.swift in Sources */, BBC0C4FD24811DBC0087C44F /* Tag.swift in Sources */, 94C2D9842386F3F80006CF46 /* LabelAttributeModel.swift in Sources */, 944589212385D6E900DE9FD4 /* DashLineModel.swift in Sources */, @@ -3221,7 +3225,6 @@ D29DF0D221E404D4003B2FB9 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; @@ -3289,7 +3292,6 @@ D29DF0D321E404D4003B2FB9 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; ALWAYS_SEARCH_USER_PATHS = NO; BUILD_LIBRARY_FOR_DISTRIBUTION = YES; CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; diff --git a/MVMCoreUI/Alerts/MVMCoreAlertHandler.m b/MVMCoreUI/Alerts/MVMCoreAlertHandler.m index 75dab8f1..16fb1f4a 100644 --- a/MVMCoreUI/Alerts/MVMCoreAlertHandler.m +++ b/MVMCoreUI/Alerts/MVMCoreAlertHandler.m @@ -83,6 +83,11 @@ [self removeAllAlertViews]; } + if (alertStyle == UIAlertControllerStyleActionSheet && UIDevice.currentDevice.userInterfaceIdiom != UIUserInterfaceIdiomPhone) { + // ActionSheets are not supported on iPad interfaces without a source rect (i.e. a source element) which isn't currently supported for our generic handling. + alertStyle = UIAlertControllerStyleAlert; + } + // Create the alert. Adds the actions one by one. MVMCoreAlertController *alertController = [MVMCoreAlertController alertControllerWithTitle:(title ?: @"") message:message preferredStyle:alertStyle]; for (NSUInteger i = 0; i < [actions count]; i++) { diff --git a/MVMCoreUI/Alerts/MVMCoreAlertObject+Swift.swift b/MVMCoreUI/Alerts/MVMCoreAlertObject+Swift.swift index c2c5d50f..0adae2e2 100644 --- a/MVMCoreUI/Alerts/MVMCoreAlertObject+Swift.swift +++ b/MVMCoreUI/Alerts/MVMCoreAlertObject+Swift.swift @@ -9,6 +9,41 @@ public extension MVMCoreAlertObject { + static func alertObject(from alertModel: AlertModel, actions: [UIAlertAction]? = nil, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> MVMCoreAlertObject? { + + let actionsForAlert = actions ?? generateActions(from: alertModel.alertActions, additionalData: additionalData, delegateObject: delegateObject) + + let alertObject = MVMCoreAlertObject(popupAlertWithTitle: alertModel.title, + message: alertModel.message, + actions: actionsForAlert, + isGreedy: false) + + alertObject?.alertStyle = alertModel.style + alertObject?.pageJson = alertModel.analyticsData + + return alertObject + } + + static func generateActions(from buttonModels: [AlertButtonModel], additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?, additionalHandling: ((AlertButtonModel, UIAlertAction)->())? = nil) -> [UIAlertAction] { + return buttonModels.map { alertButtonModel in + let alertAction = UIAlertAction(title: alertButtonModel.title, style: alertButtonModel.style) { action in + Task(priority: .userInitiated) { + do { + try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction( + with: alertButtonModel.action, + additionalData: additionalData, + delegateObject: delegateObject + ) + } catch { + + } + additionalHandling?(alertButtonModel, action) + } + } + return alertAction + } + } + @objc static func alertObjectWith(action actionJson: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?, error: AutoreleasingUnsafeMutablePointer?) -> MVMCoreAlertObject? { guard let alertJson = actionJson?.optionalDictionaryForKey("alert"), diff --git a/MVMCoreUI/Atomic/Actions/ActionAlertHandler.swift b/MVMCoreUI/Atomic/Actions/ActionAlertHandler.swift index 0f4a11fa..f3004f71 100644 --- a/MVMCoreUI/Atomic/Actions/ActionAlertHandler.swift +++ b/MVMCoreUI/Atomic/Actions/ActionAlertHandler.swift @@ -25,7 +25,14 @@ open class ActionAlertHandler: MVMCoreJSONActionHandlerProtocol { } open func execute(with model: ActionModelProtocol, delegateObject: DelegateObject?, additionalData: [AnyHashable : Any]?) async throws { - let json = try MVMCoreActionHandler.convertActionToJSON(model) - try await performAction(with: json, model: model, delegateObject: delegateObject, additionalData: additionalData) + guard let model = model as? ActionAlertModel else { return } + var error: MVMCoreErrorObject? = nil + guard let alertObject = MVMCoreAlertObject.alertObject(from: model.alert, additionalData: additionalData, delegateObject: delegateObject, error: &error) else { + throw MVMCoreError.errorObject(error!) + } + (delegateObject?.actionDelegate as? MVMCoreUIActionDelegateProtocol)?.willShowPopup(with: alertObject, alertJson: try MVMCoreActionHandler.convertActionToJSON(model)) + _ = await MainActor.run { + MVMCoreAlertHandler.shared()?.showAlert(with: alertObject) + } } } diff --git a/MVMCoreUI/Atomic/Actions/AlertModel.swift b/MVMCoreUI/Atomic/Actions/AlertModel.swift index 76bfb273..6825898c 100644 --- a/MVMCoreUI/Atomic/Actions/AlertModel.swift +++ b/MVMCoreUI/Atomic/Actions/AlertModel.swift @@ -23,7 +23,7 @@ public class AlertButtonModel: Codable { // MARK: - Initializer //-------------------------------------------------- - public init(_ title: String,_ action: ActionModelProtocol,_ style: UIAlertAction.Style = .default) { + public init(_ title: String, _ action: ActionModelProtocol, style: UIAlertAction.Style = .default) { self.title = title self.action = action self.style = style @@ -76,10 +76,11 @@ public class AlertModel: Codable { // MARK: - Properties //-------------------------------------------------- - public init(_ title: String,_ message: String,_ alertActions: [AlertButtonModel]) { + public init(title: String, message: String, alertActions: [AlertButtonModel], style: UIAlertController.Style = .alert) { self.title = title self.message = message self.alertActions = alertActions + self.style = style } //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/BaseDropdownFieldModel.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/BaseDropdownFieldModel.swift index 39701016..6c2131ac 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/BaseDropdownFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/Dropdown Fields/BaseDropdownFieldModel.swift @@ -26,6 +26,11 @@ case action } + open override func setDefaults() { + super.setDefaults() + enableClipboardActions = false + } + //-------------------------------------------------- // MARK: - Codec //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryFieldModel.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryFieldModel.swift index 4e35ce30..7b3eee03 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/EntryFieldModel.swift @@ -83,6 +83,9 @@ import Foundation case shouldMaskRecordedView } + /// Sets the default values. Should be called on init. + open func setDefaults() { } + //-------------------------------------------------- // MARK: - Validation Methods //-------------------------------------------------- @@ -119,6 +122,7 @@ import Foundation baseValue = text self.titleStateLabel = FormLabelModel(text: "") self.feedbackStateLabel = FormLabelModel(text: "") + setDefaults() } //-------------------------------------------------- @@ -157,6 +161,7 @@ import Foundation self.feedbackStateLabel = FormLabelModel(model: LabelModel(text: feedback ?? "", fontStyle: FormLabelModel.defaultFontStyle, textColor: Color(uiColor: .mvmCoolGray6))) + setDefaults() } public func encode(to encoder: Encoder) throws { diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift index 07260ac1..18749c8a 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryField.swift @@ -338,6 +338,7 @@ import UIKit placeholder = model.placeholder textField.shouldMaskWhileRecording = model.shouldMaskRecordedView ?? true + textField.enableClipboardActions = model.enableClipboardActions switch model.type { case .password, .secure: diff --git a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryFieldModel.swift b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryFieldModel.swift index 7d2eb987..053a5ac5 100644 --- a/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryFieldModel.swift +++ b/MVMCoreUI/Atomic/Atoms/FormFields/TextFields/TextEntryFieldModel.swift @@ -37,6 +37,7 @@ public var clearTextOnTap: Bool = false public var displayFormat: String? public var displayMask: String? + public var enableClipboardActions: Bool = true //-------------------------------------------------- // MARK: - Initializers @@ -112,6 +113,7 @@ case clearTextOnTap case displayFormat case displayMask + case enableClipboardActions } //-------------------------------------------------- @@ -143,6 +145,10 @@ if let textAlignment = try typeContainer.decodeIfPresent(NSTextAlignment.self, forKey: .textAlignment) { self.textAlignment = textAlignment } + + if let enableClipboardActions = try typeContainer.decodeIfPresent(Bool.self, forKey: .enableClipboardActions) { + self.enableClipboardActions = enableClipboardActions + } } open override func encode(to encoder: Encoder) throws { @@ -157,5 +163,6 @@ try container.encode(enabledTextColor, forKey: .enabledTextColor) try container.encode(disabledTextColor, forKey: .disabledTextColor) try container.encode(clearTextOnTap, forKey: .clearTextOnTap) + try container.encode(enableClipboardActions, forKey: .enableClipboardActions) } } diff --git a/MVMCoreUI/Atomic/Atoms/Views/CheckboxLabelModel.swift b/MVMCoreUI/Atomic/Atoms/Views/CheckboxLabelModel.swift index 858984b0..58f398b6 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/CheckboxLabelModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/CheckboxLabelModel.swift @@ -15,8 +15,8 @@ public enum CheckboxPosition: String, Codable { case bottom } -@objcMembers public class CheckboxLabelModel: MoleculeModelProtocol { - public static var identifier: String = "checkboxLabel" +@objcMembers open class CheckboxLabelModel: MoleculeModelProtocol { + open class var identifier: String { "checkboxLabel" } public var moleculeName: String = CheckboxLabelModel.identifier public var backgroundColor: Color? public var checkboxAlignment: CheckboxPosition? diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift index 9ce55537..059c5637 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/Label.swift @@ -241,18 +241,7 @@ public typealias ActionBlock = () -> () case left } - public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject? = nil, _ additionalData: [AnyHashable: Any]? = nil) { - - clauses = [] - text = nil - attributedText = nil - originalAttributedString = nil - shouldMaskWhileRecording = model.shouldMaskRecordedView ?? false - - guard let labelModel = model as? LabelModel else { return } - - text = labelModel.text - + @objc public func resetAttributeStyle() { /* * This is to address a reuse issue with iOS 13 and up. * Even if you set text & attributedText to nil, the moment you set text with a value, @@ -274,6 +263,21 @@ public typealias ActionBlock = () -> () self.attributedText = attributedString } + } + + public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject? = nil, _ additionalData: [AnyHashable: Any]? = nil) { + + clauses = [] + text = nil + attributedText = nil + originalAttributedString = nil + shouldMaskWhileRecording = model.shouldMaskRecordedView ?? false + + guard let labelModel = model as? LabelModel else { return } + + text = labelModel.text + + resetAttributeStyle() hero = labelModel.hero Label.setLabel(self, withHTML: labelModel.html) diff --git a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift index 10e6a4e5..d1995d19 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Label/LabelModel.swift @@ -7,12 +7,13 @@ // -@objcMembers open class LabelModel: MoleculeModelProtocol { +@objcMembers open class LabelModel: MoleculeModelProtocol, Identifiable { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- open class var identifier: String { "label" } + public var id: String public var backgroundColor: Color? public var text: String public var accessibilityText: String? @@ -34,6 +35,7 @@ private enum CodingKeys: String, CodingKey { case moleculeName + case id case text case accessibilityText case textColor @@ -58,7 +60,8 @@ // MARK: - Initializer //-------------------------------------------------- - public init(text: String) { + public init(id: String = UUID().uuidString, text: String) { + self.id = id self.text = text } @@ -78,6 +81,7 @@ required public init(from decoder: Decoder) throws { let typeContainer = try decoder.container(keyedBy: CodingKeys.self) + id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString text = try typeContainer.decode(String.self, forKey: .text) accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText) textColor = try typeContainer.decodeIfPresent(Color.self, forKey: .textColor) @@ -102,6 +106,7 @@ open func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) try container.encodeIfPresent(moleculeName, forKey: .moleculeName) + try container.encodeIfPresent(id, forKey: .id) try container.encode(text, forKey: .text) try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText) try container.encodeIfPresent(textColor, forKey: .textColor) diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextBodyTextModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextBodyTextModel.swift index 288b0591..94be5a53 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextBodyTextModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/OneColumn/ListOneColumnFullWidthTextBodyTextModel.swift @@ -9,7 +9,7 @@ import Foundation -public class ListOneColumnFullWidthTextBodyTextModel: ListItemModel, MoleculeModelProtocol { +public class ListOneColumnFullWidthTextBodyTextModel: ListItemModel, MoleculeModelProtocol, ParentMoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -35,6 +35,10 @@ public class ListOneColumnFullWidthTextBodyTextModel: ListItemModel, MoleculeMod headlineBody.style = .item } + public var children: [MoleculeModelProtocol] { + return [headlineBody] + } + //-------------------------------------------------- // MARK: - Keys //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableButtonAllTextAndLinksModel.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableButtonAllTextAndLinksModel.swift index db093a9a..21a4b08c 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableButtonAllTextAndLinksModel.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableButtonAllTextAndLinksModel.swift @@ -7,7 +7,7 @@ // -public class ListRightVariableButtonAllTextAndLinksModel: ListItemModel, MoleculeModelProtocol { +public class ListRightVariableButtonAllTextAndLinksModel: ListItemModel, MoleculeModelProtocol, ParentMoleculeModelProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- @@ -36,6 +36,10 @@ public class ListRightVariableButtonAllTextAndLinksModel: ListItemModel, Molecul self.button.style = .secondary } + public var children: [MoleculeModelProtocol] { + return [button, eyebrowHeadlineBodyLink] + } + //-------------------------------------------------- // MARK: - Keys //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableTextLinkAllTextAndLinks.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableTextLinkAllTextAndLinks.swift index 059a637f..e47cae46 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableTextLinkAllTextAndLinks.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/List/RightVariable/ListRightVariableTextLinkAllTextAndLinks.swift @@ -71,10 +71,14 @@ func getAccessibilityMessage() -> String? { - guard let linkText = link.titleLabel?.text else { + guard var linkText = link.titleLabel?.text else { return eyebrowHeadlineBodyLink.getAccessibilityMessage() } + if !link.isEnabled, let accDisabled = MVMCoreUIUtility.hardcodedString(withKey:"AccDisabled") { + linkText = linkText + ", " + accDisabled + } + guard let label = eyebrowHeadlineBodyLink.getAccessibilityMessage() else { return linkText } diff --git a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift index 62ee43f5..772ec5ac 100644 --- a/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift +++ b/MVMCoreUI/Atomic/Molecules/DesignedComponents/SectionDividers/OneColumn/ListOneColumnTextWithWhitespaceDividerTall.swift @@ -41,7 +41,6 @@ import Foundation addMolecule(stack) stack.restack() isAccessibilityElement = true - updateAccessibilityLabel() } //-------------------------------------------------- @@ -53,7 +52,8 @@ import Foundation guard let model = model as? ListOneColumnTextWithWhitespaceDividerTallModel else { return } stack.updateContainedMolecules(with: [model.headline, model.body], delegateObject, additionalData) - updateAccessibilityLabel() + + updateAccessibilityLabel(model: model) } open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? { @@ -64,24 +64,25 @@ import Foundation super.reset() headline.setFontStyle(.BoldTitleMedium) body.setFontStyle(.RegularBodySmall) + accessibilityLabel = nil } //---------------------------------------------------- // MARK: - Accessibility //---------------------------------------------------- - func updateAccessibilityLabel() { - + func updateAccessibilityLabel(model: ListOneColumnTextWithWhitespaceDividerTallModel) { + var message = "" - - if let headlineLabel = headline.text, !headlineLabel.isEmpty { + + if let headlineLabel = model.headline.accessibilityText ?? headline.text, !headlineLabel.isEmpty { message += headlineLabel + ", " } - - if let bodyLabel = body.text, !bodyLabel.isEmpty { + + if let bodyLabel = model.body?.accessibilityText ?? body.text, !bodyLabel.isEmpty { message += bodyLabel } - + accessibilityLabel = message } } diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBody.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBody.swift index ae0d22c4..96e94640 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBody.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBody.swift @@ -150,6 +150,9 @@ open class HeadlineBody: View { open override func reset() { super.reset() + //Reset the text values + headlineLabel.reset() + messageLabel.reset() stylePageHeader() } } diff --git a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift index a3452e7b..20df223a 100644 --- a/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift +++ b/MVMCoreUI/Atomic/Molecules/VerticalCombinationViews/HeadlineBodyModel.swift @@ -47,6 +47,11 @@ self.body = body } + public init(headline: LabelModel, body: LabelModel) { + self.headline = headline + self.body = body + } + //----------------------------------------------------- // MARK: - Codec //----------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Templates/ThreeLayerPageTemplateModel.swift b/MVMCoreUI/Atomic/Templates/ThreeLayerPageTemplateModel.swift index e3ada79d..ab4f29d5 100644 --- a/MVMCoreUI/Atomic/Templates/ThreeLayerPageTemplateModel.swift +++ b/MVMCoreUI/Atomic/Templates/ThreeLayerPageTemplateModel.swift @@ -7,12 +7,12 @@ // -@objcMembers public class ThreeLayerPageTemplateModel: ThreeLayerModelBase { +@objcMembers open class ThreeLayerPageTemplateModel: ThreeLayerModelBase { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- - public override class var identifier: String { "threeLayer" } + open override class var identifier: String { "threeLayer" } public var middle: MoleculeModelProtocol? public override var rootMolecules: [MoleculeModelProtocol] { @@ -51,7 +51,7 @@ try super.init(from: decoder) } - public override func encode(to encoder: Encoder) throws { + open override func encode(to encoder: Encoder) throws { try super.encode(to: encoder) var container = encoder.container(keyedBy: CodingKeys.self) try container.encodeModelIfPresent(header, forKey: .middle) diff --git a/MVMCoreUI/BaseClasses/Control.swift b/MVMCoreUI/BaseClasses/Control.swift index 865e3a8e..91cee30f 100644 --- a/MVMCoreUI/BaseClasses/Control.swift +++ b/MVMCoreUI/BaseClasses/Control.swift @@ -9,7 +9,7 @@ import UIKit -@objcMembers open class Control: UIControl, MoleculeViewProtocol { +open class Control: UIControl, MoleculeViewProtocol { //-------------------------------------------------- // MARK: - Properties //-------------------------------------------------- diff --git a/MVMCoreUI/BaseClasses/TextField.swift b/MVMCoreUI/BaseClasses/TextField.swift index 306b363f..34e301a3 100644 --- a/MVMCoreUI/BaseClasses/TextField.swift +++ b/MVMCoreUI/BaseClasses/TextField.swift @@ -23,7 +23,7 @@ public protocol TextInputDidDeleteProtocol: AnyObject { /// Set to true to hide the blinking textField cursor. public var hideBlinkingCaret = false - + public var enableClipboardActions: Bool = true public var shouldMaskWhileRecording: Bool = true //-------------------------------------------------- @@ -74,6 +74,8 @@ public protocol TextInputDidDeleteProtocol: AnyObject { super.deleteBackward() didDeleteDelegate?.textInputDidDelete() } + + open override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { enableClipboardActions } } /// MARK:- MVMCoreViewProtocol @@ -91,7 +93,7 @@ extension TextField: MVMCoreViewProtocol { /// MARK:- MoleculeViewProtocol extension TextField: MoleculeViewProtocol { - open func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { + public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { if let color = model.backgroundColor?.uiColor { backgroundColor = color diff --git a/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift b/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift index 3420299d..d5f65323 100644 --- a/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift +++ b/MVMCoreUI/Behaviors/Protocols/PageBehaviorProtocol.swift @@ -30,6 +30,8 @@ public protocol PageMoleculeTransformationBehavior: PageBehaviorProtocol { func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?) func willSetupMolecule(with model: MoleculeModelProtocol, updating view: MoleculeViewProtocol?) func didSetupMolecule(view: MoleculeViewProtocol, withModel: MoleculeModelProtocol) + func willSetupNavigationBar(with model: NavigationItemModelProtocol, updating view: UINavigationBar) + func didSetupNavigationBar(view: UINavigationBar, with model: NavigationItemModelProtocol) } public extension PageMoleculeTransformationBehavior { @@ -37,6 +39,8 @@ public extension PageMoleculeTransformationBehavior { func onPageNew(rootMolecules: [MoleculeModelProtocol], _ delegateObject: MVMCoreUIDelegateObject?) {} func willSetupMolecule(with model: MoleculeModelProtocol, updating view: MoleculeViewProtocol?) {} func didSetupMolecule(view: MoleculeViewProtocol, withModel: MoleculeModelProtocol) {} + func willSetupNavigationBar(with model: NavigationItemModelProtocol, updating view: UINavigationBar) {} + func didSetupNavigationBar(view: UINavigationBar, with model: NavigationItemModelProtocol) {} } public protocol PageVisibilityBehavior: PageBehaviorProtocol { diff --git a/MVMCoreUI/Containers/NavigationController/NavigationController.swift b/MVMCoreUI/Containers/NavigationController/NavigationController.swift index 9b4b332a..eb43201a 100644 --- a/MVMCoreUI/Containers/NavigationController/NavigationController.swift +++ b/MVMCoreUI/Containers/NavigationController/NavigationController.swift @@ -70,30 +70,30 @@ extension NavigationController: MVMCoreViewManagerProtocol { public func newDataReceived(in viewController: UIViewController) { if isDisplayed(viewController: viewController), - let topViewController = topViewController, let model = getNavigationModel(from: viewController) { - setNavigationItem(with: model, for: topViewController) - setNavigationBarUI(with: model) - - navigationBar.setNeedsLayout() - navigationBar.layoutIfNeeded() + updateNavigationView(with: model, for: viewController) } manager?.newDataReceived?(in: viewController) } public func willDisplay(_ viewController: UIViewController) { - if let topViewController = topViewController, - isDisplayed(viewController: viewController), + if isDisplayed(viewController: viewController), let model = getNavigationModel(from: viewController) { - setNavigationItem(with: model, for: topViewController) - setNavigationBarUI(with: model) - - navigationBar.setNeedsLayout() - navigationBar.layoutIfNeeded() + updateNavigationView(with: model, for: viewController) } manager?.willDisplay?(viewController) } + private func updateNavigationView(with model: NavigationItemModelProtocol, for viewController: UIViewController) { + guard let topViewController = topViewController else { return } + + setNavigationItem(with: model, for: topViewController, coordinatingWith: viewController as? PageBehaviorHandlerProtocol) + setNavigationBarUI(with: model) + + navigationBar.setNeedsLayout() + navigationBar.layoutIfNeeded() + } + public func displayedViewController(_ viewController: UIViewController) { manager?.displayedViewController?(viewController) } diff --git a/MVMCoreUI/Containers/NavigationController/UINavigationController+Extension.swift b/MVMCoreUI/Containers/NavigationController/UINavigationController+Extension.swift index e63028d4..9a0665b9 100644 --- a/MVMCoreUI/Containers/NavigationController/UINavigationController+Extension.swift +++ b/MVMCoreUI/Containers/NavigationController/UINavigationController+Extension.swift @@ -11,13 +11,24 @@ import Foundation public extension UINavigationController { /// Convenience function for setting the navigation item. - func setNavigationItem(with model: NavigationItemModelProtocol, for viewController: UIViewController) { + func setNavigationItem(with model: NavigationItemModelProtocol, for viewController: UIViewController, coordinatingWith pageBehaviorController: PageBehaviorHandlerProtocol? = nil) { + + let behaviorHandler = pageBehaviorController ?? viewController as? PageBehaviorHandlerProtocol; + + behaviorHandler?.executeBehaviors { (behavior: PageMoleculeTransformationBehavior) in + behavior.willSetupNavigationBar(with: model, updating: navigationBar) + } + viewController.navigationItem.title = model.title viewController.navigationItem.accessibilityLabel = model.title viewController.navigationItem.hidesBackButton = model.hidesSystemBackButton viewController.navigationItem.leftItemsSupplementBackButton = !model.hidesSystemBackButton setNavigationButtons(with: model, for: viewController) - setNavigationTitleView(with: model, for: viewController) + setNavigationTitleView(with: model, for: viewController, coordinatingWith: pageBehaviorController) + + behaviorHandler?.executeBehaviors { (behavior: PageMoleculeTransformationBehavior) in + behavior.didSetupNavigationBar(view: navigationBar, with: model) + } } /// Convenience function for setting the navigation buttons. @@ -48,11 +59,22 @@ public extension UINavigationController { } /// Convenience function for setting the navigation titleView. - func setNavigationTitleView(with model: NavigationItemModelProtocol, for viewController: UIViewController) { + func setNavigationTitleView(with model: NavigationItemModelProtocol, for viewController: UIViewController, coordinatingWith pageBehaviorController: PageBehaviorHandlerProtocol? = nil) { + guard let titleViewModel = model.titleView else { return } + let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject - if let titleViewModel = model.titleView, - let molecule = ModelRegistry.createMolecule(titleViewModel, delegateObject: delegate, additionalData: nil) { - viewController.navigationItem.titleView = molecule + + let behaviorHandler = pageBehaviorController ?? viewController as? PageBehaviorHandlerProtocol; + behaviorHandler?.executeBehaviors { (behavior: PageMoleculeTransformationBehavior) in + behavior.willSetupMolecule(with: titleViewModel, updating: nil) + } + + guard let molecule = ModelRegistry.createMolecule(titleViewModel, delegateObject: delegate, additionalData: nil) else { return } + + viewController.navigationItem.titleView = molecule + + behaviorHandler?.executeBehaviors { (behavior: PageMoleculeTransformationBehavior) in + behavior.didSetupMolecule(view: molecule, withModel: titleViewModel) } } diff --git a/MVMCoreUI/CustomPrimitives/Color.swift b/MVMCoreUI/CustomPrimitives/Color.swift index 42c7a600..b251f778 100644 --- a/MVMCoreUI/CustomPrimitives/Color.swift +++ b/MVMCoreUI/CustomPrimitives/Color.swift @@ -106,7 +106,7 @@ public final class Color: Codable { if colorString.hasPrefix("#") { hex = colorString.replacingOccurrences(of: "#", with: "") } else { - guard let hexString = UIColor.names[colorString]?.hex else { throw ColorError.badName(reason: "Check the spelling of your color.") } + guard let hexString = UIColor.names[colorString]?.hex else { throw ColorError.badName(reason: "Check the spelling of your color: \(colorString)") } hex = hexString.replacingOccurrences(of: "#", with: "") name = colorString } diff --git a/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleNotEqualsModel.swift b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleNotEqualsModel.swift new file mode 100644 index 00000000..1cd8bb74 --- /dev/null +++ b/MVMCoreUI/FormUIHelpers/Rules/Rules/RuleNotEqualsModel.swift @@ -0,0 +1,44 @@ +// +// RuleNotEqualsModel.swift +// MVMCoreUI +// +// Created by Marakanti, Keerthy on 26/09/22. +// Copyright © 2022 Verizon Wireless. All rights reserved. +// + +import Foundation + +public class RuleNotEqualsModel: RuleCompareModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + + public static var identifier: String = "notEquals" + public var type: String = RuleNotEqualsModel.identifier + public var ruleId: String? + public var fields: [String] + public var errorMessage: [String: String]? + + //-------------------------------------------------- + // MARK: - Initializer + //-------------------------------------------------- + + public init(fields: [String]) { + self.fields = fields + } + + //-------------------------------------------------- + // MARK: - Validation + //-------------------------------------------------- + + public func isValid(_ formField: FormFieldProtocol) -> Bool { + return false + } + + ///RuleCompareModelProtocol Method + public func compare(lhs: AnyHashable?, rhs: AnyHashable?) -> Bool { + return lhs != rhs + } + +} + diff --git a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift index 061c67fb..3e5357ea 100644 --- a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift +++ b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift @@ -244,6 +244,7 @@ open class CoreUIModelMapping: ModelMapping { ModelRegistry.register(RuleAnyValueChangedModel.self) ModelRegistry.register(RuleAllValueChangedModel.self) ModelRegistry.register(RuleEqualsModel.self) + ModelRegistry.register(RuleNotEqualsModel.self) ModelRegistry.register(RuleEqualsIgnoreCaseModel.self) ModelRegistry.register(RuleRegexModel.self) ModelRegistry.register(EnableFormFieldEffectModel.self) diff --git a/Scripts/download_dependencies.sh b/Scripts/download_dependencies.sh index cc6bc209..08ec31c0 100755 --- a/Scripts/download_dependencies.sh +++ b/Scripts/download_dependencies.sh @@ -8,7 +8,7 @@ # Create new aggregate builds if [ -z $ARTIFACTORY_URL ]; then - ARTIFACTORY_URL="https://oneartifactoryprod.verizon.com/artifactory" + ARTIFACTORY_URL="https://oneartifactoryci.verizon.com/artifactory" fi BUILD_DIR=$(xcodebuild -showBuildSettings -project ./MVMCoreUI.xcodeproj | grep -w -o 'BUILD_DIR = .*' | cut -d\ -f3-) diff --git a/Scripts/download_framework.sh b/Scripts/download_framework.sh index 5d602e0a..791e9ead 100755 --- a/Scripts/download_framework.sh +++ b/Scripts/download_framework.sh @@ -48,7 +48,7 @@ fi echo -e "Getting checksums..." echo -e "URL: ${URL}/api/storage/${REMOTEPATH}" JSON=$(curl --header "X-JFrog-Art-Api: ${ARTIFACTORY_APIKEY}" -X GET "${URL}/api/storage/${REMOTEPATH}") -CHECKSUM=$(echo "$JSON" | python -c 'import sys, json; print json.load(sys.stdin)["checksums"]["sha1"]') +CHECKSUM=$(echo "$JSON" | python3 -c 'import sys, json; print (json.load(sys.stdin)["checksums"]["sha1"])') if [[ -z "$CHECKSUM" ]]; then exit_with_error "No Checksum found in json: ${JSON}" fi diff --git a/Scripts/upload_core_ui_frameworks.sh b/Scripts/upload_core_ui_frameworks.sh index a8cf475b..b6092993 100755 --- a/Scripts/upload_core_ui_frameworks.sh +++ b/Scripts/upload_core_ui_frameworks.sh @@ -17,7 +17,7 @@ fi # Create new aggregate builds if [ -z $ARTIFACTORY_URL ]; then - ARTIFACTORY_URL="https://oneartifactoryprod.verizon.com/artifactory" + ARTIFACTORY_URL="https://oneartifactoryci.verizon.com/artifactory" fi # Upload