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:
Pfeil, Scott Robert 2022-05-09 17:54:36 +00:00
commit 0492a3fa5d
4 changed files with 130 additions and 114 deletions

View File

@ -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)
}
}

View File

@ -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() {

View File

@ -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
}
}
}
}

View File

@ -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];