Merge branch 'feature/VDS_Button' into 'feature/develop_mvp_3'
Feature/vds button See merge request BPHV_MIPS/mvm_core_ui!821
This commit is contained in:
commit
0492a3fa5d
@ -7,6 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
import VDSColorTokens
|
||||
|
||||
public typealias FacadeElements = (fill: UIColor?, text: UIColor?, border: UIColor?)
|
||||
|
||||
@ -17,12 +18,12 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
//--------------------------------------------------
|
||||
//Making static property as class property so that subclasses can override getter function of the property
|
||||
open class var identifier: String { "button" }
|
||||
public var backgroundColor: Color?
|
||||
public var accessibilityIdentifier: String?
|
||||
public var accessibilityText: String?
|
||||
public var title: String
|
||||
public var action: ActionModelProtocol
|
||||
public var enabled: Bool = true
|
||||
public var width: CGFloat?
|
||||
public var style: Styler.Button.Style? {
|
||||
didSet {
|
||||
guard let style = style else { return }
|
||||
@ -57,6 +58,20 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
public var disabledTextColor_inverted: Color?
|
||||
public var disabledBorderColor_inverted: Color?
|
||||
|
||||
private var _backgroundColor: Color?
|
||||
public var backgroundColor: Color? {
|
||||
get {
|
||||
if let backgroundColor = _backgroundColor { return backgroundColor }
|
||||
if inverted {
|
||||
return enabled ? enabledFillColor_inverted : disabledFillColor_inverted
|
||||
}
|
||||
return enabled ? enabledFillColor : disabledFillColor
|
||||
}
|
||||
set {
|
||||
_backgroundColor = newValue
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
@ -70,18 +85,21 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
public init(with title: String, action: ActionModelProtocol) {
|
||||
self.title = title
|
||||
self.action = action
|
||||
setFacade(by: .primary)
|
||||
}
|
||||
|
||||
public init(secondaryButtonWith title: String, action: ActionModelProtocol) {
|
||||
self.title = title
|
||||
self.action = action
|
||||
style = .secondary
|
||||
setFacade(by: .secondary)
|
||||
}
|
||||
|
||||
public init(primaryButtonWith title: String, action: ActionModelProtocol) {
|
||||
self.title = title
|
||||
self.action = action
|
||||
style = .primary
|
||||
setFacade(by: .primary)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -114,40 +132,30 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
|
||||
/// Defines the default appearance for the primary style.
|
||||
func setPrimaryFacade() {
|
||||
enabledFillColor = Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
enabledTextColor = Color(uiColor: VDSColor.elementsPrimaryOndark)
|
||||
disabledFillColor = Color(uiColor: VDSColor.interactiveDisabledOnlight)
|
||||
disabledTextColor = Color(uiColor: VDSColor.elementsPrimaryOndark)
|
||||
|
||||
if enabledFillColor == nil && enabledTextColor == nil {
|
||||
enabledFillColor = Color(uiColor: .mvmBlack)
|
||||
enabledTextColor = Color(uiColor: .mvmWhite)
|
||||
}
|
||||
|
||||
if disabledFillColor == nil && disabledTextColor == nil {
|
||||
disabledFillColor = Color(uiColor: .mvmCoolGray6)
|
||||
disabledTextColor = Color(uiColor: .mvmWhite)
|
||||
}
|
||||
|
||||
enabledFillColor_inverted = Color(uiColor: .mvmWhite)
|
||||
enabledTextColor_inverted = Color(uiColor: .mvmBlack)
|
||||
disabledFillColor_inverted = Color(uiColor: .mvmCoolGray6)
|
||||
disabledTextColor_inverted = Color(uiColor: .mvmBlack)
|
||||
enabledFillColor_inverted = Color(uiColor: VDSColor.elementsPrimaryOndark)
|
||||
enabledTextColor_inverted = Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
disabledFillColor_inverted = Color(uiColor: VDSColor.interactiveDisabledOndark)
|
||||
disabledTextColor_inverted = Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
}
|
||||
|
||||
/// Defines the default appearance for the Secondary style.
|
||||
func setSecondaryFacade() {
|
||||
enabledTextColor = Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
enabledFillColor = Color(uiColor: UIColor.clear)
|
||||
enabledBorderColor = Color(uiColor: VDSColor.elementsPrimaryOnlight)
|
||||
disabledTextColor = Color(uiColor: VDSColor.interactiveDisabledOnlight)
|
||||
disabledBorderColor = Color(uiColor: VDSColor.interactiveDisabledOnlight)
|
||||
|
||||
if enabledTextColor == nil && enabledBorderColor == nil {
|
||||
enabledTextColor = Color(uiColor: .mvmBlack)
|
||||
enabledBorderColor = Color(uiColor: .mvmBlack)
|
||||
}
|
||||
|
||||
if disabledTextColor == nil && disabledBorderColor == nil {
|
||||
disabledTextColor = Color(uiColor: .mvmCoolGray6)
|
||||
disabledBorderColor = Color(uiColor: .mvmCoolGray6)
|
||||
}
|
||||
|
||||
enabledTextColor_inverted = Color(uiColor: .mvmWhite)
|
||||
enabledBorderColor_inverted = Color(uiColor: .mvmWhite)
|
||||
disabledTextColor_inverted = Color(uiColor: .mvmCoolGray6)
|
||||
disabledBorderColor_inverted = Color(uiColor: .mvmCoolGray6)
|
||||
enabledTextColor_inverted = Color(uiColor: VDSColor.elementsPrimaryOndark)
|
||||
enabledFillColor_inverted = Color(uiColor: UIColor.clear)
|
||||
enabledBorderColor_inverted = Color(uiColor: VDSColor.elementsPrimaryOndark)
|
||||
disabledTextColor_inverted = Color(uiColor: VDSColor.interactiveDisabledOndark)
|
||||
disabledBorderColor_inverted = Color(uiColor: VDSColor.interactiveDisabledOndark)
|
||||
}
|
||||
|
||||
public func setFacade(by style: Styler.Button.Style) {
|
||||
@ -183,6 +191,7 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
case disabledFillColor
|
||||
case disabledTextColor
|
||||
case disabledBorderColor
|
||||
case width
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -192,7 +201,6 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
|
||||
accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
|
||||
title = try typeContainer.decode(String.self, forKey: .title)
|
||||
@ -201,6 +209,8 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
if let style = try typeContainer.decodeIfPresent(Styler.Button.Style.self, forKey: .style) {
|
||||
self.style = style
|
||||
setFacade(by: style)
|
||||
} else {
|
||||
setFacade(by: .primary)
|
||||
}
|
||||
|
||||
if let size = try typeContainer.decodeIfPresent(Styler.Button.Size.self, forKey: .size) {
|
||||
@ -242,6 +252,9 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
if let disabledBorderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledBorderColor) {
|
||||
self.disabledBorderColor = disabledBorderColor
|
||||
}
|
||||
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
width = try typeContainer.decodeIfPresent(CGFloat.self, forKey: .width)
|
||||
}
|
||||
|
||||
open func encode(to encoder: Encoder) throws {
|
||||
@ -251,7 +264,7 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encode(inverted, forKey: .inverted)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(_backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
|
||||
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
|
||||
try container.encodeIfPresent(enabledFillColor, forKey: .fillColor)
|
||||
@ -263,5 +276,6 @@ open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWat
|
||||
try container.encodeIfPresent(style, forKey: .style)
|
||||
try container.encodeIfPresent(size, forKey: .size)
|
||||
try container.encodeIfPresent(groupName, forKey: .groupName)
|
||||
try container.encodeIfPresent(width, forKey: .width)
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@
|
||||
//
|
||||
|
||||
import UIKit
|
||||
|
||||
import VDSColorTokens
|
||||
|
||||
open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
//--------------------------------------------------
|
||||
@ -23,21 +23,29 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
|
||||
/// Need to re-style on set.
|
||||
open override var isEnabled: Bool {
|
||||
didSet { style() }
|
||||
didSet { style(with: buttonModel) }
|
||||
}
|
||||
|
||||
open var buttonSize: Styler.Button.Size = .standard {
|
||||
didSet { buttonModel?.size = buttonSize }
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
|
||||
public var widthConstraint: NSLayoutConstraint?
|
||||
public var minimumWidthConstraint: NSLayoutConstraint?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
@objc public convenience init(asPrimaryButton isPrimary: Bool, makeTiny istiny: Bool) {
|
||||
self.init()
|
||||
buttonSize = istiny ? .tiny : .standard
|
||||
isPrimary ? stylePrimary() : styleSecondary()
|
||||
let model = ButtonModel(with: "", action: ActionNoopModel())
|
||||
model.style = isPrimary ? .primary : .secondary
|
||||
model.size = istiny ? .tiny : .standard
|
||||
self.init(model: model, nil, nil)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -68,39 +76,26 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
|
||||
/// The primary styling for a button. Should be used for main buttons
|
||||
public func stylePrimary() {
|
||||
|
||||
enabledTitleColor = buttonModel?.enabledColors.text ?? .mvmWhite
|
||||
disabledTitleColor = buttonModel?.disabledColors.text ?? .mvmWhite
|
||||
layer.borderWidth = 0
|
||||
backgroundColor = isEnabled ? buttonModel?.enabledColors.fill ?? .mvmBlack : buttonModel?.disabledColors.fill ?? .mvmCoolGray6
|
||||
let buttonModel = ButtonModel(primaryButtonWith: "", action: ActionNoopModel())
|
||||
style(with: buttonModel)
|
||||
}
|
||||
|
||||
/// The secondary styling for a button. Should be used for secondary buttons
|
||||
public func styleSecondary() {
|
||||
|
||||
enabledTitleColor = buttonModel?.enabledColors.text ?? .mvmBlack
|
||||
disabledTitleColor = buttonModel?.disabledColors.text ?? .mvmCoolGray6
|
||||
backgroundColor = .clear
|
||||
layer.borderWidth = 1
|
||||
borderColor = isEnabled ? buttonModel?.enabledColors.border ?? .mvmBlack : buttonModel?.disabledColors.border ?? .mvmCoolGray6
|
||||
let buttonModel = ButtonModel(secondaryButtonWith: "", action: ActionNoopModel())
|
||||
style(with: buttonModel)
|
||||
}
|
||||
|
||||
/// Styles the button based on the model style
|
||||
private func style() {
|
||||
private func style(with model: ButtonModel?) {
|
||||
|
||||
switch buttonModel?.style {
|
||||
case .secondary:
|
||||
styleSecondary()
|
||||
|
||||
default:
|
||||
stylePrimary()
|
||||
}
|
||||
layer.borderWidth = model?.style == .secondary ? 1 : 0
|
||||
|
||||
if let titleColor = buttonModel?.enabledColors.text {
|
||||
if let titleColor = model?.enabledColors.text {
|
||||
enabledTitleColor = titleColor
|
||||
}
|
||||
|
||||
if let disabledTitleColor = buttonModel?.disabledColors.text {
|
||||
if let disabledTitleColor = model?.disabledColors.text {
|
||||
self.disabledTitleColor = disabledTitleColor
|
||||
}
|
||||
|
||||
@ -110,72 +105,46 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
#endif
|
||||
|
||||
if isEnabled {
|
||||
if let fillColor = buttonModel?.enabledColors.fill {
|
||||
if let fillColor = model?.enabledColors.fill {
|
||||
backgroundColor = fillColor
|
||||
}
|
||||
|
||||
if let borderColor = buttonModel?.enabledColors.border {
|
||||
layer.borderWidth = 1
|
||||
if let borderColor = model?.enabledColors.border {
|
||||
self.borderColor = borderColor
|
||||
}
|
||||
} else {
|
||||
if let fillColor = buttonModel?.disabledColors.fill {
|
||||
if let fillColor = model?.disabledColors.fill {
|
||||
backgroundColor = fillColor
|
||||
}
|
||||
|
||||
if let borderColor = buttonModel?.disabledColors.border {
|
||||
layer.borderWidth = 1
|
||||
if let borderColor = model?.disabledColors.border {
|
||||
self.borderColor = borderColor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func getInnerPadding() -> CGFloat {
|
||||
getHeight() / 2.0
|
||||
buttonSize.getHeight() / 2.0
|
||||
}
|
||||
|
||||
private func getHeight() -> CGFloat {
|
||||
PillButton.getHeight(for: buttonSize, size: size)
|
||||
}
|
||||
|
||||
public static func getHeight(for buttonSize: Styler.Button.Size?, size: CGFloat) -> CGFloat {
|
||||
|
||||
private func getContentEdgeInsets() -> UIEdgeInsets {
|
||||
var verticalPadding = 0.0
|
||||
var horizontalPadding = 0.0
|
||||
switch buttonSize {
|
||||
case .standard:
|
||||
verticalPadding = Padding.Three
|
||||
horizontalPadding = Padding.Five
|
||||
break
|
||||
case .small:
|
||||
verticalPadding = Padding.Two
|
||||
horizontalPadding = Padding.Four
|
||||
break
|
||||
case .tiny:
|
||||
let tinyHeight = Styler.Button.Size.tiny.getHeight()
|
||||
return MFSizeObject(standardSize: tinyHeight,
|
||||
standardiPadPortraitSize: 34,
|
||||
iPadProLandscapeSize: 38)?.getValueBased(onSize: size) ?? tinyHeight
|
||||
|
||||
default:
|
||||
let standardHeight = Styler.Button.Size.standard.getHeight()
|
||||
return MFSizeObject(standardSize: standardHeight,
|
||||
standardiPadPortraitSize: 46,
|
||||
iPadProLandscapeSize: 50)?.getValueBased(onSize: size) ?? standardHeight
|
||||
}
|
||||
}
|
||||
|
||||
private func getMinimumWidth() -> CGFloat {
|
||||
|
||||
switch buttonSize {
|
||||
case .tiny:
|
||||
return MFSizeObject(standardSize: 49,
|
||||
standardiPadPortraitSize: 90,
|
||||
iPadProLandscapeSize: 135)?.getValueBased(onSize: size) ?? 49
|
||||
|
||||
default: return 151
|
||||
}
|
||||
}
|
||||
|
||||
open override var intrinsicContentSize: CGSize {
|
||||
if buttonSize == .tiny {
|
||||
let size = super.intrinsicContentSize
|
||||
let width = size.width + (2 * getInnerPadding())
|
||||
return CGSize(width: max(width, getMinimumWidth()), height: getHeight())
|
||||
} else {
|
||||
let width = Padding.Component.gutterForApplicationWidth + (2.0 * Padding.Component.columnFor(size: MVMCoreUISplitViewController.getApplicationViewWidth()))
|
||||
return CGSize(width: min(292, width), height: getHeight())
|
||||
verticalPadding = Padding.One
|
||||
horizontalPadding = Padding.Two
|
||||
break
|
||||
}
|
||||
return UIEdgeInsets(top: verticalPadding, left: horizontalPadding, bottom: verticalPadding, right: horizontalPadding)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -187,6 +156,7 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
|
||||
guard let model = model as? ButtonModel else { return }
|
||||
|
||||
setTitle(model.title, for: .normal)
|
||||
if let accessibilityText = model.accessibilityText {
|
||||
accessibilityLabel = accessibilityText
|
||||
@ -206,24 +176,44 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
}
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
PillButton.getHeight(for: (model as? ButtonModel)?.size, size: MVMCoreUIUtility.getWidth())
|
||||
return (model as? ButtonModel)?.size?.getHeight()
|
||||
}
|
||||
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
self.size = size
|
||||
|
||||
invalidateIntrinsicContentSize()
|
||||
|
||||
switch buttonSize {
|
||||
case .tiny:
|
||||
titleLabel?.font = MFFonts.mfFont75Bd(11 * (intrinsicContentSize.height / Styler.Button.Size.tiny.getHeight()))
|
||||
|
||||
default:
|
||||
titleLabel?.font = MFFonts.mfFont75Bd(13 * (intrinsicContentSize.height / Styler.Button.Size.standard.getHeight()))
|
||||
titleLabel?.font = Styler.Font.BoldMicro.getFont()
|
||||
case .small:
|
||||
titleLabel?.font = Styler.Font.BoldBodySmall.getFont()
|
||||
case .standard:
|
||||
titleLabel?.font = Styler.Font.BoldBodyLarge.getFont()
|
||||
}
|
||||
|
||||
layer.cornerRadius = getInnerPadding()
|
||||
contentEdgeInsets = getContentEdgeInsets()
|
||||
|
||||
if let contraint = buttonModel?.width {
|
||||
|
||||
if widthConstraint == nil {
|
||||
widthConstraint = widthAnchor.constraint(equalToConstant: contraint)
|
||||
} else if widthConstraint?.constant != contraint {
|
||||
widthConstraint?.constant = contraint
|
||||
}
|
||||
widthConstraint?.isActive = true
|
||||
minimumWidthConstraint?.isActive = false
|
||||
} else {
|
||||
|
||||
if minimumWidthConstraint == nil {
|
||||
minimumWidthConstraint = widthAnchor.constraint(greaterThanOrEqualToConstant: buttonSize.minimumWidth())
|
||||
} else {
|
||||
minimumWidthConstraint?.constant = buttonSize.minimumWidth()
|
||||
}
|
||||
minimumWidthConstraint?.isActive = true
|
||||
widthConstraint?.isActive = false
|
||||
}
|
||||
}
|
||||
|
||||
open override func setupView() {
|
||||
|
||||
@ -178,20 +178,33 @@ open class Styler {
|
||||
case primary
|
||||
case secondary
|
||||
}
|
||||
|
||||
///MVA 3.0 - Button sizes are standard(default size), small, Tiny. Tiny button has been depricated as of Rebranding 3.0.
|
||||
public enum Size: String, Codable {
|
||||
case standard
|
||||
case small
|
||||
case tiny
|
||||
|
||||
func getHeight() -> CGFloat {
|
||||
switch self {
|
||||
case .standard:
|
||||
return 42
|
||||
|
||||
return 44
|
||||
case .small:
|
||||
return 32
|
||||
case .tiny:
|
||||
return 20
|
||||
}
|
||||
}
|
||||
|
||||
func minimumWidth() -> CGFloat {
|
||||
switch self {
|
||||
case .standard:
|
||||
return 76
|
||||
case .small:
|
||||
return 0
|
||||
case .tiny:
|
||||
return 49
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -204,7 +204,6 @@
|
||||
|
||||
// Sets up to use a button action. Always uses the top view controller
|
||||
PillButton *button = [[PillButton alloc] initAsPrimaryButton:false makeTiny:true];
|
||||
[button styleSecondary];
|
||||
[button setContentCompressionResistancePriority:UILayoutPriorityDefaultHigh forAxis:UILayoutConstraintAxisHorizontal];
|
||||
[button setContentHuggingPriority:800 forAxis:UILayoutConstraintAxisHorizontal];
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user