diff --git a/MVMCoreUI.xcodeproj/project.pbxproj b/MVMCoreUI.xcodeproj/project.pbxproj index fbb120aa..f3ba25ce 100644 --- a/MVMCoreUI.xcodeproj/project.pbxproj +++ b/MVMCoreUI.xcodeproj/project.pbxproj @@ -602,6 +602,10 @@ EA7AE5512C74EB4500107C74 /* CalendarViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE5502C74EB4500107C74 /* CalendarViewModel.swift */; }; EA7AE5532C74F1F600107C74 /* DatePickerEntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE5522C74F1F600107C74 /* DatePickerEntryField.swift */; }; EA7AE5552C74F20600107C74 /* DatePickerEntryFieldModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE5542C74F20600107C74 /* DatePickerEntryFieldModel.swift */; }; + EA7AE55C2C7D18A100107C74 /* BreadcrumbsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE55B2C7D18A100107C74 /* BreadcrumbsModel.swift */; }; + EA7AE55E2C7D234500107C74 /* Breadcrumbs.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE55D2C7D234500107C74 /* Breadcrumbs.swift */; }; + EA7AE5602C7E554700107C74 /* PaginationModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE55F2C7E554700107C74 /* PaginationModel.swift */; }; + EA7AE5622C7E555D00107C74 /* Pagination.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7AE5612C7E555D00107C74 /* Pagination.swift */; }; EA7D81602B2B6E6800D29F9E /* Icon.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7D815F2B2B6E6800D29F9E /* Icon.swift */; }; EA7D81622B2B6E7F00D29F9E /* IconModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7D81612B2B6E7F00D29F9E /* IconModel.swift */; }; EA7D81642B2BABCB00D29F9E /* TooltipModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7D81632B2BABCB00D29F9E /* TooltipModel.swift */; }; @@ -1239,6 +1243,10 @@ EA7AE5502C74EB4500107C74 /* CalendarViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CalendarViewModel.swift; sourceTree = ""; }; EA7AE5522C74F1F600107C74 /* DatePickerEntryField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatePickerEntryField.swift; sourceTree = ""; }; EA7AE5542C74F20600107C74 /* DatePickerEntryFieldModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DatePickerEntryFieldModel.swift; sourceTree = ""; }; + EA7AE55B2C7D18A100107C74 /* BreadcrumbsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BreadcrumbsModel.swift; sourceTree = ""; }; + EA7AE55D2C7D234500107C74 /* Breadcrumbs.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Breadcrumbs.swift; sourceTree = ""; }; + EA7AE55F2C7E554700107C74 /* PaginationModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PaginationModel.swift; sourceTree = ""; }; + EA7AE5612C7E555D00107C74 /* Pagination.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Pagination.swift; sourceTree = ""; }; EA7D815F2B2B6E6800D29F9E /* Icon.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Icon.swift; sourceTree = ""; }; EA7D81612B2B6E7F00D29F9E /* IconModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IconModel.swift; sourceTree = ""; }; EA7D81632B2BABCB00D29F9E /* TooltipModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TooltipModel.swift; sourceTree = ""; }; @@ -2203,6 +2211,7 @@ D29DF10E21E67A77003B2FB9 /* Molecules */ = { isa = PBXGroup; children = ( + EA7AE55A2C7D188900107C74 /* Breadcrumbs */, D2EC7BD22527A1E400F540AF /* HeadersAndFooters */, D2CAC7C9251104CB00C75681 /* TopNotification */, D2509ED42472EE0B001BFB9D /* NavigationBar */, @@ -2364,6 +2373,8 @@ D20492A524329CE200A5EED6 /* LoadImageView.swift */, 0A51F3E02475CB73002E08B6 /* LoadingSpinnerModel.swift */, 0A51F3E12475CB73002E08B6 /* LoadingSpinner.swift */, + EA7AE55F2C7E554700107C74 /* PaginationModel.swift */, + EA7AE5612C7E555D00107C74 /* Pagination.swift */, AA37CBD2251907200027344C /* StarsModel.swift */, AA37CBD42519072F0027344C /* Stars.swift */, AA07EA902510A442009A2AE3 /* StarModel.swift */, @@ -2641,6 +2652,15 @@ path = Alerts; sourceTree = ""; }; + EA7AE55A2C7D188900107C74 /* Breadcrumbs */ = { + isa = PBXGroup; + children = ( + EA7AE55B2C7D18A100107C74 /* BreadcrumbsModel.swift */, + EA7AE55D2C7D234500107C74 /* Breadcrumbs.swift */, + ); + path = Breadcrumbs; + sourceTree = ""; + }; EAA0CFAD275E7D5A00D65EB0 /* FormFieldEffect */ = { isa = PBXGroup; children = ( @@ -2943,6 +2963,7 @@ D29DF2CF21E7C104003B2FB9 /* MFLoadingViewController.m in Sources */, D28A837B23C928DA00DFE4FC /* MoleculeListCellProtocol.swift in Sources */, D28BA74D248589C800B75CB8 /* TabPageModelProtocol.swift in Sources */, + EA7AE5602C7E554700107C74 /* PaginationModel.swift in Sources */, 608211282AC6B57E00C3FC39 /* MVMCoreUILoggingHandler.swift in Sources */, 014AA72F23C5059B006F3E93 /* ThreeLayerPageTemplateModel.swift in Sources */, 0A21DB91235E0EDB00C160A2 /* DigitBox.swift in Sources */, @@ -2968,8 +2989,10 @@ 525239C02407BCFF00454969 /* ListTwoColumnPriceDetailsModel.swift in Sources */, D2E2A99A23D8D6B4000B42E6 /* HeadlineBodyButtonModel.swift in Sources */, D202AFE6242A6A9C00E5BEDF /* UICollectionViewScrollPosition+Extension.swift in Sources */, + EA7AE55C2C7D18A100107C74 /* BreadcrumbsModel.swift in Sources */, D20F3B44252E00E4004B3F56 /* PageProtocol.swift in Sources */, AA37CBD3251907200027344C /* StarsModel.swift in Sources */, + EA7AE5622C7E555D00107C74 /* Pagination.swift in Sources */, 8D084AD22410BF7600951227 /* ListOneColumnFullWidthTextBodyText.swift in Sources */, 94C0150C2421564A005811A9 /* ActionCollapseNotificationModel.swift in Sources */, D2CAC7CB251104E100C75681 /* NotificationXButtonModel.swift in Sources */, @@ -2996,6 +3019,7 @@ AAE96FA525341F7D0037A989 /* ListStoreLocator.swift in Sources */, D282AABA224131D100C46919 /* MFTransparentGIFView.swift in Sources */, 944589232385DA9600DE9FD4 /* ImageViewModel.swift in Sources */, + EA7AE55E2C7D234500107C74 /* Breadcrumbs.swift in Sources */, D213347723843825008E41B3 /* Line.swift in Sources */, D2E2A99C23D8D975000B42E6 /* ImageHeadlineBodyModel.swift in Sources */, BB3BC1302550094500297977 /* ListLeftVariableIconWithRightCaretAllTextLinksModel.swift in Sources */, diff --git a/MVMCoreUI/Atomic/Atoms/Views/Icon.swift b/MVMCoreUI/Atomic/Atoms/Views/Icon.swift index a01c6b12..1ed0c376 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/Icon.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/Icon.swift @@ -36,6 +36,7 @@ open class Icon: VDS.Icon, VDSMoleculeViewProtocol{ size = viewModel.size customSize = viewModel.customSize name = viewModel.name + isAccessibilityElement = viewModel.isAccessibilityElement ?? true } //-------------------------------------------------- diff --git a/MVMCoreUI/Atomic/Atoms/Views/IconModel.swift b/MVMCoreUI/Atomic/Atoms/Views/IconModel.swift index ac8e6d9e..ee45a6df 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/IconModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/IconModel.swift @@ -35,4 +35,6 @@ open class IconModel: MoleculeModelProtocol { /// A custom size of the icon. public var customSize: Int? + + public var isAccessibilityElement: Bool? } diff --git a/MVMCoreUI/Atomic/Atoms/Views/Pagination.swift b/MVMCoreUI/Atomic/Atoms/Views/Pagination.swift new file mode 100644 index 00000000..7cb8c0c2 --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Views/Pagination.swift @@ -0,0 +1,57 @@ +// +// Pagination.swift +// MVMCoreUI +// +// Created by Matt Bruce on 8/27/24. +// Copyright © 2024 Verizon Wireless. All rights reserved. +// + +import Foundation +import VDS + +@objcMembers open class Pagination: VDS.Pagination, VDSMoleculeViewProtocol { + //------------------------------------------------------ + // MARK: - Properties + //------------------------------------------------------ + open var viewModel: PaginationModel! + open var delegateObject: MVMCoreUIDelegateObject? + open var additionalData: [AnyHashable : Any]? + + // Form Validation + open var fieldKey: String? + open var fieldValue: JSONValue? + open var groupName: String? + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + public convenience required init() { + self.init(frame:.zero) + } + + open override func setup() { + super.setup() + pageChangedPublisher + .sink { [weak self] control in + guard let self else { return } + viewModel?.selectedPage = control.selectedPage + }.store(in: &subscribers) + } + + open func viewModelDidUpdate() { + isEnabled = viewModel.enabled + surface = viewModel.surface + total = viewModel.totalPages + selectedPage = viewModel.selectedPage + } + + //-------------------------------------------------- + // MARK: - Actions + //-------------------------------------------------- + + //-------------------------------------------------- + // MARK: - MoleculeViewProtocol + //-------------------------------------------------- + public func updateView(_ size: CGFloat) {} + +} diff --git a/MVMCoreUI/Atomic/Atoms/Views/PaginationModel.swift b/MVMCoreUI/Atomic/Atoms/Views/PaginationModel.swift new file mode 100644 index 00000000..7027c7bb --- /dev/null +++ b/MVMCoreUI/Atomic/Atoms/Views/PaginationModel.swift @@ -0,0 +1,67 @@ +// +// PaginationModel.swift +// MVMCoreUI +// +// Created by Matt Bruce on 8/27/24. +// Copyright © 2024 Verizon Wireless. All rights reserved. +// + +import Foundation +import VDS +import MVMCore + +open class PaginationModel: MoleculeModelProtocol { + + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + open class var identifier: String { "pagination" } + open var moleculeName: String { Self.identifier } + open var backgroundColor: Color? + open var id: String = UUID().uuidString + + open var totalPages: Int = 0 + open var selectedPage: Int = 0 + open var enabled: Bool = true + open var inverted: Bool = false + open var surface: Surface { inverted ? .dark : .light } + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case totalPages + case selectedPage + case enabled + case inverted + } + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + totalPages = try container.decode(Int.self, forKey: .totalPages) + selectedPage = try container.decodeIfPresent(Int.self, forKey: .selectedPage) ?? 0 + enabled = try container.decodeIfPresent(Bool.self, forKey: .enabled) ?? false + inverted = try container.decodeIfPresent(Bool.self, forKey: .inverted) ?? false + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(totalPages, forKey: .totalPages) + try container.encode(selectedPage, forKey: .selectedPage) + try container.encode(enabled, forKey: .enabled) + try container.encode(inverted, forKey: .inverted) + } + + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { + guard let model = model as? Self else { return false } + return inverted == model.inverted + && enabled == model.enabled + && totalPages == model.totalPages + && selectedPage == model.selectedPage + } +} diff --git a/MVMCoreUI/Atomic/Atoms/Views/TileletModel.swift b/MVMCoreUI/Atomic/Atoms/Views/TileletModel.swift index e53066d0..f7b69c47 100644 --- a/MVMCoreUI/Atomic/Atoms/Views/TileletModel.swift +++ b/MVMCoreUI/Atomic/Atoms/Views/TileletModel.swift @@ -94,29 +94,34 @@ open class TileletModel: TileContainerBaseModel, Molec public func eyebrowModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Tilelet.EyebrowModel? { guard let eyebrow else { return nil } let attrs = eyebrow.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData) + var isBold: Bool = true do { if let style = eyebrow.fontStyle { + isBold = style.isBold() return .init(text: eyebrow.text, textColor: eyebrowColor, - textAttributes: attrs, isBold: style.isBold(), + textAttributes: attrs, + isBold: isBold, standardStyle: try style.vdsSubsetStyle()) } } catch MVMCoreError.errorObject(let object) { MVMCoreLoggingHandler.shared()?.addError(toLog: object) } catch { } - return .init(text: eyebrow.text, textColor: eyebrowColor, textAttributes: attrs) + return .init(text: eyebrow.text, textColor: eyebrowColor, textAttributes: attrs, isBold: isBold) } public func titleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Tilelet.TitleModel? { guard let title else { return nil } let attrs = title.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData) - + var isBold: Bool = true do { if let style = title.fontStyle { + isBold = style.isBold() return .init(text: title.text, textColor: titleColor, textAttributes: attrs, + isBold: isBold, standardStyle: try style.vdsSubsetStyle()) } @@ -124,7 +129,7 @@ open class TileletModel: TileContainerBaseModel, Molec MVMCoreLoggingHandler.shared()?.addError(toLog: object) } catch { } - return .init(text: title.text, textColor: titleColor, textAttributes: attrs) + return .init(text: title.text, textColor: titleColor, textAttributes: attrs, isBold: isBold) } public func subTitleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Tilelet.SubTitleModel? { diff --git a/MVMCoreUI/Atomic/Molecules/Breadcrumbs/Breadcrumbs.swift b/MVMCoreUI/Atomic/Molecules/Breadcrumbs/Breadcrumbs.swift new file mode 100644 index 00000000..5793caa4 --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/Breadcrumbs/Breadcrumbs.swift @@ -0,0 +1,56 @@ +// +// Breadcrumbs.swift +// MVMCoreUI +// +// Created by Matt Bruce on 8/26/24. +// Copyright © 2024 Verizon Wireless. All rights reserved. +// + +import Foundation +import VDS + +@objcMembers open class Breadcrumbs: VDS.Breadcrumbs, VDSMoleculeViewProtocol { + //------------------------------------------------------ + // MARK: - Properties + //------------------------------------------------------ + open var viewModel: BreadcrumbsModel! + open var delegateObject: MVMCoreUIDelegateObject? + open var additionalData: [AnyHashable : Any]? + + // Form Validation + open var fieldKey: String? + open var fieldValue: JSONValue? + open var groupName: String? + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + public convenience required init() { + self.init(frame:.zero) + } + + open func viewModelDidUpdate() { + isEnabled = viewModel.enabled + surface = viewModel.surface + breadcrumbModels = viewModel.breadcrumbs.compactMap { [unowned self] breadcrumb in + return .init(text: breadcrumb.text, + selected: breadcrumb.selected, + onClick: { _ in + MVMCoreUIActionHandler.performActionUnstructured(with: breadcrumb.action, + sourceModel: breadcrumb, + additionalData: self.additionalData, + delegateObject: self.delegateObject) + }) + } + } + + //-------------------------------------------------- + // MARK: - Actions + //-------------------------------------------------- + + //-------------------------------------------------- + // MARK: - MoleculeViewProtocol + //-------------------------------------------------- + public func updateView(_ size: CGFloat) {} + +} diff --git a/MVMCoreUI/Atomic/Molecules/Breadcrumbs/BreadcrumbsModel.swift b/MVMCoreUI/Atomic/Molecules/Breadcrumbs/BreadcrumbsModel.swift new file mode 100644 index 00000000..d4982de6 --- /dev/null +++ b/MVMCoreUI/Atomic/Molecules/Breadcrumbs/BreadcrumbsModel.swift @@ -0,0 +1,111 @@ +// +// BreadCrumbs.swift +// MVMCoreUI +// +// Created by Matt Bruce on 8/26/24. +// Copyright © 2024 Verizon Wireless. All rights reserved. +// + +import Foundation +import VDS +import MVMCore + +open class BreadcrumbsModel: MoleculeModelProtocol, ParentMoleculeModelProtocol { + + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + open class var identifier: String { "breadcrumbs" } + open var moleculeName: String { Self.identifier } + open var backgroundColor: Color? + open var id: String = UUID().uuidString + open var children: [any MoleculeModelProtocol] { breadcrumbs } + + open var breadcrumbs: [BreadcrumbModel] = [] + open var enabled: Bool = true + open var inverted: Bool = false + open var surface: Surface { inverted ? .dark : .light } + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case breadcrumbs + case enabled + case inverted + } + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + breadcrumbs = try container.decode([BreadcrumbModel].self, forKey: .breadcrumbs) + enabled = try container.decodeIfPresent(Bool.self, forKey: .enabled) ?? false + inverted = try container.decodeIfPresent(Bool.self, forKey: .inverted) ?? false + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(enabled, forKey: .enabled) + try container.encode(inverted, forKey: .inverted) + } + + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { + guard let model = model as? Self else { return false } + return inverted == model.inverted + && enabled == model.enabled + } +} + +open class BreadcrumbModel: MoleculeModelProtocol { + //-------------------------------------------------- + // MARK: - Properties + //-------------------------------------------------- + open class var identifier: String { "breadcrumb" } + open var moleculeName: String { Self.identifier } + open var backgroundColor: Color? + open var id: String = UUID().uuidString + + open var text: String = "" + open var selected: Bool = false + open var action: ActionModelProtocol + + + //-------------------------------------------------- + // MARK: - Keys + //-------------------------------------------------- + + private enum CodingKeys: String, CodingKey { + case text + case selected + case action + } + + //-------------------------------------------------- + // MARK: - Initializers + //-------------------------------------------------- + + required public init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + text = try container.decode(String.self, forKey: .text) + selected = try container.decodeIfPresent(Bool.self, forKey: .selected) ?? false + action = try container.decodeModel(codingKey: .action) + } + + public func encode(to encoder: Encoder) throws { + var container = encoder.container(keyedBy: CodingKeys.self) + try container.encode(text, forKey: .text) + try container.encode(selected, forKey: .selected) + try container.encodeModelIfPresent(action, forKey: .action) + } + + public func isEqual(to model: any ModelComparisonProtocol) -> Bool { + guard let model = model as? Self else { return false } + return text == model.text + && selected == model.selected + && action.isEqual(to: model.action) + } +} diff --git a/MVMCoreUI/Atomic/Molecules/OtherContainers/BGImageMolecule.swift b/MVMCoreUI/Atomic/Molecules/OtherContainers/BGImageMolecule.swift index 4aa811a1..485a82da 100644 --- a/MVMCoreUI/Atomic/Molecules/OtherContainers/BGImageMolecule.swift +++ b/MVMCoreUI/Atomic/Molecules/OtherContainers/BGImageMolecule.swift @@ -16,6 +16,8 @@ open class BGImageMolecule: MoleculeContainer { super.setupView() insertSubview(image, at: 0) NSLayoutConstraint.constraintPinSubview(toSuperview: image) + image.setContentCompressionResistancePriority(.defaultLow, for: .vertical) + image.imageView.setContentCompressionResistancePriority(.defaultLow, for: .vertical) } open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { diff --git a/MVMCoreUI/Atomic/Protocols/ModelProtocols/AccessibilityModelProtocol.swift b/MVMCoreUI/Atomic/Protocols/ModelProtocols/AccessibilityModelProtocol.swift index b233c71d..684c16b1 100644 --- a/MVMCoreUI/Atomic/Protocols/ModelProtocols/AccessibilityModelProtocol.swift +++ b/MVMCoreUI/Atomic/Protocols/ModelProtocols/AccessibilityModelProtocol.swift @@ -16,6 +16,7 @@ public protocol AccessibilityModelProtocol { var accessibilityText: String? { get set } var accessibilityValue: String? { get set } var accessibilityHint: String? { get set } + var isAccessibilityElement: Bool? { get set } } public extension AccessibilityModelProtocol { @@ -44,4 +45,9 @@ public extension AccessibilityModelProtocol { get { nil } set {} } + + var isAccessibilityElement: Bool? { + get { nil } + set { } + } } diff --git a/MVMCoreUI/BaseControllers/ViewController.swift b/MVMCoreUI/BaseControllers/ViewController.swift index 3febf61e..cb7a834a 100644 --- a/MVMCoreUI/BaseControllers/ViewController.swift +++ b/MVMCoreUI/BaseControllers/ViewController.swift @@ -187,7 +187,7 @@ import Combine // Log all parsing errors and fail load. if let errorObject = MVMCoreLoadHandler.sharedGlobal()?.error(for: loadObject, causedBy: parsingError) { errorObject.messageToDisplay = MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess) - errorObject.messageToLog = describe(parsingError: parsingError) + errorObject.messageToLog = describe(parsingError: parsingError, template: loadObject.pageJSON?["template"] as? String, pageType: loadObject.pageType) error.pointee = errorObject } return false @@ -215,11 +215,11 @@ import Combine return true } - func describe(parsingError: Error) -> String { + func describe(parsingError: Error, template: String?, pageType: String?) -> String { if let error = parsingError as? HumanReadableDecodingErrorProtocol { - return "Error parsing template. \(error.readableDescription)" + return "Error parsing \"\(template ?? "NA")\" template for pageType \"\(pageType ?? "NA")\". \(error.readableDescription)" } - return "Error parsing template. \((parsingError as NSError).localizedFailureReason ?? parsingError.localizedDescription)" + return "Error parsing \"\(template ?? "NA")\" template for pageType \"\(pageType ?? "NA")\". \((parsingError as NSError).localizedFailureReason ?? parsingError.localizedDescription)" } open func parsePageJSON(loadObject: MVMCoreLoadObject) throws -> PageModelProtocol { diff --git a/MVMCoreUI/CustomPrimitives/Color.swift b/MVMCoreUI/CustomPrimitives/Color.swift index 475e8aea..1c2240da 100644 --- a/MVMCoreUI/CustomPrimitives/Color.swift +++ b/MVMCoreUI/CustomPrimitives/Color.swift @@ -44,6 +44,7 @@ public final class Color: Codable { enum ColorError: Error { case badName(reason: String) + case invalidHex(reason: String) } //-------------------------------------------------- @@ -53,21 +54,21 @@ public final class Color: Codable { public init(uiColor: UIColor) { self.uiColor = uiColor hex = UIColor.hexString(for: uiColor) ?? "" - determineRGBA() + try? determineRGBA() } public init?(uiColor: UIColor?) { guard let uiColor = uiColor else { return nil } self.uiColor = uiColor hex = UIColor.hexString(for: uiColor) ?? "" - determineRGBA() + try? determineRGBA() } init?(name: String) { guard let colorTuple = UIColor.names[name] else { return nil } self.uiColor = colorTuple.uiColor self.hex = colorTuple.hex - determineRGBA() + try? determineRGBA() } public init?(colorString: String) throws { @@ -75,7 +76,7 @@ public final class Color: Codable { self.uiColor = components.color hex = components.hex name = components.name ?? "" - determineRGBA() + try determineRGBA() } //-------------------------------------------------- @@ -99,7 +100,7 @@ public final class Color: Codable { name = components.name ?? "" } - determineRGBA() + try determineRGBA() } public func encode(to encoder: Encoder) throws { @@ -135,9 +136,12 @@ public final class Color: Codable { return CGFloat(Int(hex[start..= 6 else { + throw ColorError.invalidHex(reason: "Invalid hex: \(hex)") + } let redStart = hex.startIndex let redEnd = hex.index(redStart, offsetBy: 2) diff --git a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift index 68494d90..db0f9e6c 100644 --- a/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift +++ b/MVMCoreUI/OtherHandlers/CoreUIModelMapping.swift @@ -142,7 +142,10 @@ open class CoreUIModelMapping: ModelMapping { ModelRegistry.register(NavigationItemModel.self) ModelRegistry.register(NavigationImageButtonModel.self) ModelRegistry.register(NavigationLabelButtonModel.self) - + ModelRegistry.register(handler: Pagination.self, for: PaginationModel.self) + ModelRegistry.register(handler: Breadcrumbs.self, for: BreadcrumbsModel.self) + ModelRegistry.register(BreadcrumbModel.self) + // MARK:- Other Organisms ModelRegistry.register(handler: Carousel.self, for: CarouselModel.self) ModelRegistry.register(handler: BarsIndicatorView.self, for: BarsCarouselIndicatorModel.self)