Merge branch 'develop' of https://gitlab.verizon.com/BPHV_MIPS/mvm_core_ui.git into feature/atomic_vds_badgeIndicator_buttonIcon_tileContainer

This commit is contained in:
Matt Bruce 2024-04-16 11:57:08 -05:00
commit eccf721447
12 changed files with 151 additions and 158 deletions

View File

@ -36,7 +36,7 @@ open class PillButton: VDS.Button, MVMCoreUIViewConstrainingProtocol, MFButtonPr
text = viewModel.title text = viewModel.title
isEnabled = viewModel.enabled isEnabled = viewModel.enabled
size = viewModel.size size = viewModel.size
use = viewModel.style ?? .primary use = viewModel.style
surface = viewModel.inverted ? .dark : .light surface = viewModel.inverted ? .dark : .light
if let accessibilityText = viewModel.accessibilityText { if let accessibilityText = viewModel.accessibilityText {
accessibilityLabel = accessibilityText accessibilityLabel = accessibilityText

View File

@ -64,9 +64,8 @@
bottomLabelConstraint.isActive = true bottomLabelConstraint.isActive = true
alignCheckbox(.center) alignCheckbox(.center)
isAccessibilityElement = true isAccessibilityElement = false
accessibilityHint = checkbox.accessibilityHint accessibilityElements = [checkbox, label]
accessibilityTraits = checkbox.accessibilityTraits
observation = observe(\.checkbox.isSelected, options: [.new]) { [weak self] _, _ in observation = observe(\.checkbox.isSelected, options: [.new]) { [weak self] _, _ in
self?.updateAccessibilityLabel() self?.updateAccessibilityLabel()
} }
@ -139,6 +138,8 @@
open func updateAccessibilityLabel() { open func updateAccessibilityLabel() {
checkbox.updateAccessibilityLabel() checkbox.updateAccessibilityLabel()
accessibilityLabel = [checkbox.accessibilityLabel, label.text].compactMap { $0 }.joined(separator: ",") if let text = label.text {
checkbox.accessibilityLabel?.append(", \(text)")
}
} }
} }

View File

