Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui into feature/native_mockups
This commit is contained in:
commit
6e37938abe
@ -595,9 +595,18 @@
|
||||
EA5124FF2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */; };
|
||||
EA7E67742758310500ABF773 /* EnableFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7E67732758310500ABF773 /* EnableFormFieldEffectModel.swift */; };
|
||||
EA7E67762758365300ABF773 /* UIUpdatableModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA7E67752758365300ABF773 /* UIUpdatableModelProtocol.swift */; };
|
||||
EA985C3E2970938F00F2FF2E /* Tilelet.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C3D2970938F00F2FF2E /* Tilelet.swift */; };
|
||||
EA985C402970939A00F2FF2E /* TileletModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C3F2970939A00F2FF2E /* TileletModel.swift */; };
|
||||
EA985C602970A3F000F2FF2E /* VDS.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA985C5F2970A3F000F2FF2E /* VDS.framework */; };
|
||||
EA985C642970A40E00F2FF2E /* VDSTypographyTokens.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = EA985C632970A40E00F2FF2E /* VDSTypographyTokens.xcframework */; };
|
||||
EA985C852981AA9C00F2FF2E /* VDS-Enums+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C842981AA9C00F2FF2E /* VDS-Enums+Codable.swift */; };
|
||||
EA985C872981AB0F00F2FF2E /* VDS-Tilelet+Codable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C862981AB0F00F2FF2E /* VDS-Tilelet+Codable.swift */; };
|
||||
EA985C892981AB7100F2FF2E /* VDS-TextStyle.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C882981AB7100F2FF2E /* VDS-TextStyle.swift */; };
|
||||
EA985C8B2983259900F2FF2E /* VDS-LabelAttributeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA985C8A2983259900F2FF2E /* VDS-LabelAttributeModel.swift */; };
|
||||
EAA0CFAF275E7D8000D65EB0 /* FormFieldEffectProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA0CFAE275E7D8000D65EB0 /* FormFieldEffectProtocol.swift */; };
|
||||
EAA0CFB1275E823A00D65EB0 /* HideFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA0CFB0275E823A00D65EB0 /* HideFormFieldEffectModel.swift */; };
|
||||
EAA0CFB3275E831E00D65EB0 /* DisableFormFieldEffectModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA0CFB2275E831E00D65EB0 /* DisableFormFieldEffectModel.swift */; };
|
||||
EAA78020290081320057DFDF /* VDSMoleculeViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAA7801F290081320057DFDF /* VDSMoleculeViewProtocol.swift */; };
|
||||
EAB14BC127D935F00012AB2C /* RuleCompareModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB14BC027D935F00012AB2C /* RuleCompareModelProtocol.swift */; };
|
||||
EAB14BC327D9378D0012AB2C /* RuleAnyModelProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB14BC227D9378D0012AB2C /* RuleAnyModelProtocol.swift */; };
|
||||
EABFC1412763BB8D00E78B40 /* FormLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = EABFC1402763BB8D00E78B40 /* FormLabel.swift */; };
|
||||
@ -1197,9 +1206,18 @@
|
||||
EA5124FE2436018E0051A3A4 /* BGImageHeadlineBodyButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BGImageHeadlineBodyButtonModel.swift; sourceTree = "<group>"; };
|
||||
EA7E67732758310500ABF773 /* EnableFormFieldEffectModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EnableFormFieldEffectModel.swift; sourceTree = "<group>"; };
|
||||
EA7E67752758365300ABF773 /* UIUpdatableModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIUpdatableModelProtocol.swift; sourceTree = "<group>"; };
|
||||
EA985C3D2970938F00F2FF2E /* Tilelet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tilelet.swift; sourceTree = "<group>"; };
|
||||
EA985C3F2970939A00F2FF2E /* TileletModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TileletModel.swift; sourceTree = "<group>"; };
|
||||
EA985C5F2970A3F000F2FF2E /* VDS.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = VDS.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
EA985C632970A40E00F2FF2E /* VDSTypographyTokens.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDSTypographyTokens.xcframework; path = ../SharedFrameworks/VDSTypographyTokens.xcframework; sourceTree = "<group>"; };
|
||||
EA985C842981AA9C00F2FF2E /* VDS-Enums+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VDS-Enums+Codable.swift"; sourceTree = "<group>"; };
|
||||
EA985C862981AB0F00F2FF2E /* VDS-Tilelet+Codable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VDS-Tilelet+Codable.swift"; sourceTree = "<group>"; };
|
||||
EA985C882981AB7100F2FF2E /* VDS-TextStyle.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VDS-TextStyle.swift"; sourceTree = "<group>"; };
|
||||
EA985C8A2983259900F2FF2E /* VDS-LabelAttributeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "VDS-LabelAttributeModel.swift"; sourceTree = "<group>"; };
|
||||
EAA0CFAE275E7D8000D65EB0 /* FormFieldEffectProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormFieldEffectProtocol.swift; sourceTree = "<group>"; };
|
||||
EAA0CFB0275E823A00D65EB0 /* HideFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HideFormFieldEffectModel.swift; sourceTree = "<group>"; };
|
||||
EAA0CFB2275E831E00D65EB0 /* DisableFormFieldEffectModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DisableFormFieldEffectModel.swift; sourceTree = "<group>"; };
|
||||
EAA7801F290081320057DFDF /* VDSMoleculeViewProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VDSMoleculeViewProtocol.swift; sourceTree = "<group>"; };
|
||||
EAB14BC027D935F00012AB2C /* RuleCompareModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleCompareModelProtocol.swift; sourceTree = "<group>"; };
|
||||
EAB14BC227D9378D0012AB2C /* RuleAnyModelProtocol.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RuleAnyModelProtocol.swift; sourceTree = "<group>"; };
|
||||
EABFC1402763BB8D00E78B40 /* FormLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FormLabel.swift; sourceTree = "<group>"; };
|
||||
@ -1214,7 +1232,9 @@
|
||||
files = (
|
||||
D29DF0E621E4F3C7003B2FB9 /* MVMCore.framework in Frameworks */,
|
||||
AFE4A1D127DFB5EE00C458D0 /* VDSColorTokens.xcframework in Frameworks */,
|
||||
EA985C602970A3F000F2FF2E /* VDS.framework in Frameworks */,
|
||||
187FEB2A2844D2A600BF29C2 /* VDSFormControlsTokens.xcframework in Frameworks */,
|
||||
EA985C642970A40E00F2FF2E /* VDSTypographyTokens.xcframework in Frameworks */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@ -1605,6 +1625,10 @@
|
||||
D2ED27E7254B0CE600A1C293 /* UIAlertControllerStyle+Extension.swift */,
|
||||
D2E0FFF726AF68530085D696 /* UITableViewRowAnimation+Extension.swift */,
|
||||
4457904D27ECE989002B1E1E /* UIImageRenderingMode+Extension.swift */,
|
||||
EA985C842981AA9C00F2FF2E /* VDS-Enums+Codable.swift */,
|
||||
EA985C862981AB0F00F2FF2E /* VDS-Tilelet+Codable.swift */,
|
||||
EA985C882981AB7100F2FF2E /* VDS-TextStyle.swift */,
|
||||
EA985C8A2983259900F2FF2E /* VDS-LabelAttributeModel.swift */,
|
||||
);
|
||||
path = Extensions;
|
||||
sourceTree = "<group>";
|
||||
@ -2058,6 +2082,8 @@
|
||||
D29DF0E421E4F3C7003B2FB9 /* Frameworks */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA985C632970A40E00F2FF2E /* VDSTypographyTokens.xcframework */,
|
||||
EA985C5F2970A3F000F2FF2E /* VDS.framework */,
|
||||
187FEB292844D2A600BF29C2 /* VDSFormControlsTokens.xcframework */,
|
||||
AFE4A1D027DFB5EE00C458D0 /* VDSColorTokens.xcframework */,
|
||||
D29DF0E521E4F3C7003B2FB9 /* MVMCore.framework */,
|
||||
@ -2255,6 +2281,8 @@
|
||||
AA37CBD42519072F0027344C /* Stars.swift */,
|
||||
AA07EA902510A442009A2AE3 /* StarModel.swift */,
|
||||
AA07EA922510A451009A2AE3 /* Star.swift */,
|
||||
EA985C3D2970938F00F2FF2E /* Tilelet.swift */,
|
||||
EA985C3F2970939A00F2FF2E /* TileletModel.swift */,
|
||||
);
|
||||
path = Views;
|
||||
sourceTree = "<group>";
|
||||
@ -2452,6 +2480,7 @@
|
||||
D2B9D0E3265EEE9D0084735C /* MoleculeListProtocol.swift */,
|
||||
011B58EE23A2AA850085F53C /* ModelProtocols */,
|
||||
27559EFB27D691D3000836C1 /* ViewMaskingProtocol.swift */,
|
||||
EAA7801F290081320057DFDF /* VDSMoleculeViewProtocol.swift */,
|
||||
);
|
||||
path = Protocols;
|
||||
sourceTree = "<group>";
|
||||
@ -2735,6 +2764,7 @@
|
||||
D253BB8A24574CC5002DE544 /* StackModel.swift in Sources */,
|
||||
EAB14BC127D935F00012AB2C /* RuleCompareModelProtocol.swift in Sources */,
|
||||
011D95A924057AC7000E3791 /* FormGroupWatcherFieldProtocol.swift in Sources */,
|
||||
EA985C892981AB7100F2FF2E /* VDS-TextStyle.swift in Sources */,
|
||||
BB2BF0EA2452A9BB001D0FC2 /* ListDeviceComplexButtonSmall.swift in Sources */,
|
||||
D20C700B250BFDE40095B21C /* MVMCoreUITopAlertView+Extension.swift in Sources */,
|
||||
D236E5B4241FEB1000C38625 /* ListTwoColumnPriceDescription.swift in Sources */,
|
||||
@ -2759,6 +2789,7 @@
|
||||
012A88AD238C418100FE3DA1 /* TemplateProtocol.swift in Sources */,
|
||||
BB6C6AC1242232DF005F7224 /* ListOneColumnTextWithWhitespaceDividerTall.swift in Sources */,
|
||||
32D2609724C19E2100B56344 /* LockupsPlanSMLXLModel.swift in Sources */,
|
||||
EA985C872981AB0F00F2FF2E /* VDS-Tilelet+Codable.swift in Sources */,
|
||||
D2092351244F7BE80044AD09 /* ThreeLayerCenterTemplateModel.swift in Sources */,
|
||||
D21B7F77243BB70700051ABF /* MoleculeCollectionItemModel.swift in Sources */,
|
||||
AAB9C10A243496DD00151545 /* RadioSwatch.swift in Sources */,
|
||||
@ -2777,7 +2808,9 @@
|
||||
D2E2A99D23DA3217000B42E6 /* UIStackViewAlignment+Extension.swift in Sources */,
|
||||
01EB369423609801006832FA /* HeadlineBodyModel.swift in Sources */,
|
||||
D2A92884241ACB25004E01C6 /* ProgrammaticScrollViewController.swift in Sources */,
|
||||
EA985C3E2970938F00F2FF2E /* Tilelet.swift in Sources */,
|
||||
D23A90002612347A007E14CE /* PageBehaviorHandlerModelProtocol.swift in Sources */,
|
||||
EAA78020290081320057DFDF /* VDSMoleculeViewProtocol.swift in Sources */,
|
||||
0A21DB7F235DECC500C160A2 /* EntryField.swift in Sources */,
|
||||
D2E2A99F23E07F8A000B42E6 /* PillButton.swift in Sources */,
|
||||
D2C5001921F8ECDD001DA659 /* MVMCoreUIViewControllerMappingObject.m in Sources */,
|
||||
@ -2962,6 +2995,7 @@
|
||||
FD99130028E21E4900542CC3 /* RuleNotEqualsModel.swift in Sources */,
|
||||
BBC0C4FD24811DBC0087C44F /* Tag.swift in Sources */,
|
||||
94C2D9842386F3F80006CF46 /* LabelAttributeModel.swift in Sources */,
|
||||
EA985C8B2983259900F2FF2E /* VDS-LabelAttributeModel.swift in Sources */,
|
||||
944589212385D6E900DE9FD4 /* DashLineModel.swift in Sources */,
|
||||
D2E2A99623D8CF85000B42E6 /* HeadlineBodyLinkToggleModel.swift in Sources */,
|
||||
C6FA7D5323C77A4A00A3614A /* StringAndMoleculeStack.swift in Sources */,
|
||||
@ -3084,6 +3118,7 @@
|
||||
BB2FB3BB247E7EBC00DF73CD /* TagCollectionViewCell.swift in Sources */,
|
||||
012A88C6238DA34000FE3DA1 /* ModuleMoleculeModel.swift in Sources */,
|
||||
94C2D9A123872BCC0006CF46 /* LabelAttributeUnderlineModel.swift in Sources */,
|
||||
EA985C852981AA9C00F2FF2E /* VDS-Enums+Codable.swift in Sources */,
|
||||
AAB8549824DC01BD00477C40 /* ListThreeColumnBillHistoryDividerModel.swift in Sources */,
|
||||
D20A9A5E2243D3E300ADE781 /* TwoButtonView.swift in Sources */,
|
||||
D2B1E3E522F37D6A0065F95C /* ImageHeadlineBody.swift in Sources */,
|
||||
@ -3170,6 +3205,7 @@
|
||||
D29E28DD23D7404C00ACEA85 /* ContainerHelper.swift in Sources */,
|
||||
012A88C2238D7BCA00FE3DA1 /* CarouselItemModel.swift in Sources */,
|
||||
27F6B08C26052AFF008529AA /* ParentMoleculeModelProtocol.swift in Sources */,
|
||||
EA985C402970939A00F2FF2E /* TileletModel.swift in Sources */,
|
||||
0AB764D324460FA400E7FE72 /* UIPickerView+Extension.swift in Sources */,
|
||||
D29DF29E21E7AE3B003B2FB9 /* MFStyler.m in Sources */,
|
||||
94C661D923CCF4B400D9FE5B /* LeftRightLabelModel.swift in Sources */,
|
||||
|
||||
@ -314,7 +314,7 @@ import MVMCore
|
||||
}
|
||||
|
||||
/// Adjust accessibility label based on state of Checkbox.
|
||||
func updateAccessibilityLabel() {
|
||||
public func updateAccessibilityLabel() {
|
||||
// Attention: This needs to be addressed with the accessibility team.
|
||||
// NOTE: Currently emptying description part of MVMCoreUICheckBox accessibility label to avoid crashing!
|
||||
if let state = MVMCoreUIUtility.hardcodedString(withKey: isSelected ? "checkbox_checked_state" : "checkbox_unchecked_state") {
|
||||
|
||||
@ -741,36 +741,6 @@ public typealias ActionBlock = () -> ()
|
||||
clauses.append(ActionableClause(range: range, actionBlock: actionBlock, accessibilityID: accessibleAction?.hash ?? -1))
|
||||
}
|
||||
|
||||
/**
|
||||
Provides a text container and layout manager of how the text would appear on screen.
|
||||
They are used in tandem to derive low-level TextKit results of the label.
|
||||
*/
|
||||
public func abstractTextContainer() -> (NSTextContainer, NSLayoutManager, NSTextStorage)? {
|
||||
|
||||
// Must configure the attributed string to translate what would appear on screen to accurately analyze.
|
||||
guard let attributedText = attributedText else { return nil }
|
||||
|
||||
let paragraph = NSMutableParagraphStyle()
|
||||
paragraph.alignment = textAlignment
|
||||
|
||||
let stagedAttributedString = NSMutableAttributedString(attributedString: attributedText)
|
||||
stagedAttributedString.addAttributes([NSAttributedString.Key.paragraphStyle: paragraph], range: NSRange(location: 0, length: attributedText.string.count))
|
||||
|
||||
let textStorage = NSTextStorage(attributedString: stagedAttributedString)
|
||||
let layoutManager = NSLayoutManager()
|
||||
let textContainer = NSTextContainer(size: .zero)
|
||||
|
||||
layoutManager.addTextContainer(textContainer)
|
||||
textStorage.addLayoutManager(layoutManager)
|
||||
|
||||
textContainer.lineFragmentPadding = 0.0
|
||||
textContainer.lineBreakMode = lineBreakMode
|
||||
textContainer.maximumNumberOfLines = numberOfLines
|
||||
textContainer.size = bounds.size
|
||||
|
||||
return (textContainer, layoutManager, textStorage)
|
||||
}
|
||||
|
||||
public static func boundingRect(forCharacterRange range: NSRange, in label: Label) -> CGRect {
|
||||
|
||||
guard let abstractContainer = label.abstractTextContainer() else { return CGRect() }
|
||||
|
||||
@ -17,6 +17,7 @@ class LabelAttributeImageModel: LabelAttributeModel {
|
||||
var size: CGFloat?
|
||||
var name: String?
|
||||
var URL: String?
|
||||
var tintColor: Color?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
@ -34,6 +35,7 @@ class LabelAttributeImageModel: LabelAttributeModel {
|
||||
case size
|
||||
case name
|
||||
case URL
|
||||
case tintColor
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -55,6 +57,7 @@ class LabelAttributeImageModel: LabelAttributeModel {
|
||||
size = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .size)
|
||||
name = try typeContainer.decodeIfPresent(String.self, forKey: .name)
|
||||
URL = try typeContainer.decodeIfPresent(String.self, forKey: .URL)
|
||||
tintColor = try typeContainer.decodeIfPresent(Color.self, forKey: .tintColor)
|
||||
try super.init(from: decoder)
|
||||
}
|
||||
|
||||
@ -64,5 +67,6 @@ class LabelAttributeImageModel: LabelAttributeModel {
|
||||
try container.encodeIfPresent(size, forKey: .size)
|
||||
try container.encodeIfPresent(name, forKey: .name)
|
||||
try container.encodeIfPresent(URL, forKey: .URL)
|
||||
try container.encodeIfPresent(tintColor, forKey: .tintColor)
|
||||
}
|
||||
}
|
||||
|
||||
85
MVMCoreUI/Atomic/Atoms/Views/Tilelet.swift
Normal file
85
MVMCoreUI/Atomic/Atoms/Views/Tilelet.swift
Normal file
@ -0,0 +1,85 @@
|
||||
//
|
||||
// Tilet.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Matt Bruce on 1/12/23.
|
||||
// Copyright © 2023 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MVMCore
|
||||
import VDS
|
||||
import Combine
|
||||
|
||||
/**
|
||||
This class expects its height and width to be equal.
|
||||
*/
|
||||
open class Tilelet: VDS.Tilelet, VDSMoleculeViewProtocol{
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
public var viewModel: TileletModel!
|
||||
public var delegateObject: MVMCoreUIDelegateObject?
|
||||
public var additionalData: [AnyHashable: Any]?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
public convenience required init() {
|
||||
self.init(frame: .zero)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public
|
||||
//--------------------------------------------------
|
||||
public func viewModelDidUpdate() {
|
||||
color = viewModel.color
|
||||
padding = viewModel.padding
|
||||
aspectRatio = viewModel.aspectRatio
|
||||
width = viewModel.width
|
||||
textWidth = viewModel.textWidth
|
||||
textPercentage = viewModel.textPercentage
|
||||
titleModel = viewModel.titleModel(delegateObject: delegateObject, additionalData: additionalData)
|
||||
subTitleModel = viewModel.subTitleModel(delegateObject: delegateObject, additionalData: additionalData)
|
||||
badgeModel = viewModel.badge
|
||||
descriptiveIconModel = viewModel.descriptiveIcon
|
||||
directionalIconModel = viewModel.directionalIcon
|
||||
//setup action
|
||||
if let action = viewModel.action {
|
||||
//add the subscriber
|
||||
onClickSubscriber = publisher(for: .touchUpInside)
|
||||
.sink {[weak self] control in
|
||||
guard let self else { return }
|
||||
MVMCoreUIActionHandler.performActionUnstructured(with: action,
|
||||
sourceModel: self.viewModel,
|
||||
additionalData: self.additionalData,
|
||||
delegateObject: self.delegateObject)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - MVMCoreViewProtocol
|
||||
//--------------------------------------------------
|
||||
open func updateView(_ size: CGFloat) {}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - MoleculeViewProtocol
|
||||
//--------------------------------------------------
|
||||
//since this is a class func, we can't reference it directly
|
||||
public static func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
100
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Overrides
|
||||
//--------------------------------------------------
|
||||
open override func layoutSubviews() {
|
||||
super.layoutSubviews()
|
||||
// Accounts for any collection size changes
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
guard let self else { return }
|
||||
self.delegateObject?.moleculeDelegate?.moleculeLayoutUpdated(self)
|
||||
}
|
||||
}
|
||||
}
|
||||
103
MVMCoreUI/Atomic/Atoms/Views/TileletModel.swift
Normal file
103
MVMCoreUI/Atomic/Atoms/Views/TileletModel.swift
Normal file
@ -0,0 +1,103 @@
|
||||
//
|
||||
// TiletModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Matt Bruce on 1/12/23.
|
||||
// Copyright © 2023 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import VDS
|
||||
|
||||
open class TileletModel: MoleculeModelProtocol {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
public static var identifier: String = "tilelet"
|
||||
public var backgroundColor: Color?
|
||||
public var color: TileContainer.BackgroundColor
|
||||
public var padding: TileContainer.Padding
|
||||
public var aspectRatio: TileContainer.AspectRatio
|
||||
public var badge: Tilelet.BadgeModel?
|
||||
public var title: LabelModel?
|
||||
public var subTitle: LabelModel?
|
||||
public var descriptiveIcon: Tilelet.DescriptiveIcon?
|
||||
public var directionalIcon: Tilelet.DirectionalIcon?
|
||||
public var width: CGFloat?
|
||||
public var textWidth: CGFloat?
|
||||
public var textPercentage: CGFloat?
|
||||
public var action: ActionModelProtocol?
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case color
|
||||
case padding
|
||||
case aspectRatio
|
||||
case badge
|
||||
case title
|
||||
case subTitle
|
||||
case descriptiveIcon
|
||||
case directionalIcon
|
||||
case width
|
||||
case textWidth
|
||||
case textPercentage
|
||||
case action
|
||||
}
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
self.backgroundColor = try container.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
self.color = try container.decodeIfPresent(TileContainer.BackgroundColor.self, forKey: .color) ?? TileContainer.BackgroundColor.black
|
||||
self.padding = try container.decodeIfPresent(TileContainer.Padding.self, forKey: .padding) ?? TileContainer.Padding.padding4X
|
||||
self.aspectRatio = try container.decodeIfPresent(TileContainer.AspectRatio.self, forKey: .aspectRatio) ?? TileContainer.AspectRatio.none
|
||||
self.badge = try container.decodeIfPresent(Tilelet.BadgeModel.self, forKey: .badge)
|
||||
self.title = try container.decodeIfPresent(LabelModel.self, forKey: .title)
|
||||
self.subTitle = try container.decodeIfPresent(LabelModel.self, forKey: .subTitle)
|
||||
self.descriptiveIcon = try container.decodeIfPresent(Tilelet.DescriptiveIcon.self, forKey: .descriptiveIcon)
|
||||
self.directionalIcon = try container.decodeIfPresent(Tilelet.DirectionalIcon.self, forKey: .directionalIcon)
|
||||
self.width = try container.decodeIfPresent(CGFloat.self, forKey: .width)
|
||||
self.textWidth = try container.decodeIfPresent(CGFloat.self, forKey: .textWidth)
|
||||
self.textPercentage = try container.decodeIfPresent(CGFloat.self, forKey: .textPercentage)
|
||||
action = try container.decodeModelIfPresent(codingKey: .action)
|
||||
}
|
||||
|
||||
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)
|
||||
let style: Tilelet.TitleModel.TextStyle? = title.fontStyle?.vdsSubsetStyle()
|
||||
if let style {
|
||||
return .init(text: title.text, textAttributes: attrs, textStyle: style)
|
||||
} else {
|
||||
return .init(text: title.text, textAttributes: attrs)
|
||||
}
|
||||
}
|
||||
|
||||
public func subTitleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Tilelet.SubTitleModel? {
|
||||
guard let subTitle else { return nil }
|
||||
let style: Tilelet.SubTitleModel.TextStyle? = subTitle.fontStyle?.vdsSubsetStyle()
|
||||
if let style {
|
||||
return .init(text: subTitle.text, textStyle: style)
|
||||
} else {
|
||||
return .init(text: subTitle.text)
|
||||
}
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(color, forKey: .color)
|
||||
try container.encodeIfPresent(padding, forKey: .padding)
|
||||
try container.encodeIfPresent(aspectRatio, forKey: .aspectRatio)
|
||||
try container.encodeIfPresent(badge, forKey: .badge)
|
||||
try container.encodeIfPresent(title, forKey: .title)
|
||||
try container.encodeIfPresent(subTitle, forKey: .subTitle)
|
||||
try container.encodeIfPresent(descriptiveIcon, forKey: .descriptiveIcon)
|
||||
try container.encodeIfPresent(directionalIcon, forKey: .directionalIcon)
|
||||
try container.encodeIfPresent(width, forKey: .width)
|
||||
try container.encodeIfPresent(textWidth, forKey: .textWidth)
|
||||
try container.encodeIfPresent(textPercentage, forKey: .textPercentage)
|
||||
try container.encodeModelIfPresent(action, forKey: .action)
|
||||
}
|
||||
}
|
||||
18
MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift
Normal file
18
MVMCoreUI/Atomic/Extensions/VDS-Enums+Codable.swift
Normal file
@ -0,0 +1,18 @@
|
||||
//
|
||||
// VDS-Enums+Codable.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Matt Bruce on 1/25/23.
|
||||
// Copyright © 2023 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import VDS
|
||||
|
||||
extension Surface: Codable {}
|
||||
extension Badge.FillColor: Codable {}
|
||||
extension Icon.Name: Codable {}
|
||||
extension Icon.Size: Codable {}
|
||||
extension TileContainer.BackgroundColor: Codable {}
|
||||
extension TileContainer.Padding: Codable {}
|
||||
extension TileContainer.AspectRatio: Codable {}
|
||||
205
MVMCoreUI/Atomic/Extensions/VDS-LabelAttributeModel.swift
Normal file
205
MVMCoreUI/Atomic/Extensions/VDS-LabelAttributeModel.swift
Normal file
@ -0,0 +1,205 @@
|
||||
//
|
||||
// VDS-LabelAttributeModel.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Matt Bruce on 1/26/23.
|
||||
// Copyright © 2023 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import VDS
|
||||
import Combine
|
||||
|
||||
//Meant to be used to convert Any Array of type LabelAttributeModel
|
||||
extension Array where Element: MVMCoreUI.LabelAttributeModel {
|
||||
public func toVDSLabelAttributeModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> [any VDS.LabelAttributeModel] {
|
||||
var attributes: [any VDS.LabelAttributeModel] = []
|
||||
forEach { atomicLabelAttribute in
|
||||
if let attr = atomicLabelAttribute as? (any VDSLabelAttributeConvertable),
|
||||
let vds = attr.convertToVDSLabelAttirbute(delegateObject: delegateObject,
|
||||
additionalData: additionalData){
|
||||
attributes.append(vds)
|
||||
}
|
||||
}
|
||||
return attributes
|
||||
}
|
||||
}
|
||||
|
||||
//VDS Convertable Protocol and Extensions
|
||||
public protocol VDSLabelAttributeConvertable<LabelAttributeType> {
|
||||
associatedtype LabelAttributeType: VDS.LabelAttributeModel
|
||||
func convertToVDSLabelAttirbute(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> LabelAttributeType?
|
||||
}
|
||||
|
||||
extension LabelAttributeUnderlineModel: VDSLabelAttributeConvertable {
|
||||
|
||||
public func convertToVDSLabelAttirbute(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> UnderlineLabelAttribute? {
|
||||
guard let style = UnderlineLabelAttribute.Style(rawValue: style.rawValue) else { return nil }
|
||||
|
||||
var pattern: UnderlineLabelAttribute.Pattern?
|
||||
if let attrPattern = pattern {
|
||||
pattern = UnderlineLabelAttribute.Pattern(rawValue: attrPattern.rawValue)
|
||||
}
|
||||
|
||||
return VDS.UnderlineLabelAttribute(location: location,
|
||||
length: length,
|
||||
style: style,
|
||||
color: color?.uiColor,
|
||||
pattern: pattern)
|
||||
}
|
||||
}
|
||||
|
||||
extension LabelAttributeActionModel: VDSLabelAttributeConvertable {
|
||||
public func convertToVDSLabelAttirbute(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> ActionLabelAttribute? {
|
||||
var vdsAttribute = VDS.ActionLabelAttribute(location: location, length: length)
|
||||
vdsAttribute.subscriber = vdsAttribute.action.sink { [weak self] in
|
||||
guard let self else { return }
|
||||
MVMCoreUIActionHandler.performActionUnstructured(with: self.action,
|
||||
sourceModel: nil,
|
||||
additionalData: additionalData,
|
||||
delegateObject: delegateObject)
|
||||
}
|
||||
return vdsAttribute
|
||||
}
|
||||
}
|
||||
|
||||
extension LabelAttributeFontModel: VDSLabelAttributeConvertable {
|
||||
public func convertToVDSLabelAttirbute(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> TextStyleLabelAttribute? {
|
||||
|
||||
var textStyle: TextStyle?
|
||||
if let found = style?.vdsTextStyle() {
|
||||
textStyle = found
|
||||
} else if let name, let found = TextStyle(rawValue: name) {
|
||||
textStyle = found
|
||||
}
|
||||
|
||||
guard let textStyle else { return nil }
|
||||
|
||||
return TextStyleLabelAttribute(location: location,
|
||||
length: length,
|
||||
textStyle: textStyle)
|
||||
}
|
||||
}
|
||||
|
||||
extension LabelAttributeColorModel: VDSLabelAttributeConvertable {
|
||||
public func convertToVDSLabelAttirbute(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> ColorLabelAttribute? {
|
||||
guard let textColor else { return nil }
|
||||
return ColorLabelAttribute(location: location,
|
||||
length: length,
|
||||
color: textColor.uiColor)
|
||||
}
|
||||
}
|
||||
|
||||
extension LabelAttributeStrikeThroughModel: VDSLabelAttributeConvertable {
|
||||
public func convertToVDSLabelAttirbute(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> StrikeThroughLabelAttribute? {
|
||||
return StrikeThroughLabelAttribute(location: location,
|
||||
length: length)
|
||||
}
|
||||
}
|
||||
|
||||
extension LabelAttributeImageModel: VDSLabelAttributeConvertable {
|
||||
public func convertToVDSLabelAttirbute(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> AtomicImageLabelAttribute? {
|
||||
var frame: CGRect?
|
||||
if let size {
|
||||
frame = CGRect(x: 0, y: 0, width: size, height: size)
|
||||
}
|
||||
return AtomicImageLabelAttribute(location: location,
|
||||
length: length,
|
||||
imageName: name,
|
||||
imageURL: URL,
|
||||
frame: frame,
|
||||
tintColor: tintColor?.uiColor)
|
||||
}
|
||||
}
|
||||
|
||||
//Custom Atomic Additions for the ImageAttachment
|
||||
public class AtomicImageLabelAttribute: AttachmentLabelAttributeModel {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Enums
|
||||
//--------------------------------------------------
|
||||
public enum Error: Swift.Error {
|
||||
case bundleNotFound
|
||||
case imageNotFound(String)
|
||||
case imageNotSet
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
public var id = UUID()
|
||||
public var location: Int
|
||||
public var length: Int = 1
|
||||
public var imageName: String?
|
||||
public var imageURL: String?
|
||||
public var image: UIImage?
|
||||
public var frame: CGRect?
|
||||
public var tintColor: UIColor?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
public init(location: Int, length: Int = 1, imageName: String? = nil, imageURL: String? = nil,
|
||||
image: UIImage? = nil, frame: CGRect? = nil, tintColor: UIColor?) {
|
||||
self.location = location
|
||||
self.length = length
|
||||
self.imageName = imageName
|
||||
self.imageURL = imageURL
|
||||
self.image = image
|
||||
self.frame = frame
|
||||
self.tintColor = tintColor
|
||||
fetchImage()
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Equatable
|
||||
//--------------------------------------------------
|
||||
public static func == (lhs: AtomicImageLabelAttribute, rhs: AtomicImageLabelAttribute) -> Bool {
|
||||
lhs.isEqual(rhs)
|
||||
}
|
||||
|
||||
public func isEqual(_ equatable: AtomicImageLabelAttribute) -> Bool {
|
||||
return id == equatable.id && range == equatable.range && imageName == equatable.imageName && imageURL == equatable.imageURL
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Functions
|
||||
//--------------------------------------------------
|
||||
private func fetchImage() {
|
||||
if image != nil { return }
|
||||
|
||||
//get a local asset
|
||||
if let imageName {
|
||||
if let coreImage = MVMCoreCache.shared()?.getImageFromRegisteredBundles(imageName) {
|
||||
image = coreImage
|
||||
}
|
||||
|
||||
if let vdsImage = BundleManager.shared.image(for: imageName) {
|
||||
image = vdsImage
|
||||
}
|
||||
}//get from url
|
||||
else if let imageURL {
|
||||
DispatchQueue.global(qos: .default).async {
|
||||
MVMCoreCache.shared()?.getImage(imageURL, useWidth: false, widthForS7: 0, useHeight: false, heightForS7: 0, localFallbackImageName: nil) { [weak self] image, data, _ in
|
||||
DispatchQueue.main.sync {
|
||||
self?.image = image
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Functions
|
||||
//--------------------------------------------------
|
||||
public func getAttachment() throws -> NSTextAttachment {
|
||||
if let image {
|
||||
let attachment = NSTextAttachment()
|
||||
attachment.image = tintColor != nil ? image.withTintColor(tintColor!) : image
|
||||
attachment.bounds = frame ?? .init(x: 0, y: 0, width: image.size.width, height: image.size.height)
|
||||
return attachment
|
||||
} else {
|
||||
throw Error.imageNotSet
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
31
MVMCoreUI/Atomic/Extensions/VDS-TextStyle.swift
Normal file
31
MVMCoreUI/Atomic/Extensions/VDS-TextStyle.swift
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// VDS-TextStyle.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Matt Bruce on 1/25/23.
|
||||
// Copyright © 2023 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import VDS
|
||||
|
||||
extension Styler.Font {
|
||||
//Converts Legacy Font to a VDS.TextStyle
|
||||
public func vdsTextStyle() -> VDS.TextStyle? {
|
||||
let updatedRaw = rawValue.replacingOccurrences(of: "Regular", with: "")
|
||||
let newRaw = updatedRaw.prefix(1).lowercased() + updatedRaw.dropFirst()
|
||||
guard let style = VDS.TextStyle(rawValue: newRaw) else { return nil }
|
||||
return style
|
||||
}
|
||||
|
||||
public func vdsSubsetStyle<T: EnumSubset>() -> T? {
|
||||
guard let style = vdsTextStyle() else { return nil }
|
||||
guard let rawValue = style.rawValue as? T.RawValue,
|
||||
let found = T(rawValue: rawValue) else {
|
||||
print("Style: \(style.rawValue) is not in enum \(T.self)\ronly these cases exist:\r\(T.allCases)")
|
||||
return nil
|
||||
}
|
||||
return found
|
||||
}
|
||||
}
|
||||
|
||||
75
MVMCoreUI/Atomic/Extensions/VDS-Tilelet+Codable.swift
Normal file
75
MVMCoreUI/Atomic/Extensions/VDS-Tilelet+Codable.swift
Normal file
@ -0,0 +1,75 @@
|
||||
//
|
||||
// VDS-Tilelet+Codable.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Matt Bruce on 1/25/23.
|
||||
// Copyright © 2023 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import VDS
|
||||
|
||||
extension Tilelet.BadgeModel: Codable {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case text, fillColor, surface, numberOfLines, maxWidth
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let text = try container.decode(String.self, forKey: .text)
|
||||
let fillColor = try container.decodeIfPresent(Badge.FillColor.self, forKey: .fillColor) ?? .red
|
||||
let surface = try container.decodeIfPresent(Surface.self, forKey: .surface) ?? .light
|
||||
let numberOfLines = try container.decodeIfPresent(Int.self, forKey: .numberOfLines) ?? 0
|
||||
let maxWidth = try container.decodeIfPresent(CGFloat.self, forKey: .maxWidth)
|
||||
self.init(text: text, fillColor: fillColor, surface: surface, numberOfLines: numberOfLines, maxWidth: maxWidth)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(fillColor, forKey: .fillColor)
|
||||
try container.encode(surface, forKey: .surface)
|
||||
try container.encode(numberOfLines, forKey: .numberOfLines)
|
||||
try container.encodeIfPresent(maxWidth, forKey: .maxWidth)
|
||||
}
|
||||
}
|
||||
|
||||
extension Tilelet.DescriptiveIcon: Codable {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case name, size, surface
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let name = try container.decode(Icon.Name.self, forKey: .name)
|
||||
let size = try container.decodeIfPresent(Icon.Size.self, forKey: .size) ?? .medium
|
||||
let surface = try container.decodeIfPresent(Surface.self, forKey: .surface) ?? .dark
|
||||
self.init(name: name, size: size, surface: surface)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(name, forKey: .name)
|
||||
try container.encode(size, forKey: .size)
|
||||
try container.encode(surface, forKey: .surface)
|
||||
}
|
||||
}
|
||||
|
||||
extension Tilelet.DirectionalIcon: Codable {
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case size, surface
|
||||
}
|
||||
|
||||
public init(from decoder: Decoder) throws {
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let size = try container.decodeIfPresent(Icon.Size.self, forKey: .size) ?? .medium
|
||||
let surface = try container.decodeIfPresent(Surface.self, forKey: .surface) ?? .dark
|
||||
self.init(size: size, surface: surface)
|
||||
}
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(size, forKey: .size)
|
||||
try container.encode(surface, forKey: .surface)
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
|
||||
open class ListLeftVariableCheckboxBodyTextModel: ListItemModel, MoleculeModelProtocol {
|
||||
open class ListLeftVariableCheckboxBodyTextModel: ListItemModel, MoleculeModelProtocol, ParentMoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
@ -16,6 +16,10 @@ open class ListLeftVariableCheckboxBodyTextModel: ListItemModel, MoleculeModelPr
|
||||
public var checkbox: CheckboxModel
|
||||
public var headlineBody: HeadlineBodyModel
|
||||
|
||||
public var children: [MoleculeModelProtocol] {
|
||||
[checkbox, headlineBody]
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
32
MVMCoreUI/Atomic/Protocols/VDSMoleculeViewProtocol.swift
Normal file
32
MVMCoreUI/Atomic/Protocols/VDSMoleculeViewProtocol.swift
Normal file
@ -0,0 +1,32 @@
|
||||
//
|
||||
// VDSMoleculeViewProtocol.swift
|
||||
// MVMCoreUI
|
||||
//
|
||||
// Created by Matt Bruce on 10/19/22.
|
||||
// Copyright © 2022 Verizon Wireless. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import MVMCore
|
||||
|
||||
///-----------------------------------------------------------------------------
|
||||
///MARK: -- VDSMoleculeViewProtocol (Contract between VDS -> Atomic)
|
||||
///-----------------------------------------------------------------------------
|
||||
public protocol VDSMoleculeViewProtocol: MoleculeViewProtocol, MVMCoreViewProtocol {
|
||||
associatedtype ViewModel: MoleculeModelProtocol
|
||||
var viewModel: ViewModel! { get set }
|
||||
var delegateObject: MVMCoreUIDelegateObject? { get set }
|
||||
var additionalData: [AnyHashable: Any]? { get set }
|
||||
func viewModelDidUpdate()
|
||||
}
|
||||
|
||||
extension VDSMoleculeViewProtocol {
|
||||
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
guard let castedModel = model as? ViewModel else { return }
|
||||
self.delegateObject = delegateObject
|
||||
self.additionalData = additionalData
|
||||
viewModel = castedModel
|
||||
viewModelDidUpdate()
|
||||
}
|
||||
}
|
||||
|
||||
@ -132,9 +132,9 @@ import MVMCore
|
||||
try parsePageJSON()
|
||||
} catch let parsingError {
|
||||
// Log all parsing errors and fail load.
|
||||
handleLoggingFor(parsingError: parsingError)
|
||||
if let errorObject = MVMCoreErrorObject.createErrorObject(for: parsingError, location: MVMCoreLoadHandler.sharedGlobal()?.errorLocation(forRequest: loadObject)) {
|
||||
if let errorObject = MVMCoreLoadHandler.sharedGlobal()?.error(for: loadObject, causedBy: parsingError) {
|
||||
errorObject.messageToDisplay = MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorUnableToProcess)
|
||||
errorObject.messageToLog = describe(parsingError: parsingError)
|
||||
error.pointee = errorObject
|
||||
}
|
||||
return false
|
||||
@ -146,40 +146,54 @@ import MVMCore
|
||||
}
|
||||
}
|
||||
|
||||
///Check with behavior if it can continue
|
||||
do{
|
||||
let allFinishedProcessingLoad = try executeThrowingBehaviors {(behavior: PageMoleculeTransformationBehavior) in
|
||||
return try behavior.shouldFinishProcessingLoad(loadObject)
|
||||
}
|
||||
guard allFinishedProcessingLoad else { return false }
|
||||
} catch let behaviorError {
|
||||
if let errorObject = MVMCoreErrorObject.createErrorObject(for: behaviorError, location: MVMCoreLoadHandler.sharedGlobal()?.errorLocation(forRequest: loadObject)) {
|
||||
error.pointee = errorObject
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func handleLoggingFor(parsingError: Error) {
|
||||
func describe(parsingError: Error) -> String {
|
||||
if let registryError = parsingError as? ModelRegistry.Error {
|
||||
switch (registryError) {
|
||||
case .decoderErrorModelNotMapped(let identifier, let codingKey, let codingPath) where identifier != nil && codingKey != nil && codingPath != nil:
|
||||
MVMCoreLoggingHandler.shared()?.handleDebugMessage("Error parsing template: Model identifier \"\(identifier!)\" is not mapped for \"\(codingKey!.stringValue)\" @ \(codingPath!.map { return $0.stringValue })")
|
||||
return "Error parsing template. Model identifier \"\(identifier!)\" is not mapped for \"\(codingKey!.stringValue)\" @ \(codingPath!.map { return $0.stringValue })"
|
||||
|
||||
case .decoderErrorObjectNotPresent(let codingKey, codingPath: let codingPath):
|
||||
MVMCoreLoggingHandler.shared()?.handleDebugMessage("Error parsing template: Required model \"\(codingKey.stringValue)\" was not found @ \(codingPath.map { return $0.stringValue })")
|
||||
case .decoderErrorObjectNotPresent(let codingKey, let codingPath):
|
||||
return "Error parsing template. Required model \"\(codingKey.stringValue)\" was not found @ \(codingPath.map { return $0.stringValue })"
|
||||
|
||||
default:
|
||||
MVMCoreLoggingHandler.shared()?.handleDebugMessage("Error parsing template: Registry error: \(registryError)")
|
||||
return "Error parsing template. Registry error: \((registryError as NSError).localizedFailureReason ?? registryError.localizedDescription)"
|
||||
}
|
||||
}
|
||||
if let decodingError = parsingError as? DecodingError {
|
||||
switch (decodingError) {
|
||||
case .keyNotFound(let codingKey, let context):
|
||||
MVMCoreLoggingHandler.shared()?.handleDebugMessage("Error parsing template: Key \(codingKey.stringValue) was not found @ \(context.codingPath.map { return $0.stringValue })")
|
||||
return "Error parsing template. Required key \(codingKey.stringValue) was not found @ \(context.codingPath.map { return $0.stringValue })"
|
||||
|
||||
case .valueNotFound(_, let context):
|
||||
MVMCoreLoggingHandler.shared()?.handleDebugMessage("Error parsing template: Value not found @ \(context.codingPath.map { return $0.stringValue })")
|
||||
return "Error parsing template. Value not found @ \(context.codingPath.map { return $0.stringValue })"
|
||||
|
||||
case .typeMismatch(_, let context):
|
||||
MVMCoreLoggingHandler.shared()?.handleDebugMessage("Error parsing template: Type mismatch @ \(context.codingPath.map { return $0.stringValue })")
|
||||
return "Error parsing template. Value type mismatch @ \(context.codingPath.map { return $0.stringValue })"
|
||||
|
||||
case .dataCorrupted(let context):
|
||||
MVMCoreLoggingHandler.shared()?.handleDebugMessage("Error parsing template: Data corrupted @ \(context.codingPath.map { return $0.stringValue })")
|
||||
return "Error parsing template. Data corrupted @ \(context.codingPath.map { return $0.stringValue })"
|
||||
|
||||
@unknown default:
|
||||
MVMCoreLoggingHandler.shared()?.handleDebugMessage("Error parsing template: \(parsingError)")
|
||||
return "Error parsing template. \((parsingError as NSError).localizedFailureReason ?? parsingError.localizedDescription)"
|
||||
}
|
||||
}
|
||||
return "Error parsing template. \((parsingError as NSError).localizedFailureReason ?? parsingError.localizedDescription)"
|
||||
}
|
||||
|
||||
open func parsePageJSON() throws { }
|
||||
@ -200,7 +214,8 @@ import MVMCore
|
||||
}
|
||||
|
||||
guard modulesRequired.count == 0 else {
|
||||
if let errorObject = MVMCoreErrorObject(title: nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorCritical), messageToLog: modulesRequired.description, code: ErrorCode.requiredModuleNotPresent.rawValue, domain: ErrorDomainNative, location: MVMCoreLoadHandler.sharedGlobal()?.errorLocation(forRequest: loadObject!)) {
|
||||
if let loadObject = loadObject, let errorObject = MVMCoreLoadHandler.sharedGlobal()?.error(for: loadObject, withTitle:nil, message: MVMCoreGetterUtility.hardcodedString(withKey: HardcodedErrorCritical), code: ErrorCode.requiredModuleNotPresent.rawValue, domain: ErrorDomainNative) {
|
||||
errorObject.messageToLog = modulesRequired.description
|
||||
error.pointee = errorObject
|
||||
}
|
||||
return false
|
||||
@ -473,6 +488,14 @@ import MVMCore
|
||||
|
||||
open func handleAction(error: Error, model: ActionModelProtocol, additionalData: [AnyHashable : Any]?, delegateObject: DelegateObject?) {
|
||||
let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: MVMCoreActionHandler.getErrorLocation(with: delegateObject?.actionDelegate, actionType: model.actionType))!
|
||||
|
||||
switch (model) {
|
||||
case let model as ActionOpenPageModel:
|
||||
errorObject.silentError = model.background ?? false
|
||||
default:
|
||||
errorObject.silentError = false
|
||||
}
|
||||
|
||||
MVMCoreUIActionHandler.shared()?.defaultHandleActionError(errorObject, additionalData: additionalData)
|
||||
}
|
||||
|
||||
|
||||
@ -44,4 +44,8 @@ public extension PageBehaviorHandlerProtocol {
|
||||
func executeBehaviors<T>(_ behaviorBlock: (_ behavior: T) -> Void) {
|
||||
behaviors?.compactMap { $0 as? T }.forEach { behaviorBlock($0) }
|
||||
}
|
||||
|
||||
func executeThrowingBehaviors<T>(_ behaviourBlock: (_ behavior: T) throws -> Bool) throws -> Bool {
|
||||
return try behaviors?.compactMap({$0 as? T}).allSatisfy({ return try behaviourBlock($0) }) ?? true
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ public protocol PageMoleculeTransformationBehavior: PageBehaviorProtocol {
|
||||
func didSetupMolecule(view: MoleculeViewProtocol, withModel: MoleculeModelProtocol)
|
||||
func willSetupNavigationBar(with model: NavigationItemModelProtocol, updating view: UINavigationBar)
|
||||
func didSetupNavigationBar(view: UINavigationBar, with model: NavigationItemModelProtocol)
|
||||
func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject) throws -> Bool
|
||||
}
|
||||
|
||||
public extension PageMoleculeTransformationBehavior {
|
||||
@ -41,6 +42,7 @@ public extension PageMoleculeTransformationBehavior {
|
||||
func didSetupMolecule(view: MoleculeViewProtocol, withModel: MoleculeModelProtocol) {}
|
||||
func willSetupNavigationBar(with model: NavigationItemModelProtocol, updating view: UINavigationBar) {}
|
||||
func didSetupNavigationBar(view: UINavigationBar, with model: NavigationItemModelProtocol) {}
|
||||
func shouldFinishProcessingLoad(_ loadObject: MVMCoreLoadObject) throws -> Bool { return true }
|
||||
}
|
||||
|
||||
public protocol PageVisibilityBehavior: PageBehaviorProtocol {
|
||||
|
||||
@ -71,7 +71,8 @@ open class CoreUIModelMapping: ModelMapping {
|
||||
ModelRegistry.register(handler: WebView.self, for: WebViewModel.self)
|
||||
ModelRegistry.register(handler: LoadingSpinner.self, for: LoadingSpinnerModel.self)
|
||||
ModelRegistry.register(handler: Video.self, for: VideoModel.self)
|
||||
|
||||
ModelRegistry.register(handler: Tilelet.self, for: TileletModel.self)
|
||||
|
||||
// MARK:- Horizontal Combination Molecules
|
||||
ModelRegistry.register(handler: StringAndMoleculeView.self, for: StringAndMoleculeModel.self)
|
||||
ModelRegistry.register(handler: ImageHeadlineBody.self, for: ImageHeadlineBodyModel.self)
|
||||
|
||||
@ -41,6 +41,7 @@ import SafariServices
|
||||
open override func defaultHandleActionError(_ error: MVMCoreErrorObject, additionalData: [AnyHashable : Any]?) {
|
||||
super.defaultHandleActionError(error, additionalData: additionalData)
|
||||
guard !error.silentError else { return }
|
||||
error.silentError = true // Silence if this error is triggered again. (Legacy action handler flow.)
|
||||
Task(priority: .userInitiated) { @MainActor in
|
||||
let alertObject = MVMCoreAlertObject.init(popupAlertWithError: error, isGreedy: false)!
|
||||
MVMCoreAlertHandler.shared()?.showAlert(with: alertObject)
|
||||
|
||||
@ -15,6 +15,10 @@ UNIVERSAL_OUTPUTFOLDER="${BUILD_DIR}/universal"
|
||||
# Update to use .xcframework
|
||||
sed -i '' 's|MVMCore.framework \*\/ = {isa.*};|MVMCore.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = MVMCore.xcframework; path = ../SharedFrameworks/MVMCore.xcframework; sourceTree = "<group>"; };|g' ./MVMCoreUI.xcodeproj/project.pbxproj
|
||||
sed -i '' 's/MVMCore.framework/MVMCore.xcframework/g' ./MVMCoreUI.xcodeproj/project.pbxproj
|
||||
|
||||
sed -i '' 's|VDS.framework \*\/ = {isa.*};|VDS.xcframework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcframework; name = VDS.xcframework; path = ../SharedFrameworks/VDS.xcframework; sourceTree = "<group>"; };|g' ./MVMCoreUI.xcodeproj/project.pbxproj
|
||||
sed -i '' 's/VDS.framework/VDS.xcframework/g' ./MVMCoreUI.xcodeproj/project.pbxproj
|
||||
|
||||
sed -i '' "s|path = \.\.\/SharedFrameworks|path = ${FRAMEWORKS_DIR}|g" ./MVMCoreUI.xcodeproj/project.pbxproj
|
||||
|
||||
# Build device archive
|
||||
|
||||
@ -18,8 +18,10 @@ if [ ! -d $FRAMEWORKS_DIR ]; then
|
||||
mkdir -p $FRAMEWORKS_DIR
|
||||
fi
|
||||
|
||||
./Scripts/download_framework.sh $ARTIFACTORY_URL "$FRAMEWORKS_DIR/MVMCore.xcframework" BPHV_MobileFirst_IOS/com/vzw/hss/myverizon/MVMCore/3.0/MVMCore-3.0-Debug-SNAPSHOT.zip
|
||||
./Scripts/download_framework.sh $ARTIFACTORY_URL "$FRAMEWORKS_DIR/MVMCore.xcframework" BPHV_MobileFirst_IOS/com/vzw/hss/myverizon/MVMCore/3.1/MVMCore-3.1-Debug-SNAPSHOT.zip
|
||||
|
||||
./Scripts/download_framework.sh $ARTIFACTORY_URL "$FRAMEWORKS_DIR/VDSColorTokens.xcframework" GVJV_VDS_Maven/%40vds-tokens/ios/VDSColorTokens.1.0.6.xcframework.zip
|
||||
./Scripts/download_framework.sh $ARTIFACTORY_URL "$FRAMEWORKS_DIR/VDS.xcframework" BPHV_MobileFirst_IOS/com/vzw/hss/myverizon/VDS/1.0/VDS-1.0-Debug-SNAPSHOT.zip
|
||||
|
||||
./Scripts/download_framework.sh $ARTIFACTORY_URL "$FRAMEWORKS_DIR/VDSColorTokens.xcframework" GVJV_VDS_Maven/@vds-tokens/ios/VDSColorTokens.1.0.6.xcframework.zip
|
||||
|
||||
./Scripts/download_framework.sh $ARTIFACTORY_URL "$FRAMEWORKS_DIR/VDSFormControlsTokens.xcframework" GVJV_VDS_Maven/@vds-tokens/ios/VDSFormControlsTokens.1.0.7.xcframework.zip
|
||||
|
||||
Loading…
Reference in New Issue
Block a user