Merge branch 'feature/vds_batch_three' into 'develop'
VDS Batch Three ### Summary VDS Label / TitleLockup Integration ### JIRA Ticket https://onejira.verizon.com/browse/ONEAPP-4349 https://onejira.verizon.com/browse/ONEAPP-6241 Co-authored-by: Matt Bruce <matt.bruce@verizon.com> See merge request https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui/-/merge_requests/1059
This commit is contained in:
commit
0977794160
@ -19,6 +19,7 @@ import UIKit
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
public private(set) var titleLabel: FormLabel = {
|
public private(set) var titleLabel: FormLabel = {
|
||||||
let label = FormLabel()
|
let label = FormLabel()
|
||||||
|
label.setFontStyle(.RegularMicro)
|
||||||
label.setContentCompressionResistancePriority(.required, for: .vertical)
|
label.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
@ -28,6 +29,7 @@ import UIKit
|
|||||||
/// Provides contextual information on the TextField.
|
/// Provides contextual information on the TextField.
|
||||||
public private(set) var feedbackLabel: FormLabel = {
|
public private(set) var feedbackLabel: FormLabel = {
|
||||||
let label = FormLabel()
|
let label = FormLabel()
|
||||||
|
label.setFontStyle(.RegularMicro)
|
||||||
label.setContentCompressionResistancePriority(.required, for: .vertical)
|
label.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||||
return label
|
return label
|
||||||
}()
|
}()
|
||||||
@ -276,15 +278,13 @@ import UIKit
|
|||||||
|
|
||||||
backgroundColor = .clear
|
backgroundColor = .clear
|
||||||
isAccessibilityElement = false
|
isAccessibilityElement = false
|
||||||
titleLabel.font = Styler.Font.RegularMicro.getFont()
|
titleLabel.setFontStyle(.RegularMicro)
|
||||||
titleLabel.textColor = .mvmBlack
|
feedbackLabel.setFontStyle(.RegularMicro)
|
||||||
feedbackLabel.font = Styler.Font.RegularMicro.getFont()
|
errorLabel.setFontStyle(.RegularMicro)
|
||||||
feedbackLabel.textColor = .mvmBlack
|
titleLabel.text = nil
|
||||||
errorLabel.font = Styler.Font.RegularMicro.getFont()
|
feedbackLabel.text = nil
|
||||||
errorLabel.textColor = .mvmBlack
|
|
||||||
errorLabel.text = nil
|
errorLabel.text = nil
|
||||||
entryFieldContainer.disableAllBorders = false
|
entryFieldContainer.disableAllBorders = false
|
||||||
feedbackLabel.text = nil
|
|
||||||
entryFieldContainer.reset()
|
entryFieldContainer.reset()
|
||||||
entryFieldModel?.updateUI = nil
|
entryFieldModel?.updateUI = nil
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,11 +9,7 @@
|
|||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/// Subclass of label that helps with different states
|
/// Subclass of label that helps with different states
|
||||||
public class FormLabel: Label {
|
public class FormLabel: Label {
|
||||||
//properties used in setting label
|
|
||||||
private var delegateObject: MVMCoreUIDelegateObject?
|
|
||||||
private var additionalData: [AnyHashable: Any]?
|
|
||||||
|
|
||||||
//models that drive the label UI
|
//models that drive the label UI
|
||||||
private var formModel: FormLabelModel!
|
private var formModel: FormLabelModel!
|
||||||
|
|
||||||
|
|||||||
@ -8,15 +8,18 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import MVMCore
|
import MVMCore
|
||||||
|
import VDS
|
||||||
|
|
||||||
public typealias ActionBlock = () -> ()
|
public typealias ActionBlock = () -> ()
|
||||||
|
|
||||||
|
|
||||||
@objcMembers open class Label: UILabel, MVMCoreViewProtocol, MoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol, MFButtonProtocol, ViewMaskingProtocol {
|
@objcMembers open class Label: VDS.Label, VDSMoleculeViewProtocol, MVMCoreUIViewConstrainingProtocol, MFButtonProtocol, ViewMaskingProtocol {
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
|
open var viewModel: LabelModel!
|
||||||
|
open var delegateObject: MVMCoreUIDelegateObject?
|
||||||
|
open var additionalData: [AnyHashable : Any]?
|
||||||
|
|
||||||
public var makeWholeViewClickable = false
|
public var makeWholeViewClickable = false
|
||||||
|
|
||||||
@ -24,58 +27,23 @@ public typealias ActionBlock = () -> ()
|
|||||||
public var standardFontSize: CGFloat = 0.0
|
public var standardFontSize: CGFloat = 0.0
|
||||||
|
|
||||||
/// Set this to use a custom sizing object during updateView instead of the standard.
|
/// Set this to use a custom sizing object during updateView instead of the standard.
|
||||||
|
@available(*, deprecated, message: "VDS is maintaining scaleSize")
|
||||||
public var sizeObject: MFSizeObject?
|
public var sizeObject: MFSizeObject?
|
||||||
|
@available(*, deprecated, message: "VDS is maintaining scaleSize")
|
||||||
public var scaleSize: NSNumber?
|
public var scaleSize: NSNumber?
|
||||||
|
|
||||||
/// A specific text index to use as a unique marker.
|
/// A specific text index to use as a unique marker.
|
||||||
public var hero: Int?
|
public var hero: Int?
|
||||||
|
|
||||||
// Used for scaling the font in updateView.
|
|
||||||
private var originalAttributedString: NSAttributedString?
|
|
||||||
|
|
||||||
public var hasText: Bool {
|
|
||||||
guard let text = text, let attributedText = attributedText else { return false }
|
|
||||||
return !text.isEmpty || !attributedText.string.isEmpty
|
|
||||||
}
|
|
||||||
|
|
||||||
public var getRange: NSRange {
|
public var getRange: NSRange {
|
||||||
NSRange(location: 0, length: text?.count ?? 0)
|
NSRange(location: 0, length: text?.count ?? 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
public var shouldMaskWhileRecording: Bool = false
|
public var shouldMaskWhileRecording: Bool = false
|
||||||
|
|
||||||
public var model: MoleculeModelProtocol?
|
public var hasText: Bool {
|
||||||
//------------------------------------------------------
|
guard let text = text, let attributedText = attributedText else { return false }
|
||||||
// MARK: - Multi-Action Text
|
return !text.isEmpty || !attributedText.string.isEmpty
|
||||||
//------------------------------------------------------
|
|
||||||
|
|
||||||
/// Data store of the tappable ranges of the text.
|
|
||||||
public var clauses: [ActionableClause] = [] {
|
|
||||||
didSet {
|
|
||||||
isUserInteractionEnabled = !clauses.isEmpty
|
|
||||||
if clauses.count > 1 {
|
|
||||||
clauses.sort { first, second in
|
|
||||||
return first.range.location < second.range.location
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Used for tappable links in the text.
|
|
||||||
public struct ActionableClause {
|
|
||||||
public var range: NSRange
|
|
||||||
public var actionBlock: ActionBlock
|
|
||||||
public var accessibilityID: Int = 0
|
|
||||||
|
|
||||||
public func performAction() {
|
|
||||||
actionBlock()
|
|
||||||
}
|
|
||||||
|
|
||||||
public init(range: NSRange, actionBlock: @escaping ActionBlock, accessibilityID: Int = 0) {
|
|
||||||
self.range = range
|
|
||||||
self.actionBlock = actionBlock
|
|
||||||
self.accessibilityID = accessibilityID
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
@ -84,49 +52,27 @@ public typealias ActionBlock = () -> ()
|
|||||||
|
|
||||||
/// Sets the clauses array to empty.
|
/// Sets the clauses array to empty.
|
||||||
@objc public func setEmptyClauses() {
|
@objc public func setEmptyClauses() {
|
||||||
clauses = []
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
// MARK: - Initialization
|
// MARK: - Initialization
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
|
|
||||||
@objc public func setupView() {
|
@objc public required init() {
|
||||||
backgroundColor = .clear
|
super.init()
|
||||||
numberOfLines = 0
|
|
||||||
lineBreakMode = .byWordWrapping
|
|
||||||
translatesAutoresizingMaskIntoConstraints = false
|
|
||||||
clauses = []
|
|
||||||
accessibilityCustomActions = []
|
|
||||||
accessibilityTraits = .staticText
|
|
||||||
|
|
||||||
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(textLinkTapped))
|
|
||||||
tapGesture.numberOfTapsRequired = 1
|
|
||||||
addGestureRecognizer(tapGesture)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public init() {
|
|
||||||
super.init(frame: .zero)
|
|
||||||
setupView()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc required public init?(coder: NSCoder) {
|
@objc required public init?(coder: NSCoder) {
|
||||||
super.init(coder: coder)
|
super.init(coder: coder)
|
||||||
setupView()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc override public init(frame: CGRect) {
|
@objc override public init(frame: CGRect) {
|
||||||
super.init(frame: frame)
|
super.init(frame: frame)
|
||||||
setupView()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public init(fontStyle: Styler.Font, _ scale: Bool = true) {
|
public init(fontStyle: Styler.Font, _ scale: Bool = true) {
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
setupView()
|
setFontStyle(fontStyle, scale)
|
||||||
|
|
||||||
font = fontStyle.getFont(false)
|
|
||||||
textColor = fontStyle.color()
|
|
||||||
setScale(scale)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc convenience public init(standardFontSize size: CGFloat) {
|
@objc convenience public init(standardFontSize size: CGFloat) {
|
||||||
@ -145,7 +91,6 @@ public typealias ActionBlock = () -> ()
|
|||||||
|
|
||||||
required public init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
required public init(model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||||
super.init(frame: .zero)
|
super.init(frame: .zero)
|
||||||
setupView()
|
|
||||||
styleB2(true)
|
styleB2(true)
|
||||||
set(with: model, delegateObject, additionalData)
|
set(with: model, delegateObject, additionalData)
|
||||||
}
|
}
|
||||||
@ -236,12 +181,6 @@ public typealias ActionBlock = () -> ()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
enum LabelAlignment: String {
|
|
||||||
case center
|
|
||||||
case right
|
|
||||||
case left
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public func resetAttributeStyle() {
|
@objc public func resetAttributeStyle() {
|
||||||
/*
|
/*
|
||||||
* This is to address a reuse issue with iOS 13 and up.
|
* This is to address a reuse issue with iOS 13 and up.
|
||||||
@ -250,298 +189,121 @@ public typealias ActionBlock = () -> ()
|
|||||||
* appropriately called.
|
* appropriately called.
|
||||||
* Only other reference found of issue: https://www.thetopsites.net/article/58142205.shtml
|
* Only other reference found of issue: https://www.thetopsites.net/article/58142205.shtml
|
||||||
*/
|
*/
|
||||||
if let attributedText = attributedText, let text = text, !text.isEmpty {
|
if let text = text, !text.isEmpty {
|
||||||
let attributedString = NSMutableAttributedString(string: text)
|
|
||||||
let range = NSRange(location: 0, length: text.count)
|
//create the primary string
|
||||||
for attribute in attributedText.attributes(at: 0, effectiveRange: nil) {
|
let mutableText = NSMutableAttributedString.mutableText(for: text,
|
||||||
if attribute.key == .underlineStyle {
|
textStyle: textStyle,
|
||||||
attributedString.addAttribute(.underlineStyle, value: 0, range: range)
|
useScaledFont: useScaledFont,
|
||||||
}
|
textColor: textColorConfiguration.getColor(self),
|
||||||
if attribute.key == .strikethroughStyle {
|
alignment: textAlignment,
|
||||||
attributedString.addAttribute(.strikethroughStyle, value: 0, range: range)
|
lineBreakMode: lineBreakMode)
|
||||||
}
|
|
||||||
|
if let attributes = attributes {
|
||||||
|
mutableText.apply(attributes: attributes)
|
||||||
}
|
}
|
||||||
|
|
||||||
self.attributedText = attributedString
|
self.attributedText = mutableText
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject? = nil, _ additionalData: [AnyHashable: Any]? = nil) {
|
public func viewModelDidUpdate() {
|
||||||
|
shouldMaskWhileRecording = viewModel.shouldMaskRecordedView ?? false
|
||||||
|
text = viewModel.text
|
||||||
|
hero = viewModel.hero
|
||||||
|
Label.setLabel(self, withHTML: viewModel.html)
|
||||||
|
textAlignment = viewModel.textAlignment ?? .left
|
||||||
|
surface = viewModel.surface
|
||||||
|
|
||||||
clauses = []
|
makeWholeViewClickable = viewModel.makeWholeViewClickable ?? false
|
||||||
text = nil
|
if let backgroundColor = viewModel.backgroundColor {
|
||||||
attributedText = nil
|
|
||||||
originalAttributedString = nil
|
|
||||||
shouldMaskWhileRecording = model.shouldMaskRecordedView ?? false
|
|
||||||
|
|
||||||
guard let labelModel = model as? LabelModel else { return }
|
|
||||||
|
|
||||||
text = labelModel.text
|
|
||||||
if let accessibilityTraits = labelModel.accessibilityTraits {
|
|
||||||
self.accessibilityTraits = accessibilityTraits
|
|
||||||
}
|
|
||||||
|
|
||||||
resetAttributeStyle()
|
|
||||||
|
|
||||||
hero = labelModel.hero
|
|
||||||
Label.setLabel(self, withHTML: labelModel.html)
|
|
||||||
isAccessibilityElement = hasText
|
|
||||||
|
|
||||||
switch labelModel.textAlignment {
|
|
||||||
case .center:
|
|
||||||
textAlignment = .center
|
|
||||||
|
|
||||||
case .right:
|
|
||||||
textAlignment = .right
|
|
||||||
|
|
||||||
default:
|
|
||||||
textAlignment = .left
|
|
||||||
}
|
|
||||||
|
|
||||||
makeWholeViewClickable = labelModel.makeWholeViewClickable ?? false
|
|
||||||
if let backgroundColor = labelModel.backgroundColor {
|
|
||||||
self.backgroundColor = backgroundColor.uiColor
|
self.backgroundColor = backgroundColor.uiColor
|
||||||
}
|
}
|
||||||
|
|
||||||
if let accessibilityText = labelModel.accessibilityText {
|
if let style = viewModel.fontStyle?.vdsTextStyle() {
|
||||||
accessibilityLabel = accessibilityText
|
font = style.font
|
||||||
}
|
textStyle = style
|
||||||
|
} else if let fontName = viewModel.fontName {
|
||||||
if let fontStyle = labelModel.fontStyle {
|
// there is a TextStyle.defaultStyle
|
||||||
fontStyle.styleLabel(self, genericScaling: false)
|
let fontSize = viewModel.fontSize
|
||||||
standardFontSize = font.pointSize
|
if let fontSize {
|
||||||
} else {
|
|
||||||
let fontSize = labelModel.fontSize
|
|
||||||
if let fontSize = fontSize {
|
|
||||||
standardFontSize = fontSize
|
standardFontSize = fontSize
|
||||||
}
|
}
|
||||||
if let fontName = labelModel.fontName {
|
if let customStyle = style(for: fontName, pointSize: fontSize ?? standardFontSize), customStyle != textStyle {
|
||||||
font = MFFonts.mfFont(withName: fontName, size: fontSize ?? standardFontSize)
|
font = customStyle.font
|
||||||
} else if let fontSize = fontSize {
|
textStyle = customStyle
|
||||||
font = font.updateSize(fontSize)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let color = labelModel.textColor {
|
if let color = viewModel.textColor {
|
||||||
textColor = color.uiColor
|
textColorConfiguration = SurfaceColorConfiguration(color.uiColor, color.uiColor).eraseToAnyColorable()
|
||||||
}
|
}
|
||||||
|
|
||||||
if let lines = labelModel.numberOfLines {
|
if let lines = viewModel.numberOfLines {
|
||||||
numberOfLines = lines
|
numberOfLines = lines
|
||||||
}
|
}
|
||||||
|
|
||||||
if let attributes = labelModel.attributes, let labelText = text {
|
if let attributeModels = viewModel.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData) {
|
||||||
let attributedString = NSMutableAttributedString(string: labelText, attributes: [NSAttributedString.Key.font: font.updateSize(standardFontSize), NSAttributedString.Key.foregroundColor: textColor as UIColor])
|
attributes = attributeModels
|
||||||
|
}
|
||||||
for attribute in attributes {
|
|
||||||
guard let range = validateAttribute(range: NSRange(location: attribute.location, length: attribute.length) , in: attributedString, type: attribute.type)
|
}
|
||||||
else { continue }
|
|
||||||
|
/// See if the font that is currently set matches a VDS Font and if so grab the matching TextStyle or create custom TextStyle that
|
||||||
switch attribute {
|
/// that the Label will use moving forward.
|
||||||
case let underlineAtt as LabelAttributeUnderlineModel:
|
private func checkforFontChange() {
|
||||||
attributedString.addAttribute(.underlineStyle, value: underlineAtt.underlineValue.rawValue, range: range)
|
guard let customStyle = style(for: font.fontName, pointSize: font.pointSize), customStyle != textStyle
|
||||||
if let underlineColor = underlineAtt.color?.uiColor {
|
else { return }
|
||||||
attributedString.addAttribute(.underlineColor, value: underlineColor, range: range)
|
textStyle = customStyle
|
||||||
}
|
}
|
||||||
|
|
||||||
case _ as LabelAttributeStrikeThroughModel:
|
private func style(for fontName: String, pointSize: CGFloat) -> TextStyle? {
|
||||||
attributedString.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.thick.rawValue, range: range)
|
guard let vdsFont = Font.from(fontName: fontName),
|
||||||
attributedString.addAttribute(.baselineOffset, value: 0, range: range)
|
let customStyle = TextStyle.style(from: vdsFont, pointSize: pointSize)
|
||||||
|
else { return nil }
|
||||||
case let colorAtt as LabelAttributeColorModel:
|
return customStyle
|
||||||
if let colorHex = colorAtt.textColor {
|
}
|
||||||
attributedString.removeAttribute(.foregroundColor, range: range)
|
|
||||||
attributedString.addAttribute(.foregroundColor, value: colorHex.uiColor, range: range)
|
open override func updateView() {
|
||||||
}
|
checkforFontChange()
|
||||||
|
super.updateView()
|
||||||
case let imageAtt as LabelAttributeImageModel:
|
}
|
||||||
var fontSize = font.pointSize
|
|
||||||
if let attributeSize = imageAtt.size {
|
open override func updateAccessibility() {
|
||||||
fontSize = attributeSize
|
super.updateAccessibility()
|
||||||
}
|
if let accessibilityTraits = viewModel?.accessibilityTraits {
|
||||||
let imageName = imageAtt.name ?? "externalLink"
|
self.accessibilityTraits = accessibilityTraits
|
||||||
let imageAttachment: NSTextAttachment
|
}
|
||||||
|
|
||||||
if let url = imageAtt.URL {
|
if let accessibilityText = viewModel?.accessibilityText {
|
||||||
imageAttachment = Label.getTextAttachmentFrom(url: url, dimension: fontSize, label: self)
|
accessibilityLabel = accessibilityText
|
||||||
} else {
|
}
|
||||||
imageAttachment = Label.getTextAttachmentImage(name: imageName, dimension: fontSize)
|
}
|
||||||
}
|
|
||||||
|
@objc open override func reset() {
|
||||||
if let tintColor = imageAtt.tintColor {
|
super.reset()
|
||||||
imageAttachment.image = imageAttachment.image?.withTintColor(tintColor.uiColor, renderingMode: .alwaysTemplate)
|
}
|
||||||
}
|
|
||||||
|
@objc open func updateView(_ size: CGFloat) { }
|
||||||
// Confirm that the intended image location is within range.
|
|
||||||
if 0...labelText.count ~= imageAtt.location {
|
@objc open func setFont(_ font: UIFont, scale: Bool) {
|
||||||
let mutableString = NSMutableAttributedString()
|
self.font = font
|
||||||
mutableString.append(NSAttributedString(attachment: imageAttachment))
|
setScale(scale)
|
||||||
attributedString.insert(mutableString, at: imageAtt.location)
|
}
|
||||||
}
|
|
||||||
|
@objc open func setScale(_ scale: Bool) {
|
||||||
case let fontAtt as LabelAttributeFontModel:
|
if scale {
|
||||||
if let fontStyle = fontAtt.style {
|
standardFontSize = font.pointSize
|
||||||
attributedString.removeAttribute(.font, range: range)
|
} else {
|
||||||
attributedString.removeAttribute(.foregroundColor, range: range)
|
standardFontSize = 0
|
||||||
attributedString.addAttribute(.font, value: fontStyle.getFont(), range: range)
|
|
||||||
attributedString.addAttribute(.foregroundColor, value: fontStyle.color(), range: range)
|
|
||||||
} else {
|
|
||||||
let fontSize = fontAtt.size
|
|
||||||
var font: UIFont?
|
|
||||||
|
|
||||||
if let fontName = fontAtt.name {
|
|
||||||
font = MFFonts.mfFont(withName: fontName, size: fontSize ?? self.font.pointSize)
|
|
||||||
} else if let fontSize = fontSize {
|
|
||||||
font = self.font.updateSize(fontSize)
|
|
||||||
}
|
|
||||||
if let font = font {
|
|
||||||
attributedString.removeAttribute(.font, range: range)
|
|
||||||
attributedString.addAttribute(.font, value: font, range: range)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case let actionAtt as LabelAttributeActionModel:
|
|
||||||
addTappableLinkAttribute(range: NSRange(location: range.location, length: range.length)) {
|
|
||||||
MVMCoreUIActionHandler.performActionUnstructured(with: actionAtt.action, sourceModel: model, additionalData: additionalData, delegateObject: delegateObject)
|
|
||||||
}
|
|
||||||
addActionAttributes(range: range, string: attributedString)
|
|
||||||
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attributedText = attributedString
|
|
||||||
originalAttributedString = attributedText
|
|
||||||
}
|
}
|
||||||
self.model = labelModel
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public static func setUILabel(_ label: UILabel?, withJSON json: [AnyHashable: Any]?, delegate: DelegateObject?, additionalData: [AnyHashable: Any]?) {
|
@objc public static func setUILabel(_ label: UILabel?, withJSON json: [AnyHashable: Any]?, delegate: DelegateObject?, additionalData: [AnyHashable: Any]?) {
|
||||||
guard let label = label else { return }
|
guard let label = label as? Label,
|
||||||
|
let json = json as? [String: Any],
|
||||||
// Some properties can only be set on Label.
|
let labelModel = try? LabelModel.decode(jsonDict: json) else { return }
|
||||||
// Label fonts should not be scaled because it will be scaled in updateView.
|
label.set(with: labelModel, delegate as? MVMCoreUIDelegateObject, additionalData)
|
||||||
let mvmLabel = label as? Label
|
|
||||||
|
|
||||||
label.text = json?.optionalStringForKey(KeyText)
|
|
||||||
|
|
||||||
setLabel(label, withHTML: json?.optionalStringForKey("html"))
|
|
||||||
|
|
||||||
if let alignment = json?.optionalStringForKey("textAlignment") {
|
|
||||||
switch alignment {
|
|
||||||
case "center":
|
|
||||||
label.textAlignment = .center
|
|
||||||
case "right":
|
|
||||||
label.textAlignment = .right
|
|
||||||
default:
|
|
||||||
label.textAlignment = .left
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mvmLabel?.makeWholeViewClickable = json?.boolForKey("makeWholeViewClickable") ?? false
|
|
||||||
|
|
||||||
if let backgroundColorHex = json?.optionalStringForKey(KeyBackgroundColor), !backgroundColorHex.isEmpty {
|
|
||||||
label.backgroundColor = UIColor.mfGet(forHex: backgroundColorHex)
|
|
||||||
}
|
|
||||||
|
|
||||||
label.accessibilityLabel = json?.optionalStringForKey("accessibilityText")
|
|
||||||
|
|
||||||
if let fontStyle = json?.optionalStringForKey("fontStyle") {
|
|
||||||
MFStyler.style(label: label, styleString: fontStyle, genericScaling: mvmLabel == nil)
|
|
||||||
mvmLabel?.standardFontSize = label.font.pointSize
|
|
||||||
} else {
|
|
||||||
let fontSize = json?["fontSize"] as? CGFloat
|
|
||||||
if let fontSize = fontSize {
|
|
||||||
mvmLabel?.standardFontSize = fontSize
|
|
||||||
}
|
|
||||||
|
|
||||||
if let fontName = json?.optionalStringForKey("fontName") {
|
|
||||||
label.font = MFFonts.mfFont(withName: fontName, size: fontSize ?? mvmLabel?.standardFontSize ?? label.font.pointSize)
|
|
||||||
} else if let fontSize = fontSize {
|
|
||||||
label.font = label.font.updateSize(fontSize)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let textColorHex = json?.optionalStringForKey(KeyTextColor), !textColorHex.isEmpty {
|
|
||||||
label.textColor = UIColor.mfGet(forHex: textColorHex)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let attributes = json?.optionalArrayForKey("attributes"), let labelText = label.text {
|
|
||||||
let attributedString = NSMutableAttributedString(string: labelText,
|
|
||||||
attributes: [NSAttributedString.Key.font: mvmLabel?.font.updateSize(mvmLabel!.standardFontSize) ?? label.font as UIFont,
|
|
||||||
NSAttributedString.Key.foregroundColor: label.textColor as UIColor])
|
|
||||||
for case let attribute as [String: Any] in attributes {
|
|
||||||
guard let attributeType = attribute.optionalStringForKey(KeyType),
|
|
||||||
let location = attribute["location"] as? Int,
|
|
||||||
let length = attribute["length"] as? Int,
|
|
||||||
let range = validateAttribute(range: NSRange(location: location, length: length), in: attributedString, type: attributeType)
|
|
||||||
else { continue }
|
|
||||||
|
|
||||||
switch attributeType {
|
|
||||||
case "underline":
|
|
||||||
attributedString.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: range)
|
|
||||||
|
|
||||||
case "strikethrough":
|
|
||||||
attributedString.addAttribute(.strikethroughStyle, value: NSUnderlineStyle.thick.rawValue, range: range)
|
|
||||||
attributedString.addAttribute(.baselineOffset, value: 0, range: range)
|
|
||||||
|
|
||||||
case "color":
|
|
||||||
if let colorHex = attribute.optionalStringForKey(KeyTextColor), !colorHex.isEmpty {
|
|
||||||
attributedString.removeAttribute(.foregroundColor, range: range)
|
|
||||||
attributedString.addAttribute(.foregroundColor, value: UIColor.mfGet(forHex: colorHex), range: range)
|
|
||||||
}
|
|
||||||
case "image":
|
|
||||||
let fontSize = attribute["size"] as? CGFloat ?? label.font.pointSize
|
|
||||||
let imageName = attribute["name"] as? String ?? "externalLink"
|
|
||||||
let imageURL = attribute["URL"] as? String
|
|
||||||
let imageAttachment: NSTextAttachment
|
|
||||||
|
|
||||||
if let url = imageURL, let label = label as? Label {
|
|
||||||
imageAttachment = Label.getTextAttachmentFrom(url: url, dimension: fontSize, label: label)
|
|
||||||
} else {
|
|
||||||
imageAttachment = Label.getTextAttachmentImage(name: imageName, dimension: fontSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
let mutableString = NSMutableAttributedString()
|
|
||||||
mutableString.append(NSAttributedString(attachment: imageAttachment))
|
|
||||||
attributedString.insert(mutableString, at: location)
|
|
||||||
|
|
||||||
case "font":
|
|
||||||
if let fontStyle = attribute.optionalStringForKey("style") {
|
|
||||||
let styles = MFStyler.getAttributedString(for: "0", styleString: fontStyle, genericScaling: mvmLabel == nil)
|
|
||||||
attributedString.removeAttribute(.font, range: range)
|
|
||||||
attributedString.removeAttribute(.foregroundColor, range: range)
|
|
||||||
attributedString.addAttributes(styles.attributes(at: 0, effectiveRange: nil), range: range)
|
|
||||||
} else {
|
|
||||||
let fontSize = attribute["size"] as? CGFloat
|
|
||||||
var font: UIFont?
|
|
||||||
|
|
||||||
if let fontName = attribute.optionalStringForKey("name") {
|
|
||||||
font = MFFonts.mfFont(withName: fontName, size: fontSize ?? mvmLabel?.standardFontSize ?? label.font.pointSize)
|
|
||||||
} else if let fontSize = fontSize {
|
|
||||||
font = label.font.updateSize(fontSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let font = font {
|
|
||||||
attributedString.removeAttribute(.font, range: range)
|
|
||||||
attributedString.addAttribute(.font, value: font, range: range)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
case "action":
|
|
||||||
guard let actionLabel = label as? Label else { continue }
|
|
||||||
|
|
||||||
actionLabel.addActionAttributes(range: range, string: attributedString)
|
|
||||||
if let actionBlock = actionLabel.createActionBlockFor(actionMap: attribute, additionalData: additionalData, delegateObject: delegate) {
|
|
||||||
actionLabel.appendActionableClause(range: range, actionBlock: actionBlock)
|
|
||||||
}
|
|
||||||
|
|
||||||
default:
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
label.attributedText = attributedString
|
|
||||||
mvmLabel?.originalAttributedString = attributedString
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
@ -549,119 +311,50 @@ public typealias ActionBlock = () -> ()
|
|||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
|
|
||||||
public func setFontStyle(_ fontStyle: Styler.Font, _ scale: Bool = true) {
|
public func setFontStyle(_ fontStyle: Styler.Font, _ scale: Bool = true) {
|
||||||
fontStyle.styleLabel(self, genericScaling: false)
|
guard let style = fontStyle.vdsTextStyle() else { return }
|
||||||
|
textStyle = style
|
||||||
setScale(scale)
|
setScale(scale)
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
// MARK: - 2.0 Styling Methods
|
// MARK: - 2.0 Styling Methods
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
|
|
||||||
@objc public func styleH1(_ scale: Bool) {
|
@objc public func styleH1(_ scale: Bool) {
|
||||||
MFStyler.styleLabelH1(self, genericScaling: false)
|
setFontStyle(.H1, scale)
|
||||||
setScale(scale)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func styleH2(_ scale: Bool) {
|
@objc public func styleH2(_ scale: Bool) {
|
||||||
MFStyler.styleLabelH2(self, genericScaling: false)
|
setFontStyle(.H2, scale)
|
||||||
setScale(scale)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func styleH3(_ scale: Bool) {
|
@objc public func styleH3(_ scale: Bool) {
|
||||||
MFStyler.styleLabelH3(self, genericScaling: false)
|
setFontStyle(.H3, scale)
|
||||||
setScale(scale)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func styleH32(_ scale: Bool) {
|
@objc public func styleH32(_ scale: Bool) {
|
||||||
MFStyler.styleLabelH32(self, genericScaling: false)
|
setFontStyle(.H32, scale)
|
||||||
setScale(scale)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func styleB1(_ scale: Bool) {
|
@objc public func styleB1(_ scale: Bool) {
|
||||||
MFStyler.styleLabelB1(self, genericScaling: false)
|
setFontStyle(.B1, scale)
|
||||||
setScale(scale)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func styleB2(_ scale: Bool) {
|
@objc public func styleB2(_ scale: Bool) {
|
||||||
MFStyler.styleLabelB2(self, genericScaling: false)
|
setFontStyle(.B2, scale)
|
||||||
setScale(scale)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func styleB3(_ scale: Bool) {
|
@objc public func styleB3(_ scale: Bool) {
|
||||||
MFStyler.styleLabelB3(self, genericScaling: false)
|
setFontStyle(.B3, scale)
|
||||||
setScale(scale)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@objc public func styleB20(_ scale: Bool) {
|
@objc public func styleB20(_ scale: Bool) {
|
||||||
MFStyler.styleLabelB20(self, genericScaling: false)
|
setFontStyle(.B20, scale)
|
||||||
setScale(scale)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Will remove the values contained in attributedText.
|
}
|
||||||
func clearAttributes() {
|
|
||||||
guard let labelText = text, !labelText.isEmpty else { return }
|
|
||||||
guard let attributes = attributedText?.attributes(at: 0, longestEffectiveRange: nil, in: NSRange(location: 0, length: labelText.count))
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
let attributedString = NSMutableAttributedString(string: labelText)
|
|
||||||
|
|
||||||
for attribute in attributes {
|
|
||||||
attributedString.removeAttribute(attribute.key, range: NSRange(location: 0, length: labelText.count))
|
|
||||||
}
|
|
||||||
|
|
||||||
attributedText = attributedString
|
|
||||||
}
|
|
||||||
|
|
||||||
|
// Mark: - Old Helpers
|
||||||
@objc public func updateView(_ size: CGFloat) {
|
extension Label {
|
||||||
scaleSize = size as NSNumber
|
|
||||||
|
|
||||||
if let originalAttributedString = originalAttributedString {
|
|
||||||
let attributedString = NSMutableAttributedString(attributedString: originalAttributedString)
|
|
||||||
attributedString.removeAttribute(.font, range: NSRange(location: 0, length: attributedString.length))
|
|
||||||
|
|
||||||
// Loop the original attributed string, resize the fonts.
|
|
||||||
originalAttributedString.enumerateAttribute(.font, in: NSRange(location: 0, length: originalAttributedString.length), options: []) { value, range, stop in
|
|
||||||
|
|
||||||
if let fontObj = value as? UIFont, let stylerSize = MFStyler.sizeObjectGeneric(forCurrentDevice: fontObj.pointSize)?.getValueBased(onSize: size) {
|
|
||||||
attributedString.addAttribute(.font, value: fontObj.updateSize(stylerSize) as Any, range: range)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Loop the original attributed string, resize the image attachments.
|
|
||||||
originalAttributedString.enumerateAttribute(.attachment, in: NSRange(location: 0, length: originalAttributedString.length), options: []) { value, range, stop in
|
|
||||||
if let attachment = value as? NSTextAttachment,
|
|
||||||
let stylerSize = MFStyler.sizeObjectGeneric(forCurrentDevice: attachment.bounds.width)?.getValueBased(onSize: size) {
|
|
||||||
|
|
||||||
let dimension = round(stylerSize)
|
|
||||||
attachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
attributedText = attributedString
|
|
||||||
} else if !MVMCoreGetterUtility.fequal(a: Float(standardFontSize), b: 0.0), let sizeObject = sizeObject ?? MFStyler.sizeObjectGeneric(forCurrentDevice: standardFontSize) {
|
|
||||||
font = font.updateSize(sizeObject.getValueBased(onSize: size))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public func setFont(_ font: UIFont, scale: Bool) {
|
|
||||||
self.font = font
|
|
||||||
setScale(scale)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public func setScale(_ scale: Bool) {
|
|
||||||
if scale {
|
|
||||||
standardFontSize = font.pointSize
|
|
||||||
if let floatScale = scaleSize?.floatValue {
|
|
||||||
updateView(CGFloat(floatScale))
|
|
||||||
} else {
|
|
||||||
updateView(MVMCoreUIUtility.getWidth())
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
standardFontSize = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Appends an external link image to the end of the attributed string.
|
Appends an external link image to the end of the attributed string.
|
||||||
Will provide one whitespace to the left of the icon; adds 2 chars to the end of the string.
|
Will provide one whitespace to the left of the icon; adds 2 chars to the end of the string.
|
||||||
@ -693,7 +386,7 @@ public typealias ActionBlock = () -> ()
|
|||||||
|
|
||||||
self.attributedText = mutableString
|
self.attributedText = mutableString
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Retrieves an NSTextAttachment for NSAttributedString that is prepped to be inserted with the text.
|
Retrieves an NSTextAttachment for NSAttributedString that is prepped to be inserted with the text.
|
||||||
|
|
||||||
@ -709,47 +402,6 @@ public typealias ActionBlock = () -> ()
|
|||||||
return imageAttachment
|
return imageAttachment
|
||||||
}
|
}
|
||||||
|
|
||||||
static func getTextAttachmentFrom(url: String, dimension: CGFloat, label: Label) -> NSTextAttachment {
|
|
||||||
|
|
||||||
let imageAttachment = NSTextAttachment()
|
|
||||||
imageAttachment.bounds = CGRect(x: 0, y: 0, width: dimension, height: dimension)
|
|
||||||
|
|
||||||
DispatchQueue.global(qos: .default).async {
|
|
||||||
MVMCoreCache.shared()?.getImage(url, useWidth: false, widthForS7: 0, useHeight: false, heightForS7: 0, localFallbackImageName: nil) { image, data, _ in
|
|
||||||
|
|
||||||
DispatchQueue.main.sync {
|
|
||||||
imageAttachment.image = image
|
|
||||||
label.setNeedsDisplay()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return imageAttachment
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Call to detect in the attributedText contains an NSTextAttachment.
|
|
||||||
func containsTextAttachment() -> Bool {
|
|
||||||
|
|
||||||
guard let attributedText = attributedText else { return false }
|
|
||||||
|
|
||||||
var containsAttachment = false
|
|
||||||
|
|
||||||
attributedText.enumerateAttribute(.attachment, in: NSRange(location: 0, length: attributedText.length), options: []) { value, range, stop in
|
|
||||||
if value is NSTextAttachment {
|
|
||||||
containsAttachment = true
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return containsAttachment
|
|
||||||
}
|
|
||||||
|
|
||||||
func appendActionableClause(range: NSRange, actionBlock: @escaping ActionBlock) {
|
|
||||||
|
|
||||||
accessibilityTraits = .button
|
|
||||||
let accessibleAction = customAccessibilityAction(range: range)
|
|
||||||
clauses.append(ActionableClause(range: range, actionBlock: actionBlock, accessibilityID: accessibleAction?.hash ?? -1))
|
|
||||||
}
|
|
||||||
|
|
||||||
public static func boundingRect(forCharacterRange range: NSRange, in label: Label) -> CGRect {
|
public static func boundingRect(forCharacterRange range: NSRange, in label: Label) -> CGRect {
|
||||||
|
|
||||||
guard let abstractContainer = label.abstractTextContainer() else { return CGRect() }
|
guard let abstractContainer = label.abstractTextContainer() else { return CGRect() }
|
||||||
@ -793,25 +445,11 @@ public typealias ActionBlock = () -> ()
|
|||||||
|
|
||||||
return (textContainer, layoutManager, textStorage)
|
return (textContainer, layoutManager, textStorage)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MARK: - Atomization
|
// MARK: - Atomization
|
||||||
extension Label {
|
extension Label {
|
||||||
|
|
||||||
public func reset() {
|
|
||||||
text = nil
|
|
||||||
attributedText = nil
|
|
||||||
hero = nil
|
|
||||||
textAlignment = .left
|
|
||||||
originalAttributedString = nil
|
|
||||||
styleB2(true)
|
|
||||||
accessibilityCustomActions = []
|
|
||||||
clauses = []
|
|
||||||
accessibilityTraits = .staticText
|
|
||||||
numberOfLines = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
public func needsToBeConstrained() -> Bool { true }
|
public func needsToBeConstrained() -> Bool { true }
|
||||||
|
|
||||||
public func horizontalAlignment() -> UIStackView.Alignment { .leading }
|
public func horizontalAlignment() -> UIStackView.Alignment { .leading }
|
||||||
@ -821,19 +459,25 @@ extension Label {
|
|||||||
|
|
||||||
// MARK: - Multi-Link Functionality
|
// MARK: - Multi-Link Functionality
|
||||||
extension Label {
|
extension Label {
|
||||||
|
|
||||||
/// Applied to existing text. Removes underlines of tappable links and assoated actionable clauses.
|
/// Underlines the tappable region and stores the tap logic for interation.
|
||||||
@objc public func clearActionableClauses() {
|
private func setTextLinkState(range: NSRange, actionBlock: @escaping ActionBlock) {
|
||||||
guard let attributedText = attributedText else { return }
|
var textLink = ActionLabelAttribute(location: range.location, length: range.length)
|
||||||
let mutableAttributedString = NSMutableAttributedString(attributedString: attributedText)
|
textLink.subscriber = textLink
|
||||||
|
.action
|
||||||
clauses.forEach { clause in
|
.sink { _ in
|
||||||
mutableAttributedString.removeAttribute(NSAttributedString.Key.underlineStyle, range: clause.range)
|
actionBlock()
|
||||||
|
}
|
||||||
|
if var attributes {
|
||||||
|
attributes.append(textLink)
|
||||||
|
setNeedsUpdate()
|
||||||
|
} else {
|
||||||
|
attributes = [textLink]
|
||||||
}
|
}
|
||||||
|
}
|
||||||
self.attributedText = mutableAttributedString
|
|
||||||
accessibilityElements = []
|
@objc public func clearActionableClauses() {
|
||||||
clauses = []
|
attributes = attributes?.filter { !($0 is (any ActionLabelAttributeModel)) }
|
||||||
}
|
}
|
||||||
|
|
||||||
public func createActionBlockFor(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) -> ActionBlock? {
|
public func createActionBlockFor(actionMap: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?, delegateObject: DelegateObject?) -> ActionBlock? {
|
||||||
@ -846,24 +490,6 @@ extension Label {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addActionAttributes(range: NSRange, string: NSMutableAttributedString?) {
|
|
||||||
|
|
||||||
guard let string = string,
|
|
||||||
let range = validateAttribute(range: range, in: string)
|
|
||||||
else { return }
|
|
||||||
|
|
||||||
string.addAttributes([NSAttributedString.Key.underlineStyle: NSUnderlineStyle.single.rawValue], range: range)
|
|
||||||
}
|
|
||||||
|
|
||||||
fileprivate func setActionAttributes(range: NSRange) {
|
|
||||||
|
|
||||||
guard let attributedText = attributedText else { return }
|
|
||||||
|
|
||||||
let mutableAttributedString = NSMutableAttributedString(attributedString: attributedText)
|
|
||||||
addActionAttributes(range: range, string: mutableAttributedString)
|
|
||||||
self.attributedText = mutableAttributedString
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Provides an actionable range of text.
|
Provides an actionable range of text.
|
||||||
|
|
||||||
@ -902,113 +528,6 @@ extension Label {
|
|||||||
|
|
||||||
setTextLinkState(range: getRange, actionBlock: actionBlock)
|
setTextLinkState(range: getRange, actionBlock: actionBlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Underlines the tappable region and stores the tap logic for interation.
|
|
||||||
private func setTextLinkState(range: NSRange, actionBlock: @escaping ActionBlock) {
|
|
||||||
|
|
||||||
setActionAttributes(range: range)
|
|
||||||
appendActionableClause(range: range, actionBlock: actionBlock)
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc private func textLinkTapped(_ gesture: UITapGestureRecognizer) {
|
|
||||||
|
|
||||||
for clause in clauses {
|
|
||||||
// This determines if we tapped on the desired range of text.
|
|
||||||
if gesture.didTapAttributedTextInLabel(self, inRange: clause.range) {
|
|
||||||
clause.performAction()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: -
|
|
||||||
extension UITapGestureRecognizer {
|
|
||||||
|
|
||||||
func didTapAttributedTextInLabel(_ label: Label, inRange targetRange: NSRange) -> Bool {
|
|
||||||
|
|
||||||
// There would only ever be one clause to act on.
|
|
||||||
if label.makeWholeViewClickable {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let abstractContainer = label.abstractTextContainer() else { return false }
|
|
||||||
let textContainer = abstractContainer.0
|
|
||||||
let layoutManager = abstractContainer.1
|
|
||||||
|
|
||||||
let tapLocation = location(in: label)
|
|
||||||
let indexOfGlyph = layoutManager.glyphIndex(for: tapLocation, in: textContainer)
|
|
||||||
let intrinsicWidth = label.intrinsicContentSize.width
|
|
||||||
|
|
||||||
// Assert that tapped occured within acceptable bounds based on alignment.
|
|
||||||
switch label.textAlignment {
|
|
||||||
case .right:
|
|
||||||
if tapLocation.x < label.bounds.width - intrinsicWidth {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
case .center:
|
|
||||||
let halfBounds = label.bounds.width / 2
|
|
||||||
let halfIntrinsicWidth = intrinsicWidth / 2
|
|
||||||
|
|
||||||
if tapLocation.x > halfBounds + halfIntrinsicWidth {
|
|
||||||
return false
|
|
||||||
} else if tapLocation.x < halfBounds - halfIntrinsicWidth {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
default: // Left align
|
|
||||||
if tapLocation.x > intrinsicWidth {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Affirms that the tap occured in the desired rect of provided by the target range.
|
|
||||||
return layoutManager.boundingRect(forGlyphRange: targetRange, in: textContainer).contains(tapLocation) && NSLocationInRange(indexOfGlyph, targetRange)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Accessibility
|
|
||||||
extension Label {
|
|
||||||
|
|
||||||
func customAccessibilityAction(range: NSRange) -> UIAccessibilityCustomAction? {
|
|
||||||
|
|
||||||
guard let text = text else { return nil }
|
|
||||||
|
|
||||||
if accessibilityHint == nil {
|
|
||||||
accessibilityHint = MVMCoreUIUtility.hardcodedString(withKey: "swipe_to_select_with_action_hint")
|
|
||||||
}
|
|
||||||
|
|
||||||
let actionText = NSString(string: text).substring(with: range)
|
|
||||||
let accessibleAction = UIAccessibilityCustomAction(name: actionText, target: self, selector: #selector(accessibilityCustomAction(_:)))
|
|
||||||
accessibilityCustomActions?.append(accessibleAction)
|
|
||||||
|
|
||||||
return accessibleAction
|
|
||||||
}
|
|
||||||
|
|
||||||
@objc public func accessibilityCustomAction(_ action: UIAccessibilityCustomAction) {
|
|
||||||
|
|
||||||
for clause in clauses {
|
|
||||||
if action.hash == clause.accessibilityID {
|
|
||||||
clause.performAction()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func accessibilityActivate() -> Bool {
|
|
||||||
|
|
||||||
guard let accessibleActions = accessibilityCustomActions else { return false }
|
|
||||||
|
|
||||||
for clause in clauses {
|
|
||||||
for action in accessibleActions {
|
|
||||||
if action.hash == clause.accessibilityID {
|
|
||||||
clause.performAction()
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//------------------------------------------------------
|
//------------------------------------------------------
|
||||||
@ -1029,3 +548,4 @@ func validateAttribute(range: NSRange, in string: NSAttributedString, type: Stri
|
|||||||
|
|
||||||
return range
|
return range
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
// Created by Suresh, Kamlesh on 10/3/19.
|
// Created by Suresh, Kamlesh on 10/3/19.
|
||||||
// Copyright © 2019 Suresh, Kamlesh. All rights reserved.
|
// Copyright © 2019 Suresh, Kamlesh. All rights reserved.
|
||||||
//
|
//
|
||||||
|
import VDS
|
||||||
|
|
||||||
@objcMembers open class LabelModel: MoleculeModelProtocol {
|
@objcMembers open class LabelModel: MoleculeModelProtocol {
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -30,6 +30,7 @@
|
|||||||
public var numberOfLines: Int?
|
public var numberOfLines: Int?
|
||||||
public var shouldMaskRecordedView: Bool? = false
|
public var shouldMaskRecordedView: Bool? = false
|
||||||
public var accessibilityTraits: UIAccessibilityTraits?
|
public var accessibilityTraits: UIAccessibilityTraits?
|
||||||
|
public var inverted: Bool = false
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Keys
|
// MARK: - Keys
|
||||||
@ -49,6 +50,7 @@
|
|||||||
case attributes
|
case attributes
|
||||||
case html
|
case html
|
||||||
case hero
|
case hero
|
||||||
|
case inverted
|
||||||
case makeWholeViewClickable
|
case makeWholeViewClickable
|
||||||
case numberOfLines
|
case numberOfLines
|
||||||
case shouldMaskRecordedView
|
case shouldMaskRecordedView
|
||||||
@ -97,6 +99,7 @@
|
|||||||
attributes = try typeContainer.decodeModelsIfPresent(codingKey: .attributes)
|
attributes = try typeContainer.decodeModelsIfPresent(codingKey: .attributes)
|
||||||
html = try typeContainer.decodeIfPresent(String.self, forKey: .html)
|
html = try typeContainer.decodeIfPresent(String.self, forKey: .html)
|
||||||
hero = try typeContainer.decodeIfPresent(Int.self, forKey: .hero)
|
hero = try typeContainer.decodeIfPresent(Int.self, forKey: .hero)
|
||||||
|
inverted = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) ?? false
|
||||||
makeWholeViewClickable = try typeContainer.decodeIfPresent(Bool.self, forKey: .makeWholeViewClickable)
|
makeWholeViewClickable = try typeContainer.decodeIfPresent(Bool.self, forKey: .makeWholeViewClickable)
|
||||||
numberOfLines = try typeContainer.decodeIfPresent(Int.self, forKey: .numberOfLines)
|
numberOfLines = try typeContainer.decodeIfPresent(Int.self, forKey: .numberOfLines)
|
||||||
shouldMaskRecordedView = try typeContainer.decodeIfPresent(Bool.self, forKey: .shouldMaskRecordedView) ?? false
|
shouldMaskRecordedView = try typeContainer.decodeIfPresent(Bool.self, forKey: .shouldMaskRecordedView) ?? false
|
||||||
@ -123,9 +126,14 @@
|
|||||||
try container.encodeModelsIfPresent(attributes, forKey: .attributes)
|
try container.encodeModelsIfPresent(attributes, forKey: .attributes)
|
||||||
try container.encodeIfPresent(html, forKey: .html)
|
try container.encodeIfPresent(html, forKey: .html)
|
||||||
try container.encodeIfPresent(hero, forKey: .hero)
|
try container.encodeIfPresent(hero, forKey: .hero)
|
||||||
|
try container.encodeIfPresent(inverted, forKey: .inverted)
|
||||||
try container.encodeIfPresent(makeWholeViewClickable, forKey: .makeWholeViewClickable)
|
try container.encodeIfPresent(makeWholeViewClickable, forKey: .makeWholeViewClickable)
|
||||||
try container.encodeIfPresent(numberOfLines, forKey: .numberOfLines)
|
try container.encodeIfPresent(numberOfLines, forKey: .numberOfLines)
|
||||||
try container.encodeIfPresent(shouldMaskRecordedView, forKey: .shouldMaskRecordedView)
|
try container.encodeIfPresent(shouldMaskRecordedView, forKey: .shouldMaskRecordedView)
|
||||||
try container.encodeIfPresent(accessibilityTraits, forKey: .accessibilityTraits)
|
try container.encodeIfPresent(accessibilityTraits, forKey: .accessibilityTraits)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension LabelModel {
|
||||||
|
public var surface: Surface { inverted ? .dark : .light }
|
||||||
|
}
|
||||||
|
|||||||
@ -68,23 +68,35 @@ open class TileletModel: MoleculeModelProtocol {
|
|||||||
public func titleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Tilelet.TitleModel? {
|
public func titleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Tilelet.TitleModel? {
|
||||||
guard let title else { return nil }
|
guard let title else { return nil }
|
||||||
let attrs = title.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData)
|
let attrs = title.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData)
|
||||||
let style: TextStyle? = title.fontStyle?.vdsTextStyle()
|
|
||||||
if let style, let standardStyle = Tilelet.TitleModel.StandardStyle(rawValue: style.toStandardStyle().rawValue) {
|
do {
|
||||||
return .init(text: title.text, textAttributes: attrs, standardStyle: standardStyle)
|
if let style = title.fontStyle {
|
||||||
} else {
|
return .init(text: title.text,
|
||||||
return .init(text: title.text, textAttributes: attrs)
|
textAttributes: attrs,
|
||||||
}
|
standardStyle: try style.vdsSubsetStyle())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} catch MVMCoreError.errorObject(let object) {
|
||||||
|
MVMCoreLoggingHandler.shared()?.addError(toLog: object)
|
||||||
|
} catch { }
|
||||||
|
|
||||||
|
return .init(text: title.text, textAttributes: attrs)
|
||||||
|
}
|
||||||
|
|
||||||
public func subTitleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Tilelet.SubTitleModel? {
|
public func subTitleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> Tilelet.SubTitleModel? {
|
||||||
guard let subTitle else { return nil }
|
guard let subTitle else { return nil }
|
||||||
let attrs = subTitle.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData)
|
let attrs = subTitle.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData)
|
||||||
let style: TextStyle? = subTitle.fontStyle?.vdsTextStyle()
|
do {
|
||||||
if let style, let standardStyle = Tilelet.SubTitleModel.StandardStyle(rawValue: style.toStandardStyle().rawValue) {
|
if let style = subTitle.fontStyle {
|
||||||
return .init(text: subTitle.text, textAttributes: attrs, standardStyle: standardStyle)
|
return .init(text: subTitle.text,
|
||||||
} else {
|
otherStandardStyle: try style.vdsSubsetStyle(),
|
||||||
return .init(text: subTitle.text, textAttributes: attrs)
|
textAttributes: attrs)
|
||||||
}
|
}
|
||||||
|
} catch MVMCoreError.errorObject(let object) {
|
||||||
|
MVMCoreLoggingHandler.shared()?.addError(toLog: object)
|
||||||
|
} catch { }
|
||||||
|
|
||||||
|
return .init(text: subTitle.text, textAttributes: attrs)
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
|
|||||||
@ -26,6 +26,7 @@ extension VDS.Tabs.Size: Codable {}
|
|||||||
extension VDS.TextLink.Size: Codable {}
|
extension VDS.TextLink.Size: Codable {}
|
||||||
extension VDS.TextLinkCaret.IconPosition: Codable {}
|
extension VDS.TextLinkCaret.IconPosition: Codable {}
|
||||||
extension VDS.TileContainer.AspectRatio: Codable {}
|
extension VDS.TileContainer.AspectRatio: Codable {}
|
||||||
|
extension VDS.TitleLockup.TextAlignment: Codable {}
|
||||||
extension VDS.Tooltip.FillColor: Codable {}
|
extension VDS.Tooltip.FillColor: Codable {}
|
||||||
extension VDS.Tooltip.Size: Codable {}
|
extension VDS.Tooltip.Size: Codable {}
|
||||||
extension VDS.Line.Style: Codable {}
|
extension VDS.Line.Style: Codable {}
|
||||||
|
|||||||
@ -12,20 +12,54 @@ import VDS
|
|||||||
extension Styler.Font {
|
extension Styler.Font {
|
||||||
//Converts Legacy Font to a VDS.TextStyle
|
//Converts Legacy Font to a VDS.TextStyle
|
||||||
public func vdsTextStyle() -> VDS.TextStyle? {
|
public func vdsTextStyle() -> VDS.TextStyle? {
|
||||||
let updatedRaw = rawValue.replacingOccurrences(of: "Regular", with: "")
|
|
||||||
|
//ensure that the current Styler.Font isn't Legacy Version
|
||||||
|
//if it is, here is the conversion to the updated version
|
||||||
|
var actualFont: Styler.Font = self
|
||||||
|
switch self {
|
||||||
|
case .Title2XLarge: actualFont = .RegularTitle2XLarge
|
||||||
|
case .TitleXLarge: actualFont = .RegularTitleXLarge
|
||||||
|
case .H1: actualFont = .RegularTitle2XLarge
|
||||||
|
case .H32: actualFont = .RegularTitleXLarge
|
||||||
|
case .H2: actualFont = .RegularTitleLarge
|
||||||
|
case .B20: actualFont = .RegularBodyLarge
|
||||||
|
case .H3: actualFont = .BoldTitleMedium
|
||||||
|
case .B1: actualFont = .BoldBodySmall
|
||||||
|
case .B2: actualFont = .RegularBodySmall
|
||||||
|
case .B3: actualFont = .RegularMicro
|
||||||
|
default: break
|
||||||
|
}
|
||||||
|
|
||||||
|
let updatedRaw = actualFont.rawValue.replacingOccurrences(of: "Regular", with: "")
|
||||||
let newRaw = updatedRaw.prefix(1).lowercased() + updatedRaw.dropFirst()
|
let newRaw = updatedRaw.prefix(1).lowercased() + updatedRaw.dropFirst()
|
||||||
guard let style = VDS.TextStyle(rawValue: newRaw) else { return nil }
|
guard let style = VDS.TextStyle(rawValue: newRaw) else { return nil }
|
||||||
return style
|
return style
|
||||||
}
|
}
|
||||||
|
|
||||||
public func vdsSubsetStyle<T: EnumSubset>() -> T? {
|
public func vdsSubsetStyle<T: EnumSubset>() throws -> T {
|
||||||
guard let style = vdsTextStyle() else { return nil }
|
guard let style = vdsTextStyle(), let rawValue = style.toStandardStyle().rawValue as? T.RawValue, let standardStyle = T(rawValue: rawValue) else {
|
||||||
guard let rawValue = style.rawValue as? T.RawValue,
|
let err = "\(rawValue) was not found in the \(T.self), only these cases exist:\r\(T.allCases)"
|
||||||
let found = T(rawValue: rawValue) else {
|
throw MVMCoreError.errorObject(MVMCoreErrorObject(title: "\(T.self) conversion Issue",
|
||||||
print("Style: \(style.rawValue) is not in enum \(T.self)\ronly these cases exist:\r\(T.allCases)")
|
messageToLog: err,
|
||||||
return nil
|
code: 999,
|
||||||
|
domain: ErrorDomainNative,
|
||||||
|
location: #file)!)
|
||||||
}
|
}
|
||||||
return found
|
return standardStyle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension VDS.Font {
|
||||||
|
internal static func from(fontName: String) -> Self? {
|
||||||
|
Self.allCases.filter({$0.fontName == fontName }).first
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension VDS.TextStyle {
|
||||||
|
internal static func style(from font: VDS.Font, pointSize: CGFloat) -> TextStyle? {
|
||||||
|
guard let first = allCases.filter({$0.fontFace == font && $0.pointSize == pointSize}).first else {
|
||||||
|
return TextStyle(rawValue: "Custom-TextStyle", fontFace: font, pointSize: pointSize)
|
||||||
|
}
|
||||||
|
return first
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import Foundation
|
|||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Outlets
|
// MARK: - Outlets
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
public let planLabel = Label()
|
public let planLabel = Label(fontStyle: .BoldFeatureXLarge)
|
||||||
public let headline = Label(fontStyle: .BoldTitleLarge)
|
public let headline = Label(fontStyle: .BoldTitleLarge)
|
||||||
public let subHeadline = Label(fontStyle: .RegularTitleLarge)
|
public let subHeadline = Label(fontStyle: .RegularTitleLarge)
|
||||||
public let body = Label(fontStyle: .RegularBodySmall)
|
public let body = Label(fontStyle: .RegularBodySmall)
|
||||||
@ -33,8 +33,6 @@ import Foundation
|
|||||||
//-------------------------------------------------------
|
//-------------------------------------------------------
|
||||||
open override func setupView() {
|
open override func setupView() {
|
||||||
super.setupView()
|
super.setupView()
|
||||||
planLabel.font = MFStyler.getMVA3FontSize(96, bold: true)
|
|
||||||
planLabel.standardFontSize = 96
|
|
||||||
addSubview(stack)
|
addSubview(stack)
|
||||||
planLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
|
planLabel.setContentCompressionResistancePriority(.required, for: .horizontal)
|
||||||
planLabel.setContentHuggingPriority(.defaultHigh, for: .vertical)
|
planLabel.setContentHuggingPriority(.defaultHigh, for: .vertical)
|
||||||
@ -94,8 +92,7 @@ import Foundation
|
|||||||
open override func reset() {
|
open override func reset() {
|
||||||
super.reset()
|
super.reset()
|
||||||
stack.reset()
|
stack.reset()
|
||||||
planLabel.font = MFStyler.getMVA3FontSize(96, bold: true)
|
planLabel.setFontStyle(.BoldFeatureXLarge)
|
||||||
planLabel.standardFontSize = 96
|
|
||||||
headline.setFontStyle(.BoldTitleLarge)
|
headline.setFontStyle(.BoldTitleLarge)
|
||||||
subHeadline.setFontStyle(.RegularTitleLarge)
|
subHeadline.setFontStyle(.RegularTitleLarge)
|
||||||
body.setFontStyle(.RegularBodySmall)
|
body.setFontStyle(.RegularBodySmall)
|
||||||
|
|||||||
@ -5,119 +5,43 @@
|
|||||||
// Created by Nadigadda, Sumanth on 04/05/22.
|
// Created by Nadigadda, Sumanth on 04/05/22.
|
||||||
// Copyright © 2022 Verizon Wireless. All rights reserved.
|
// Copyright © 2022 Verizon Wireless. All rights reserved.
|
||||||
//
|
//
|
||||||
|
import VDS
|
||||||
|
|
||||||
|
@objcMembers open class TitleLockup: VDS.TitleLockup, VDSMoleculeViewProtocol {
|
||||||
|
|
||||||
@objcMembers open class TitleLockup: View {
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Outlets
|
// MARK: - Public Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
open var viewModel: TitleLockupModel!
|
||||||
|
open var delegateObject: MVMCoreUIDelegateObject?
|
||||||
|
open var additionalData: [AnyHashable : Any]?
|
||||||
|
|
||||||
public let eyebrow = Label(fontStyle: .RegularBodySmall)
|
//--------------------------------------------------
|
||||||
public let title = Label(fontStyle: .RegularBodySmall)
|
// MARK: - Public Functions
|
||||||
public let subTitle = Label(fontStyle: .RegularBodySmall)
|
//--------------------------------------------------
|
||||||
public lazy var stack: UIStackView = {
|
open func viewModelDidUpdate() {
|
||||||
let stack = UIStackView(arrangedSubviews: [eyebrow, title, subTitle])
|
surface = viewModel.surface
|
||||||
stack.translatesAutoresizingMaskIntoConstraints = false
|
textAlignment = viewModel.textAlignment
|
||||||
stack.axis = .vertical
|
eyebrowModel = viewModel.eyebrowModel(delegateObject: delegateObject, additionalData: additionalData)
|
||||||
return stack
|
titleModel = viewModel.titleModel(delegateObject: delegateObject, additionalData: additionalData)
|
||||||
}()
|
subTitleModel = viewModel.subTitleModel(delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
|
||||||
var castModel: TitleLockupModel? {
|
|
||||||
get { return model as? TitleLockupModel }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - Initialization
|
// MARK: - Initialization
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public convenience init() {
|
public convenience required init() {
|
||||||
self.init(frame: .zero)
|
self.init(frame: .zero)
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - MFViewProtocol
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
open override func setupView() {
|
|
||||||
super.setupView()
|
|
||||||
addSubview(stack)
|
|
||||||
NSLayoutConstraint.constraintPinSubview(toSuperview: stack)
|
|
||||||
}
|
|
||||||
|
|
||||||
open override func updateView(_ size: CGFloat) {
|
|
||||||
super.updateView(size)
|
|
||||||
stack.updateView(size)
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
// MARK: - MoleculeViewProtocol
|
// MARK: - MoleculeViewProtocol
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||||
open override func reset() {
|
|
||||||
super.reset()
|
|
||||||
stack.reset()
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - MoleculeViewProtocol
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
|
||||||
super.set(with: model, delegateObject, additionalData)
|
|
||||||
guard let model = model as? TitleLockupModel else { return }
|
|
||||||
stack.setCustomSpacing(model.defaultEyebrowTitleSpacing(), after: eyebrow)
|
|
||||||
stack.setCustomSpacing(model.defaultTitleSubTitleSpacing(), after: title)
|
|
||||||
stack.updateContainedMolecules(with: [model.eyebrow,
|
|
||||||
model.title,
|
|
||||||
model.subTitle],
|
|
||||||
delegateObject, additionalData)
|
|
||||||
}
|
|
||||||
|
|
||||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
|
||||||
return 65
|
return 65
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
open func updateView(_ size: CGFloat) {}
|
||||||
// MARK: - Accessibility Helpers
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
/// Returns the labels text in one message.
|
|
||||||
func getAccessibilityMessage() -> String? {
|
|
||||||
|
|
||||||
var message = ""
|
|
||||||
|
|
||||||
if let eyebrowLabel = eyebrow.text {
|
|
||||||
message += eyebrowLabel + ", "
|
|
||||||
}
|
|
||||||
|
|
||||||
if let headlineLabel = title.text {
|
|
||||||
message += headlineLabel + ", "
|
|
||||||
}
|
|
||||||
|
|
||||||
if let bodyLabel = subTitle.text {
|
|
||||||
message += bodyLabel
|
|
||||||
}
|
|
||||||
|
|
||||||
return message.count > 0 ? message : nil
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns an array of the appropriate accessibility elements.
|
|
||||||
func getAccessibilityElements() -> [Any]? {
|
|
||||||
|
|
||||||
var elements: [UIView] = []
|
|
||||||
|
|
||||||
if eyebrow.hasText {
|
|
||||||
elements.append(eyebrow)
|
|
||||||
}
|
|
||||||
|
|
||||||
if title.hasText {
|
|
||||||
elements.append(title)
|
|
||||||
}
|
|
||||||
|
|
||||||
if subTitle.hasText {
|
|
||||||
elements.append(subTitle)
|
|
||||||
}
|
|
||||||
|
|
||||||
return elements.count > 0 ? elements : nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import VDSColorTokens
|
import VDSColorTokens
|
||||||
|
import VDS
|
||||||
|
|
||||||
public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtocol {
|
public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtocol {
|
||||||
|
|
||||||
@ -18,47 +19,16 @@ public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtoco
|
|||||||
public var moleculeName: String = TitleLockupModel.identifier
|
public var moleculeName: String = TitleLockupModel.identifier
|
||||||
public var id: String = UUID().uuidString
|
public var id: String = UUID().uuidString
|
||||||
|
|
||||||
|
public var textAlignment: TitleLockup.TextAlignment = .left
|
||||||
public var eyebrow: LabelModel?
|
public var eyebrow: LabelModel?
|
||||||
public var title: LabelModel
|
public var title: LabelModel
|
||||||
public var subTitle: LabelModel?
|
public var subTitle: LabelModel?
|
||||||
|
public var subTitleColor: Use = .primary
|
||||||
|
|
||||||
public var alignment: Alignment = .left {
|
public var alignment: VDS.TitleLockup.TextAlignment = .left
|
||||||
didSet {
|
public var inverted: Bool = false
|
||||||
///Updating the text alignment for all labels
|
|
||||||
if let textAlignment = NSTextAlignment(rawValue: alignment.rawValue) {
|
|
||||||
eyebrow?.textAlignment = textAlignment
|
|
||||||
title.textAlignment = textAlignment
|
|
||||||
subTitle?.textAlignment = textAlignment
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public var inverted: Bool = false {
|
public var backgroundColor: Color?
|
||||||
didSet {
|
|
||||||
///Updating the text color
|
|
||||||
eyebrow?.textColor = titleColor
|
|
||||||
title.textColor = titleColor
|
|
||||||
subTitle?.textColor = subTitleColor
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private var _backgroundColor: Color?
|
|
||||||
public var backgroundColor: Color? {
|
|
||||||
get {
|
|
||||||
return inverted ? Color(uiColor: VDSColor.backgroundPrimaryDark) : Color(uiColor: VDSColor.backgroundPrimaryLight)
|
|
||||||
}
|
|
||||||
set {
|
|
||||||
_backgroundColor = newValue
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public var titleColor: Color? {
|
|
||||||
return inverted ? Color(uiColor: VDSColor.elementsPrimaryOndark) : Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
|
||||||
}
|
|
||||||
|
|
||||||
public var subTitleColor: Color? {
|
|
||||||
return inverted ? Color(uiColor: VDSColor.elementsSecondaryOndark) : Color(uiColor: VDSColor.elementsSecondaryOnlight)
|
|
||||||
}
|
|
||||||
|
|
||||||
public var children: [MoleculeModelProtocol] {
|
public var children: [MoleculeModelProtocol] {
|
||||||
[eyebrow, title, subTitle].compactMap { (molecule: MoleculeModelProtocol?) in molecule }
|
[eyebrow, title, subTitle].compactMap { (molecule: MoleculeModelProtocol?) in molecule }
|
||||||
@ -78,58 +48,6 @@ public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtoco
|
|||||||
self.eyebrow = eyebrow
|
self.eyebrow = eyebrow
|
||||||
self.title = title
|
self.title = title
|
||||||
self.subTitle = subTitle
|
self.subTitle = subTitle
|
||||||
updateLabelAttributes()
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Enum
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
public enum Alignment: String, Codable {
|
|
||||||
case left
|
|
||||||
case center
|
|
||||||
}
|
|
||||||
|
|
||||||
//--------------------------------------------------
|
|
||||||
// MARK: - Styling
|
|
||||||
//--------------------------------------------------
|
|
||||||
|
|
||||||
/// Returns the default fontStyle for the subtitle, based on the title fontStyle.
|
|
||||||
func defaultSubtitleFontStyle() -> Styler.Font {
|
|
||||||
switch title.fontStyle {
|
|
||||||
case .RegularTitleXLarge, .RegularTitle2XLarge, .RegularFeatureXSmall:
|
|
||||||
return .RegularBodyLarge
|
|
||||||
case .RegularFeatureSmall, .RegularFeatureMedium:
|
|
||||||
return .RegularTitleLarge
|
|
||||||
default:
|
|
||||||
return .RegularBodySmall
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the default spacing between the eyebrow and title, based on the title fontStyle.
|
|
||||||
func defaultEyebrowTitleSpacing() -> CGFloat {
|
|
||||||
switch title.fontStyle {
|
|
||||||
case .RegularTitleXLarge, .RegularTitle2XLarge, .RegularFeatureXSmall, .RegularFeatureSmall:
|
|
||||||
return Padding.Three
|
|
||||||
case .RegularFeatureMedium:
|
|
||||||
return subTitle?.fontStyle == .RegularBodyLarge ? Padding.Three : Padding.Four
|
|
||||||
default:
|
|
||||||
return Padding.Two
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the default spacing between the title and subTitle, based on the title fontStyle.
|
|
||||||
func defaultTitleSubTitleSpacing() -> CGFloat {
|
|
||||||
switch title.fontStyle {
|
|
||||||
case .RegularTitleXLarge:
|
|
||||||
return Padding.Three
|
|
||||||
case .RegularTitle2XLarge, .RegularFeatureXSmall, .RegularFeatureSmall:
|
|
||||||
return Padding.Four
|
|
||||||
case .RegularFeatureMedium:
|
|
||||||
return Padding.Five
|
|
||||||
default:
|
|
||||||
return Padding.Two
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
@ -139,10 +57,11 @@ public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtoco
|
|||||||
private enum CodingKeys: String, CodingKey {
|
private enum CodingKeys: String, CodingKey {
|
||||||
case id
|
case id
|
||||||
case moleculeName
|
case moleculeName
|
||||||
case backgroundColor
|
case textAlignment
|
||||||
case eyebrow
|
case eyebrow
|
||||||
case title
|
case title
|
||||||
case subTitle
|
case subTitle
|
||||||
|
case subTitleColor
|
||||||
case inverted
|
case inverted
|
||||||
case alignment
|
case alignment
|
||||||
}
|
}
|
||||||
@ -154,72 +73,122 @@ public class TitleLockupModel: MoleculeModelProtocol, ParentMoleculeModelProtoco
|
|||||||
required public init(from decoder: Decoder) throws {
|
required public init(from decoder: Decoder) throws {
|
||||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||||
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
|
id = try typeContainer.decodeIfPresent(String.self, forKey: .id) ?? UUID().uuidString
|
||||||
|
textAlignment = try typeContainer.decodeIfPresent(TitleLockup.TextAlignment.self, forKey: .textAlignment) ?? .left
|
||||||
title = try typeContainer.decodeMolecule(codingKey: .title)
|
title = try typeContainer.decodeMolecule(codingKey: .title)
|
||||||
eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow)
|
eyebrow = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .eyebrow)
|
||||||
subTitle = try typeContainer.decodeMoleculeIfPresent(codingKey: .subTitle)
|
subTitle = try typeContainer.decodeMoleculeIfPresent(codingKey: .subTitle)
|
||||||
|
|
||||||
|
/// look for color hex code
|
||||||
|
if let color = try? typeContainer.decodeIfPresent(Color.self, forKey: .subTitleColor) {
|
||||||
|
self.subTitleColor = color.uiColor.isDark() ? .primary : .secondary
|
||||||
|
|
||||||
if let newAlignment = try typeContainer.decodeIfPresent(Alignment.self, forKey: .alignment) {
|
} else if let subTitleColor = try? typeContainer.decodeIfPresent(Use.self, forKey: .subTitleColor) {
|
||||||
|
self.subTitleColor = subTitleColor
|
||||||
|
|
||||||
|
} else {
|
||||||
|
subTitleColor = .primary
|
||||||
|
}
|
||||||
|
|
||||||
|
if let newAlignment = try typeContainer.decodeIfPresent(VDS.TitleLockup.TextAlignment.self, forKey: .alignment) {
|
||||||
alignment = newAlignment
|
alignment = newAlignment
|
||||||
}
|
}
|
||||||
|
|
||||||
if let invertedStatus = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) {
|
if let inverted = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) {
|
||||||
inverted = invertedStatus
|
self.inverted = inverted
|
||||||
|
} else {
|
||||||
|
try setInverted(deprecatedFrom: decoder)
|
||||||
}
|
}
|
||||||
|
|
||||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
|
||||||
|
|
||||||
updateLabelAttributes()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public func encode(to encoder: Encoder) throws {
|
public func encode(to encoder: Encoder) throws {
|
||||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||||
try container.encode(id, forKey: .id)
|
try container.encode(id, forKey: .id)
|
||||||
try container.encode(moleculeName, forKey: .moleculeName)
|
try container.encode(moleculeName, forKey: .moleculeName)
|
||||||
|
try container.encode(textAlignment, forKey: .textAlignment)
|
||||||
try container.encodeIfPresent(eyebrow, forKey: .eyebrow)
|
try container.encodeIfPresent(eyebrow, forKey: .eyebrow)
|
||||||
try container.encodeModel(title, forKey: .title)
|
try container.encodeModel(title, forKey: .title)
|
||||||
try container.encodeIfPresent(subTitle, forKey: .subTitle)
|
try container.encodeIfPresent(subTitle, forKey: .subTitle)
|
||||||
|
try container.encode(subTitleColor, forKey: .subTitleColor)
|
||||||
try container.encode(alignment, forKey: .alignment)
|
try container.encode(alignment, forKey: .alignment)
|
||||||
try container.encode(inverted, forKey: .inverted)
|
try container.encode(inverted, forKey: .inverted)
|
||||||
try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//--------------------------------------------------
|
public func eyebrowModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> VDS.TitleLockup.EyebrowModel? {
|
||||||
// MARK: - Model updates
|
guard let eyebrow else { return nil }
|
||||||
//--------------------------------------------------
|
let attrs = eyebrow.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
do {
|
||||||
|
if let style = eyebrow.fontStyle {
|
||||||
|
return .init(text: eyebrow.text,
|
||||||
|
isBold: style.isBold(),
|
||||||
|
standardStyle: try style.vdsSubsetStyle(),
|
||||||
|
textAttributes: attrs,
|
||||||
|
numberOfLines: eyebrow.numberOfLines ?? 0)
|
||||||
|
}
|
||||||
|
} catch MVMCoreError.errorObject(let object) {
|
||||||
|
MVMCoreLoggingHandler.shared()?.addError(toLog: object)
|
||||||
|
} catch { }
|
||||||
|
|
||||||
|
return .init(text: eyebrow.text, textAttributes: attrs, numberOfLines: eyebrow.numberOfLines ?? 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
public func titleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> VDS.TitleLockup.TitleModel {
|
||||||
|
let attrs = title.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
do {
|
||||||
|
if let style = title.fontStyle {
|
||||||
|
return .init(text: title.text,
|
||||||
|
textAttributes: attrs,
|
||||||
|
isBold: style.isBold(),
|
||||||
|
standardStyle: try style.vdsSubsetStyle(),
|
||||||
|
numberOfLines: title.numberOfLines ?? 0)
|
||||||
|
}
|
||||||
|
|
||||||
private func updateLabelAttributes() {
|
} catch MVMCoreError.errorObject(let object) {
|
||||||
// If subtitle style is not available, will set font style based on the component
|
MVMCoreLoggingHandler.shared()?.addError(toLog: object)
|
||||||
if subTitle?.fontStyle == nil {
|
} catch { }
|
||||||
subTitle?.fontStyle = defaultSubtitleFontStyle()
|
|
||||||
}
|
|
||||||
|
|
||||||
// If eyebrow style is not available, will set font style based on the component. Eyebrow and subtitle share the same font size
|
return .init(text: title.text, textAttributes: attrs, numberOfLines: title.numberOfLines ?? 0)
|
||||||
if eyebrow?.fontStyle == nil {
|
}
|
||||||
eyebrow?.fontStyle = subTitle?.fontStyle
|
|
||||||
}
|
public func subTitleModel(delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) -> VDS.TitleLockup.SubTitleModel? {
|
||||||
|
guard let subTitle else { return nil }
|
||||||
|
let attrs = subTitle.attributes?.toVDSLabelAttributeModel(delegateObject: delegateObject, additionalData: additionalData)
|
||||||
|
|
||||||
// Updating the text color
|
do {
|
||||||
if eyebrow?.textColor == nil {
|
if let style = subTitle.fontStyle {
|
||||||
eyebrow?.textColor = subTitleColor
|
return .init(text: subTitle.text,
|
||||||
}
|
otherStandardStyle: try style.vdsSubsetStyle(),
|
||||||
if title.textColor == nil {
|
textColor: subTitleColor,
|
||||||
title.textColor = titleColor
|
textAttributes: attrs,
|
||||||
}
|
numberOfLines: subTitle.numberOfLines ?? 0)
|
||||||
if subTitle?.textColor == nil {
|
|
||||||
subTitle?.textColor = subTitleColor
|
|
||||||
}
|
|
||||||
|
|
||||||
// Updating the text alignment for all labels
|
|
||||||
if let textAlignment = NSTextAlignment(rawValue: alignment.rawValue) {
|
|
||||||
if eyebrow?.textAlignment == nil {
|
|
||||||
eyebrow?.textAlignment = textAlignment
|
|
||||||
}
|
|
||||||
if title.textAlignment == nil {
|
|
||||||
title.textAlignment = textAlignment
|
|
||||||
}
|
|
||||||
if subTitle?.textAlignment == nil {
|
|
||||||
subTitle?.textAlignment = textAlignment
|
|
||||||
}
|
}
|
||||||
|
} catch MVMCoreError.errorObject(let object) {
|
||||||
|
MVMCoreLoggingHandler.shared()?.addError(toLog: object)
|
||||||
|
} catch { }
|
||||||
|
|
||||||
|
return .init(text: subTitle.text, textColor: subTitleColor, textAttributes: attrs, numberOfLines: subTitle.numberOfLines ?? 0)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum DeprecatedCodingKeys: String, CodingKey {
|
||||||
|
case titleColor
|
||||||
|
case backgroundColor
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setInverted(deprecatedFrom decoder: Decoder) throws {
|
||||||
|
let typeContainer = try decoder.container(keyedBy: DeprecatedCodingKeys.self)
|
||||||
|
|
||||||
|
if let titleColor = try typeContainer.decodeIfPresent(Color.self, forKey: .titleColor) {
|
||||||
|
inverted = !titleColor.uiColor.isDark()
|
||||||
|
}
|
||||||
|
|
||||||
|
if let backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor) {
|
||||||
|
inverted = !backgroundColor.uiColor.isDark()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
extension TitleLockupModel {
|
||||||
|
public var surface: Surface { inverted ? .dark : .light }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -76,8 +76,8 @@ import UIKit
|
|||||||
|
|
||||||
private func setDefaultState() {
|
private func setDefaultState() {
|
||||||
|
|
||||||
headlineBodyButton.headlineBody.headlineLabel.font = MFStyler.fontBoldTitleMedium()
|
headlineBodyButton.headlineBody.headlineLabel.setFontStyle(.BoldTitleMedium)
|
||||||
headlineBodyButton.headlineBody.messageLabel.font = MFStyler.fontRegularMicro()
|
headlineBodyButton.headlineBody.messageLabel.setFontStyle(.RegularMicro)
|
||||||
imageLoader.imageView.contentMode = .scaleAspectFit
|
imageLoader.imageView.contentMode = .scaleAspectFit
|
||||||
imageLoader.addSizeConstraintsForAspectRatio = true
|
imageLoader.addSizeConstraintsForAspectRatio = true
|
||||||
buttonHeaderPadding = PaddingTwo
|
buttonHeaderPadding = PaddingTwo
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import UIKit
|
|||||||
// MARK: - Properties
|
// MARK: - Properties
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|
||||||
public let label = Label(fontStyle: .BoldBodySmall)
|
public let label = Label().with { $0.font = Styler.Font.BoldFeatureXLarge.getFont() }
|
||||||
public let toggle = Toggle()
|
public let toggle = Toggle()
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
|||||||
@ -62,8 +62,8 @@
|
|||||||
|
|
||||||
private func defaultState() {
|
private func defaultState() {
|
||||||
|
|
||||||
headlineBody.headlineLabel.font = Styler.Font.BoldTitleMedium.getFont()
|
headlineBody.headlineLabel.setFontStyle(.BoldTitleMedium)
|
||||||
headlineBody.messageLabel.font = Styler.Font.RegularMicro.getFont()
|
headlineBody.messageLabel.setFontStyle(.RegularMicro)
|
||||||
button.use = .secondary
|
button.use = .secondary
|
||||||
button.isHidden = false
|
button.isHidden = false
|
||||||
buttonHeadlinePadding = PaddingTwo
|
buttonHeadlinePadding = PaddingTwo
|
||||||
|
|||||||
@ -57,59 +57,6 @@ open class Styler {
|
|||||||
case B2 // Maps to RegularBodySmall
|
case B2 // Maps to RegularBodySmall
|
||||||
case B3 // Maps to RegularMicro
|
case B3 // Maps to RegularMicro
|
||||||
|
|
||||||
/// Returns the font size of the current enum case.
|
|
||||||
public func pointSize() -> CGFloat {
|
|
||||||
switch self {
|
|
||||||
case .RegularFeatureXLarge,
|
|
||||||
.BoldFeatureXLarge:
|
|
||||||
return 96
|
|
||||||
case .RegularFeatureLarge,
|
|
||||||
.BoldFeatureLarge:
|
|
||||||
return 80
|
|
||||||
case .RegularFeatureMedium,
|
|
||||||
.BoldFeatureMedium:
|
|
||||||
return 64
|
|
||||||
case .RegularFeatureSmall,
|
|
||||||
.BoldFeatureSmall:
|
|
||||||
return 48
|
|
||||||
case .RegularFeatureXSmall,
|
|
||||||
.BoldFeatureXSmall,
|
|
||||||
.RegularTitle2XLarge,
|
|
||||||
.BoldTitle2XLarge,
|
|
||||||
.Title2XLarge,
|
|
||||||
.H1:
|
|
||||||
return 40
|
|
||||||
case .RegularTitleXLarge,
|
|
||||||
.BoldTitleXLarge,
|
|
||||||
.TitleXLarge,
|
|
||||||
.H32:
|
|
||||||
return 32
|
|
||||||
case .BoldTitleLarge,
|
|
||||||
.RegularTitleLarge,
|
|
||||||
.H2:
|
|
||||||
return 24
|
|
||||||
case .BoldTitleMedium,
|
|
||||||
.RegularTitleMedium,
|
|
||||||
.H3:
|
|
||||||
return 20
|
|
||||||
case .RegularTitleSmall,
|
|
||||||
.BoldTitleSmall,
|
|
||||||
.BoldBodyLarge,
|
|
||||||
.RegularBodyLarge,
|
|
||||||
.B20:
|
|
||||||
return 16
|
|
||||||
case .RegularBodyMedium,
|
|
||||||
.BoldBodyMedium:
|
|
||||||
return 14
|
|
||||||
case .BoldBodySmall, .B1,
|
|
||||||
.RegularBodySmall, .B2:
|
|
||||||
return 12
|
|
||||||
case .BoldMicro,
|
|
||||||
.RegularMicro, .B3:
|
|
||||||
return 11
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public func color() -> UIColor {
|
public func color() -> UIColor {
|
||||||
switch self {
|
switch self {
|
||||||
case .B3:
|
case .B3:
|
||||||
@ -148,8 +95,8 @@ open class Styler {
|
|||||||
|
|
||||||
/// Returns the font based on the declared enum case.
|
/// Returns the font based on the declared enum case.
|
||||||
public func getFont(_ genericScaling: Bool = true) -> UIFont {
|
public func getFont(_ genericScaling: Bool = true) -> UIFont {
|
||||||
let size = genericScaling ? sizeFontGeneric(forCurrentDevice: pointSize()) : pointSize()
|
let vdsStyle = vdsTextStyle() ?? .defaultStyle
|
||||||
return MFStyler.getFontFor(size: size, isBold: isBold())
|
return vdsStyle.font
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Styles the provided label to the declared enum Font case.
|
/// Styles the provided label to the declared enum Font case.
|
||||||
@ -237,7 +184,7 @@ open class Styler {
|
|||||||
/// Creates the appropriate VZW font for a VDS style, scaling based on the scaleValue threshold passed in.
|
/// Creates the appropriate VZW font for a VDS style, scaling based on the scaleValue threshold passed in.
|
||||||
@objc static func getFontFor(styleString: String, scaleValue: CGFloat) -> UIFont? {
|
@objc static func getFontFor(styleString: String, scaleValue: CGFloat) -> UIFont? {
|
||||||
guard let font = Styler.Font(rawValue: styleString),
|
guard let font = Styler.Font(rawValue: styleString),
|
||||||
let size = Styler.Font(rawValue: styleString)?.pointSize(),
|
let size = font.vdsTextStyle()?.pointSize,
|
||||||
let newSize = Styler.sizeObjectGeneric(forCurrentDevice: size)?.getValueBased(onSize: scaleValue) else { return nil }
|
let newSize = Styler.sizeObjectGeneric(forCurrentDevice: size)?.getValueBased(onSize: scaleValue) else { return nil }
|
||||||
return getFontFor(size: newSize, isBold: font.isBold())
|
return getFontFor(size: newSize, isBold: font.isBold())
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user