@ -10,6 +10,7 @@ import Foundation
import Combine import Combine
import Dispatch import Dispatch
import MVMCore import MVMCore
import VDSTokens
@objcMembers open class CollapsableNotification: View { @objcMembers open class CollapsableNotification: View {
//-------------------------------------------------- //--------------------------------------------------
@ -50,7 +51,7 @@ import MVMCore
open override func reset() { open override func reset() {
super.reset() super.reset()
verticalStack.reset() verticalStack.reset()
backgroundColor = .mvmGreen() backgroundColor = bottomView.backgroundColor
} }
open func subscribeForNotifications() { open func subscribeForNotifications() {
@ -98,6 +99,8 @@ import MVMCore
guard let model = model as? CollapsableNotificationModel else { return } guard let model = model as? CollapsableNotificationModel else { return }
topView.set(with: model, delegateObject, additionalData) topView.set(with: model, delegateObject, additionalData)
bottomView.set(with: model, delegateObject, additionalData) bottomView.set(with: model, delegateObject, additionalData)
topView.label.textColorConfiguration = bottomView.titleLabel.textColorConfiguration
topView.label.surface = bottomView.surface
// Update top view default noop to expand. // Update top view default noop to expand.
if let topAction = model.topAction, if let topAction = model.topAction,
@ -110,6 +113,7 @@ import MVMCore
} }
} }
initialState() initialState()
backgroundColor = bottomView.backgroundColor
} }
open func performBlockOperation(with block: @escaping (MVMCoreBlockOperation) -> Void) { open func performBlockOperation(with block: @escaping (MVMCoreBlockOperation) -> Void) {
@ -214,7 +218,7 @@ import MVMCore
extension CollapsableNotification: StatusBarUI { extension CollapsableNotification: StatusBarUI {
public func getStatusBarUI() -> (color: UIColor, style: UIStatusBarStyle) { public func getStatusBarUI() -> (color: UIColor, style: UIStatusBarStyle) {
let color = backgroundColor ?? UIColor.mvmGreen let color = backgroundColor ?? VDSColor.feedbackInformationBackgroundOnlight
var greyScale: CGFloat = 0 var greyScale: CGFloat = 0
topView.label.textColor.getWhite(&greyScale, alpha: nil) topView.label.textColor.getWhite(&greyScale, alpha: nil)
return (color, greyScale > 0.5 ? .lightContent : .default) return (color, greyScale > 0.5 ? .lightContent : .default)
@ -226,7 +230,7 @@ extension CollapsableNotification: AccessibilityProtocol {
if !topView.isHidden { if !topView.isHidden {
return topView return topView
} else { } else {
return bottomView.headline return bottomView.titleLabel
} }
} }
} }

View File

@ -26,21 +26,13 @@ open class CollapsableNotificationModel: NotificationMoleculeModel {
self.collapseTime = collapseTime self.collapseTime = collapseTime
} }
super.init(with: headline, style: style, backgroundColor: backgroundColor, body: body, button: button, closeButton: closeButton) super.init(with: headline, style: style, backgroundColor: backgroundColor, body: body, button: button, closeButton: closeButton)
setDefaults()
} }
open override func setDefaults() { open func setDefaults() {
super.setDefaults()
if topLabel.numberOfLines == nil { if topLabel.numberOfLines == nil {
topLabel.numberOfLines = 1 topLabel.numberOfLines = 1
} }
if topLabel.textColor == nil {
switch style {
case .error, .warning:
topLabel.textColor = Color(uiColor: .mvmBlack)
default:
topLabel.textColor = Color(uiColor: .mvmWhite)
}
}
if topLabel.textAlignment == nil { if topLabel.textAlignment == nil {
topLabel.textAlignment = .center topLabel.textAlignment = .center
} }
@ -69,6 +61,7 @@ open class CollapsableNotificationModel: NotificationMoleculeModel {
self.initiallyCollapsed = initiallyCollapsed self.initiallyCollapsed = initiallyCollapsed
} }
try super.init(from: decoder) try super.init(from: decoder)
setDefaults()
} }
open override func encode(to encoder: Encoder) throws { open override func encode(to encoder: Encoder) throws {

View File

@ -52,7 +52,7 @@ import Foundation
open override func reset() { open override func reset() {
super.reset() super.reset()
label.setFontStyle(.BoldBodySmall) label.setFontStyle(.BoldBodySmall)
label.textColor = .white label.textColor = .black
label.textAlignment = .center label.textAlignment = .center
} }

View File

@ -5,9 +5,9 @@
// Created by Scott Pfeil on 9/15/20. // Created by Scott Pfeil on 9/15/20.
// Copyright © 2020 Verizon Wireless. All rights reserved. // Copyright © 2020 Verizon Wireless. All rights reserved.
// //
import VDS
open class NotificationMoleculeModel: MoleculeModelProtocol {
open class NotificationMoleculeModel: ContainerModel, MoleculeModelProtocol {
/** /**
The style of the notification: The style of the notification:
@ -21,91 +21,48 @@ open class NotificationMoleculeModel: ContainerModel, MoleculeModelProtocol {
case error case error
case warning case warning
case information case information
var toVDSStyle: VDS.Notification.Style {
switch self {
case .success:
.success
case .error:
.error
case .warning:
.warning
case .information:
.info
}
}
} }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Properties // MARK: - Properties
//-------------------------------------------------- //--------------------------------------------------
public var id: String = UUID().uuidString
public class var identifier: String { "notification" } public class var identifier: String { "notification" }
public var accessibilityIdentifier: String? public var accessibilityIdentifier: String?
public var backgroundColor: Color? public var backgroundColor: Color?
public var headline: LabelModel public var headline: LabelModel
public var body: LabelModel? public var body: LabelModel?
public var button: ButtonModel? public var button: ButtonModel?
public var secondaryButton: ButtonModel?
public var closeButton: NotificationXButtonModel? public var closeButton: NotificationXButtonModel?
public var style: NotificationMoleculeModel.Style = .success public var style: Style = .success
public var inverted: Bool = false
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Initializer // MARK: - Initializer
//-------------------------------------------------- //--------------------------------------------------
public init(with headline: LabelModel, style: NotificationMoleculeModel.Style = .success, backgroundColor: Color? = nil, body: LabelModel? = nil, button: ButtonModel? = nil, closeButton: NotificationXButtonModel? = nil) { public init(with headline: LabelModel, style: NotificationMoleculeModel.Style = .success, backgroundColor: Color? = nil, body: LabelModel? = nil, button: ButtonModel? = nil, secondaryButton: ButtonModel? = nil, closeButton: NotificationXButtonModel? = nil) {
self.headline = headline self.headline = headline
self.style = style self.style = style
self.backgroundColor = backgroundColor self.backgroundColor = backgroundColor
self.body = body self.body = body
self.button = button self.button = button
self.secondaryButton = secondaryButton
self.closeButton = closeButton self.closeButton = closeButton
super.init()
}
//--------------------------------------------------
// MARK: - Default
//--------------------------------------------------
open override func setDefaults() {
useHorizontalMargins = true
useVerticalMargins = true
topPadding = PaddingTwo
bottomPadding = PaddingTwo
if backgroundColor == nil {
switch style {
case .error:
backgroundColor = Color(uiColor: .mvmOrange)
case .warning:
backgroundColor = Color(uiColor: .mvmYellow)
case .information:
backgroundColor = Color(uiColor: .mvmBlue)
default:
backgroundColor = Color(uiColor: .mvmGreen)
}
}
if headline.textColor == nil {
switch style {
case .error, .warning:
headline.textColor = Color(uiColor: .mvmBlack)
default:
headline.textColor = Color(uiColor: .mvmWhite)
}
}
if body?.textColor == nil {
switch style {
case .error, .warning:
body?.textColor = Color(uiColor: .mvmBlack)
default:
body?.textColor = Color(uiColor: .mvmWhite)
}
}
button?.size = .small
button?.style = .secondary
switch style {
case .error, .warning:
button?.inverted = false
default:
button?.inverted = true
}
if closeButton?.color == nil {
switch style {
case .error, .warning:
closeButton?.color = Color(uiColor: .mvmBlack)
default:
closeButton?.color = Color(uiColor: .mvmWhite)
}
}
} }
//-------------------------------------------------- //--------------------------------------------------
@ -119,7 +76,9 @@ open class NotificationMoleculeModel: ContainerModel, MoleculeModelProtocol {
case headline case headline
case body case body
case button case button
case secondaryButton
case closeButton case closeButton
case inverted
case style case style
} }
@ -129,27 +88,34 @@ open class NotificationMoleculeModel: ContainerModel, MoleculeModelProtocol {
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)
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier) accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
headline = try typeContainer.decode(LabelModel.self, forKey: .headline) headline = try typeContainer.decode(LabelModel.self, forKey: .headline)
body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body) body = try typeContainer.decodeIfPresent(LabelModel.self, forKey: .body)
button = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .button) button = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .button)
secondaryButton = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .secondaryButton)
closeButton = try typeContainer.decodeIfPresent(NotificationXButtonModel.self, forKey: .closeButton) closeButton = try typeContainer.decodeIfPresent(NotificationXButtonModel.self, forKey: .closeButton)
inverted = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) ?? false
if let style = try typeContainer.decodeIfPresent(NotificationMoleculeModel.Style.self, forKey: .style) { if let style = try typeContainer.decodeIfPresent(NotificationMoleculeModel.Style.self, forKey: .style) {
self.style = style self.style = style
} }
super.init()
} }
open override func encode(to encoder: Encoder) throws { open func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self) var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(moleculeName, forKey: .moleculeName) try container.encode(moleculeName, forKey: .moleculeName)
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier) try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
try container.encode(headline, forKey: .headline) try container.encode(headline, forKey: .headline)
try container.encodeIfPresent(body, forKey: .body) try container.encodeIfPresent(body, forKey: .body)
try container.encodeIfPresent(button, forKey: .button) try container.encodeIfPresent(button, forKey: .button)
try container.encodeIfPresent(secondaryButton, forKey: .secondaryButton)
try container.encodeIfPresent(closeButton, forKey: .closeButton) try container.encodeIfPresent(closeButton, forKey: .closeButton)
try container.encodeIfPresent(inverted, forKey: .inverted)
try container.encode(style, forKey: .style) try container.encode(style, forKey: .style)
} }
} }
extension NotificationMoleculeModel {
public var surface: Surface {
inverted ? .dark : .light
}
}

View File

@ -7,90 +7,101 @@
// //
import Foundation import Foundation
import VDS
@objcMembers open class NotificationMoleculeView: Container { @objcMembers open class NotificationMoleculeView: VDS.Notification, VDSMoleculeViewProtocol {
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
open var viewModel: NotificationMoleculeModel!
public var delegateObject: MVMCoreUIDelegateObject?
public var additionalData: [AnyHashable: Any]?
//--------------------------------------------------
// MARK: - VDSMoleculeViewProtocol
//--------------------------------------------------
open func viewModelDidUpdate() {
surface = viewModel.surface
title = viewModel.headline.text
subTitle = viewModel.body?.text
if let button = viewModel.button {
primaryButtonModel = .init(text: button.title, onClick: {[weak self] _ in
guard let self else { return }
self.executeAction(model: button, delegateObject: self.delegateObject, additionalData: self.additionalData)
})
}
if let secondaryButton = viewModel.secondaryButton {
secondaryButtonModel = .init(text: secondaryButton.title, onClick: {[weak self] _ in
guard let self else { return }
self.executeAction(model: secondaryButton, delegateObject: self.delegateObject, additionalData: self.additionalData)
})
}
if let accessibilityIdentifier = viewModel.accessibilityIdentifier {
self.accessibilityIdentifier = accessibilityIdentifier
}
if let closeButton = viewModel.closeButton {
onCloseClick = { [weak self] _ in
guard let self else { return }
self.executeAction(model: closeButton, delegateObject: self.delegateObject, additionalData: self.additionalData) }
}
hideCloseButton = viewModel.closeButton == nil
style = viewModel.style.toVDSStyle
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Outlets // MARK: - Outlets
//-------------------------------------------------- //--------------------------------------------------
public let headline = Label(fontStyle: .BoldBodySmall)
public let body = Label(fontStyle: .RegularBodySmall)
public let button = PillButton()
public let closeButton = NotificationXButton()
public var labelStack: Stack<StackModel>!
public var horizontalStack: Stack<StackModel>!
// Legacy constant // Legacy constant
private static let viewHeight: CGFloat = 96.0 private static let viewHeight: CGFloat = 96.0
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Life Cycle // MARK: - Life Cycle
//-------------------------------------------------- //--------------------------------------------------
open override func updateAccessibility() {
public override func setupView() { super.updateAccessibility()
super.setupView() Self.amendAccesibilityLabel(for: titleLabel)
reset() Self.amendAccesibilityLabel(for: subTitleLabel)
Self.amendAccesibilityLabel(for: primaryButton)
// Buttons should have highest priority, then headline, then body Self.amendAccesibilityLabel(for: secondaryButton)
headline.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 500), for: .horizontal) Self.amendAccesibilityLabel(for: closeButton)
headline.setContentHuggingPriority(.required, for: .vertical)
body.setContentCompressionResistancePriority(UILayoutPriority(rawValue: 500), for: .horizontal)
body.setContentHuggingPriority(.required, for: .vertical)
headline.setContentCompressionResistancePriority(UILayoutPriority(rawValue: body.contentCompressionResistancePriority(for: .vertical).rawValue + 40), for: .vertical)
headline.lineBreakMode = .byTruncatingTail
body.lineBreakMode = .byTruncatingTail
button.setContentCompressionResistancePriority(.defaultHigh, for: .horizontal)
labelStack = Stack<StackModel>.createStack(with: [headline, body], spacing: 0)
horizontalStack = Stack<StackModel>.createStack(with: [(view: labelStack, model: StackItemModel()),(view: button, model: StackItemModel(horizontalAlignment: .fill)),(view: closeButton, model: StackItemModel(horizontalAlignment: .fill))], axis: .horizontal)
addAndContain(horizontalStack)
labelStack.restack()
horizontalStack.restack()
heightAnchor.constraint(equalToConstant: Self.viewHeight).isActive = true
}
open override func reset() {
super.reset()
backgroundColor = .mvmGreen()
headline.textColor = .white
body.textColor = .white
} }
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Molecule // MARK: - Molecule
//-------------------------------------------------- //--------------------------------------------------
public func updateView(_ size: CGFloat) { }
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
super.set(with: model, delegateObject, additionalData) open class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
guard let model = model as? NotificationMoleculeModel else { return }
labelStack.updateContainedMolecules(with: [model.headline, model.body], delegateObject, nil)
horizontalStack.updateContainedMolecules(with: [labelStack.stackModel, model.button, model.closeButton], delegateObject, nil)
updateAccessibility()
}
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
return viewHeight return viewHeight
} }
open func updateAccessibility() {
NotificationMoleculeView.amendAccesibilityLabel(for: headline)
NotificationMoleculeView.amendAccesibilityLabel(for: body)
NotificationMoleculeView.amendAccesibilityLabel(for: button)
NotificationMoleculeView.amendAccesibilityLabel(for: closeButton)
}
/// Formats the accessibilityLabel so voice over users know it's in the notification. /// Formats the accessibilityLabel so voice over users know it's in the notification.
static public func amendAccesibilityLabel(for view: UIView) { public class func amendAccesibilityLabel(for view: UIView?) {
guard let amendment = MVMCoreUIUtility.hardcodedString(withKey: "top_alert_notification"), guard let view,
let accessibilityLabel = view.accessibilityLabel, let amendment = MVMCoreUIUtility.hardcodedString(withKey: "top_alert_notification")
!accessibilityLabel.hasPrefix(amendment) else { return } else { return }
view.accessibilityLabel = "\(amendment) - \(accessibilityLabel)" view.amendAccesibilityLabel(with: amendment)
} }
} }
extension NotificationMoleculeView: AccessibilityProtocol { extension NotificationMoleculeView: AccessibilityProtocol {
public func getAccessibilityLayoutChangedArgument() -> Any? { public func getAccessibilityLayoutChangedArgument() -> Any? {
return headline return titleLabel
}
}
extension UIView {
/// Formats the accessibilityLabel so voice over users know it's in the notification.
public func amendAccesibilityLabel(with amendment: String) {
guard let accessibilityLabel, !accessibilityLabel.hasPrefix(amendment) else { return }
self.accessibilityLabel = "\(amendment) - \(accessibilityLabel)"
} }
} }

View File

@ -30,7 +30,6 @@ import MVMCore
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) { open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable : Any]?) {
super.set(with: model, delegateObject, additionalData) super.set(with: model, delegateObject, additionalData)
guard let model = model as? NotificationXButtonModel else { return } guard let model = model as? NotificationXButtonModel else { return }
tintColor = model.color?.uiColor ?? .white
// TODO: Temporary, consider action for dismissing top alert // TODO: Temporary, consider action for dismissing top alert
if model.action.actionType == ActionNoopModel.identifier { if model.action.actionType == ActionNoopModel.identifier {

View File

@ -15,25 +15,21 @@ public class NotificationXButtonModel: ButtonModelProtocol, MoleculeModelProtoco
public var id: String = UUID().uuidString public var id: String = UUID().uuidString
public var backgroundColor: Color? public var backgroundColor: Color?
public var color: Color?
public var action: ActionModelProtocol = ActionNoopModel() public var action: ActionModelProtocol = ActionNoopModel()
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case id case id
case moleculeName case moleculeName
case color
case action case action
} }
public init(color: Color? = nil, action: ActionModelProtocol = ActionNoopModel()) { public init(action: ActionModelProtocol = ActionNoopModel()) {
self.color = color
self.action = action self.action = action
} }
public required init(from decoder: Decoder) throws { public required 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
color = try typeContainer.decodeIfPresent(Color.self, forKey: .color)
if let action: ActionModelProtocol = try typeContainer.decodeModelIfPresent(codingKey: .action) { if let action: ActionModelProtocol = try typeContainer.decodeModelIfPresent(codingKey: .action) {
self.action = action self.action = action
} }
@ -43,7 +39,6 @@ public class NotificationXButtonModel: ButtonModelProtocol, MoleculeModelProtoco
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.encodeIfPresent(color, forKey: .color)
try container.encodeModel(action, forKey: .action) try container.encodeModel(action, forKey: .action)
} }
} }

View File

@ -66,6 +66,14 @@ extension MoleculeViewProtocol {
set(with: model, delegateObject, additionalData) set(with: model, delegateObject, additionalData)
} }
} }
public func executeAction<T: ButtonModelProtocol & MoleculeModelProtocol>(model: T, delegateObject: MVMCoreUIDelegateObject?, additionalData: [AnyHashable: Any]?) {
Task(priority: .userInitiated) {
try await (delegateObject?.actionDelegate as? ActionDelegateProtocol)?.performAction(with: model.action,
additionalData: MVMCoreUIActionHandler.add(sourceModel: model, to: additionalData),
delegateObject: delegateObject)
}
}
} }
// Convenience Functions // Convenience Functions

View File

@ -21,7 +21,11 @@ public protocol VDSMoleculeViewProtocol: MoleculeViewProtocol, MVMCoreViewProtoc
} }
extension VDSMoleculeViewProtocol { extension VDSMoleculeViewProtocol {
public var model: MoleculeModelProtocol {
get { viewModel }
set { }
}
public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) { public func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
self.model = model self.model = model
guard let castedModel = model as? ViewModel else { return } guard let castedModel = model as? ViewModel else { return }

View File

@ -56,6 +56,18 @@ extension UIColor {
"upGold2": (.vzupGold2, "#F4CA53"), "upGold2": (.vzupGold2, "#F4CA53"),
"upGold3": (.vzupGold3, "#CC9B2D")] "upGold3": (.vzupGold3, "#CC9B2D")]
//--------------------------------------------------
// MARK: - Helper
//--------------------------------------------------
public var rgbComponents: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
var red: CGFloat = 0
var green: CGFloat = 0
var blue: CGFloat = 0
var alpha: CGFloat = 0
getRed(&red, green: &green, blue: &blue, alpha: &alpha)
return (red, green, blue, alpha)
}
//-------------------------------------------------- //--------------------------------------------------
// MARK: - Brand // MARK: - Brand
//-------------------------------------------------- //--------------------------------------------------