Merge branch 'develop' into feature/revised_accessibility
This commit is contained in:
commit
3abe936d7d
@ -2103,7 +2103,7 @@
|
||||
0A7BAFA1232BE61800FB8E22 /* Checkbox.swift in Sources */,
|
||||
011B58F023A2AA980085F53C /* ListItemModelProtocol.swift in Sources */,
|
||||
D22479962316AF6E003FCCF9 /* HeadlineBodyLink.swift in Sources */,
|
||||
8DE5BECD2456F7A200772E76 /* ListTwoColumnDropdownSelectorsModel.swift in Sources */,
|
||||
8DE5BECD2456F7A200772E76 /* ListTwoColumnDropdownSelectorsModel.swift in Sources */,
|
||||
0A41BA7F23453A6400D4C0BC /* TextEntryField.swift in Sources */,
|
||||
BB55B51D244482C1002001AD /* ListRightVariablePriceChangeBodyText.swift in Sources */,
|
||||
017BEB382360C6AC0024EF95 /* RadioButtonLabel.swift in Sources */,
|
||||
|
||||
@ -8,40 +8,75 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
public enum ButtonStyle: String, Codable {
|
||||
case primary
|
||||
case secondary
|
||||
}
|
||||
public typealias FacadeElements = (fill: UIColor?, text: UIColor?, border: UIColor?)
|
||||
|
||||
public enum ButtonSize: String, Codable {
|
||||
case standard
|
||||
case tiny
|
||||
}
|
||||
|
||||
public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWatcherFieldProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var identifier: String = "button"
|
||||
public var backgroundColor: Color?
|
||||
public var title: String
|
||||
public var action: ActionModelProtocol
|
||||
public var enabled: Bool = true
|
||||
public var style: ButtonStyle?
|
||||
public var size: ButtonSize? = .standard
|
||||
public var fillColor: Color?
|
||||
public var textColor: Color?
|
||||
public var borderColor: Color?
|
||||
public var style: Styler.Button.Style? {
|
||||
didSet {
|
||||
guard let style = style else { return }
|
||||
switch style {
|
||||
case .primary:
|
||||
setPrimaryFacade()
|
||||
|
||||
case .secondary:
|
||||
setSecondaryFacade()
|
||||
}
|
||||
}
|
||||
}
|
||||
public var size: Styler.Button.Size? = .standard
|
||||
public var groupName: String = ""
|
||||
public var inverted: Bool = false
|
||||
|
||||
public lazy var enabledColors: FacadeElements = (fill: enabled_fillColor(),
|
||||
text: enabled_textColor(),
|
||||
border: enabled_borderColor())
|
||||
|
||||
public lazy var disabledColors: FacadeElements = (fill: disabled_fillColor(),
|
||||
text: disabled_textColor(),
|
||||
border: disabled_borderColor())
|
||||
|
||||
public var enabledFillColor: Color?
|
||||
public var enabledTextColor: Color?
|
||||
public var enabledBorderColor: Color?
|
||||
|
||||
public var enabledFillColor_inverted: Color?
|
||||
public var enabledTextColor_inverted: Color?
|
||||
public var enabledBorderColor_inverted: Color?
|
||||
|
||||
public var disabledFillColor: Color?
|
||||
public var disabledTextColor: Color?
|
||||
public var disabledBorderColor: Color?
|
||||
public var groupName: String = ""
|
||||
|
||||
|
||||
public var disabledFillColor_inverted: Color?
|
||||
public var disabledTextColor_inverted: Color?
|
||||
public var disabledBorderColor_inverted: Color?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
public func setValidity(_ valid: Bool, group: FormGroupRule) {
|
||||
enabled = valid
|
||||
updateUI?()
|
||||
}
|
||||
|
||||
|
||||
/// Temporary binding mechanism for the view to update on enable changes.
|
||||
public var updateUI: (() -> Void)?
|
||||
|
||||
public var updateUI: ActionBlock?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(with title: String, action: ActionModelProtocol) {
|
||||
self.title = title
|
||||
self.action = action
|
||||
@ -52,71 +87,173 @@ public class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupW
|
||||
self.action = action
|
||||
style = .secondary
|
||||
}
|
||||
|
||||
|
||||
public init(primaryButtonWith title: String, action: ActionModelProtocol) {
|
||||
self.title = title
|
||||
self.action = action
|
||||
style = .primary
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
public func enabled_fillColor() -> UIColor? {
|
||||
return (inverted ? enabledFillColor_inverted : enabledFillColor)?.uiColor
|
||||
}
|
||||
|
||||
public func enabled_textColor() -> UIColor? {
|
||||
return (inverted ? enabledTextColor_inverted : enabledTextColor)?.uiColor
|
||||
}
|
||||
|
||||
public func enabled_borderColor() -> UIColor? {
|
||||
return (inverted ? enabledBorderColor_inverted : enabledBorderColor)?.uiColor
|
||||
}
|
||||
|
||||
public func disabled_fillColor() -> UIColor? {
|
||||
return (inverted ? disabledFillColor_inverted : disabledFillColor)?.uiColor
|
||||
}
|
||||
|
||||
public func disabled_textColor() -> UIColor? {
|
||||
return (inverted ? disabledTextColor_inverted : disabledTextColor)?.uiColor
|
||||
}
|
||||
|
||||
public func disabled_borderColor() -> UIColor? {
|
||||
return (inverted ? disabledBorderColor_inverted : disabledBorderColor)?.uiColor
|
||||
}
|
||||
|
||||
/// Defines the default appearance for the primary style.
|
||||
func setPrimaryFacade() {
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
/// Defines the default appearance for the Secondary style.
|
||||
func setSecondaryFacade() {
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case title
|
||||
case inverted
|
||||
case action
|
||||
case enabled
|
||||
case style
|
||||
case size
|
||||
case groupName
|
||||
case fillColor
|
||||
case textColor
|
||||
case borderColor
|
||||
case disabledFillColor
|
||||
case disabledTextColor
|
||||
case disabledBorderColor
|
||||
case groupName
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
title = try typeContainer.decode(String.self, forKey: .title)
|
||||
action = try typeContainer.decodeModel(codingKey: .action)
|
||||
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
|
||||
self.groupName = groupName
|
||||
}
|
||||
if let style = try typeContainer.decodeIfPresent(ButtonStyle.self, forKey: .style) {
|
||||
|
||||
if let style = try typeContainer.decodeIfPresent(Styler.Button.Style.self, forKey: .style) {
|
||||
self.style = style
|
||||
}
|
||||
if let size = try typeContainer.decodeIfPresent(ButtonSize.self, forKey: .size) {
|
||||
|
||||
if let size = try typeContainer.decodeIfPresent(Styler.Button.Size.self, forKey: .size) {
|
||||
self.size = size
|
||||
}
|
||||
|
||||
if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
|
||||
self.enabled = enabled
|
||||
}
|
||||
fillColor = try typeContainer.decodeIfPresent(Color.self, forKey: .fillColor)
|
||||
textColor = try typeContainer.decodeIfPresent(Color.self, forKey: .textColor)
|
||||
borderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .borderColor)
|
||||
disabledFillColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledFillColor)
|
||||
disabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledTextColor)
|
||||
disabledBorderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledBorderColor)
|
||||
|
||||
if let inverted = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) {
|
||||
self.inverted = inverted
|
||||
}
|
||||
|
||||
if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
|
||||
self.groupName = groupName
|
||||
}
|
||||
|
||||
if let enabledFillColor = try typeContainer.decodeIfPresent(Color.self, forKey: .fillColor) {
|
||||
self.enabledFillColor = enabledFillColor
|
||||
}
|
||||
|
||||
if let enabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .textColor) {
|
||||
self.enabledTextColor = enabledTextColor
|
||||
}
|
||||
|
||||
if let enabledBorderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .borderColor) {
|
||||
self.enabledBorderColor = enabledBorderColor
|
||||
}
|
||||
|
||||
if let disabledFillColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledFillColor) {
|
||||
self.disabledFillColor = disabledFillColor
|
||||
}
|
||||
|
||||
if let disabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledTextColor) {
|
||||
self.disabledTextColor = disabledTextColor
|
||||
}
|
||||
|
||||
if let disabledBorderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledBorderColor) {
|
||||
self.disabledBorderColor = disabledBorderColor
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
try container.encode(title, forKey: .title)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
try container.encode(enabled, forKey: .enabled)
|
||||
try container.encodeIfPresent(style, forKey: .style)
|
||||
try container.encodeIfPresent(size, forKey: .size)
|
||||
try container.encodeIfPresent(fillColor, forKey: .fillColor)
|
||||
try container.encodeIfPresent(textColor, forKey: .textColor)
|
||||
try container.encodeIfPresent(borderColor, forKey: .borderColor)
|
||||
try container.encode(inverted, forKey: .inverted)
|
||||
try container.encodeModel(action, forKey: .action)
|
||||
try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
|
||||
try container.encodeIfPresent(enabledFillColor, forKey: .fillColor)
|
||||
try container.encodeIfPresent(enabledTextColor, forKey: .textColor)
|
||||
try container.encodeIfPresent(enabledBorderColor, forKey: .borderColor)
|
||||
try container.encodeIfPresent(disabledFillColor, forKey: .disabledFillColor)
|
||||
try container.encodeIfPresent(disabledTextColor, forKey: .disabledTextColor)
|
||||
try container.encodeIfPresent(disabledBorderColor, forKey: .disabledBorderColor)
|
||||
try container.encodeIfPresent(style, forKey: .style)
|
||||
try container.encodeIfPresent(size, forKey: .size)
|
||||
try container.encodeIfPresent(groupName, forKey: .groupName)
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,80 +8,105 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
// Used to size the button.
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
/// Used to size the button.
|
||||
var size = MVMCoreUIUtility.getWidth()
|
||||
|
||||
var buttonModel: ButtonModel? {
|
||||
get { return model as? ButtonModel }
|
||||
}
|
||||
|
||||
// Need to re-style on set.
|
||||
/// Need to re-style on set.
|
||||
open override var isEnabled: Bool {
|
||||
didSet {
|
||||
style()
|
||||
}
|
||||
didSet { style() }
|
||||
}
|
||||
|
||||
private enum ButtonHeight: CGFloat {
|
||||
case tiny = 20
|
||||
case standard = 42
|
||||
//--------------------------------------------------
|
||||
// MARK: - Computed Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public var enabledTitleColor: UIColor? {
|
||||
get { return titleColor(for: .normal) }
|
||||
set { setTitleColor(newValue, for: .normal) }
|
||||
}
|
||||
|
||||
public var disabledTitleColor: UIColor? {
|
||||
get { return titleColor(for: .disabled) }
|
||||
set { setTitleColor(newValue, for: .disabled) }
|
||||
}
|
||||
|
||||
public var borderColor: UIColor? {
|
||||
get {
|
||||
guard let currentColor = layer.borderColor else { return nil }
|
||||
return UIColor(cgColor: currentColor)
|
||||
}
|
||||
set { layer.borderColor = newValue?.cgColor }
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Methods
|
||||
//--------------------------------------------------
|
||||
|
||||
/// The primary styling for a button. Should be used for main buttons
|
||||
public func stylePrimary() {
|
||||
setTitleColor(.white, for: .normal)
|
||||
setTitleColor(.white, for: .disabled)
|
||||
|
||||
enabledTitleColor = buttonModel?.enabledColors.text ?? .mvmWhite
|
||||
disabledTitleColor = buttonModel?.disabledColors.text ?? .mvmWhite
|
||||
layer.borderWidth = 0
|
||||
if isEnabled {
|
||||
backgroundColor = .black
|
||||
} else {
|
||||
backgroundColor = .mvmCoolGray6
|
||||
}
|
||||
backgroundColor = isEnabled ? buttonModel?.enabledColors.fill ?? .mvmBlack : buttonModel?.disabledColors.fill ?? .mvmCoolGray6
|
||||
}
|
||||
|
||||
/// The secondary styling for a button. Should be used for secondary buttons
|
||||
public func styleSecondary() {
|
||||
setTitleColor(.black, for: .normal)
|
||||
setTitleColor(.mvmCoolGray6, for: .disabled)
|
||||
|
||||
enabledTitleColor = buttonModel?.enabledColors.text ?? .mvmBlack
|
||||
disabledTitleColor = buttonModel?.disabledColors.text ?? .mvmCoolGray6
|
||||
backgroundColor = .clear
|
||||
layer.borderWidth = 1
|
||||
if isEnabled {
|
||||
layer.borderColor = UIColor.black.cgColor
|
||||
} else {
|
||||
layer.borderColor = UIColor.mvmCoolGray6.cgColor
|
||||
}
|
||||
borderColor = isEnabled ? buttonModel?.enabledColors.border ?? .mvmBlack : buttonModel?.disabledColors.border ?? .mvmCoolGray6
|
||||
}
|
||||
|
||||
/// Styles the button based on the model style
|
||||
private func style() {
|
||||
|
||||
switch buttonModel?.style {
|
||||
case .secondary:
|
||||
styleSecondary()
|
||||
|
||||
default:
|
||||
stylePrimary()
|
||||
}
|
||||
if let titleColor = buttonModel?.textColor {
|
||||
setTitleColor(titleColor.uiColor, for: .normal)
|
||||
|
||||
if let titleColor = buttonModel?.enabledColors.text {
|
||||
enabledTitleColor = titleColor
|
||||
}
|
||||
if let disabledTitleColor = buttonModel?.disabledTextColor {
|
||||
setTitleColor(disabledTitleColor.uiColor, for: .disabled)
|
||||
|
||||
if let disabledTitleColor = buttonModel?.disabledColors.text {
|
||||
self.disabledTitleColor = disabledTitleColor
|
||||
}
|
||||
|
||||
if isEnabled {
|
||||
if let fillColor = buttonModel?.fillColor {
|
||||
backgroundColor = fillColor.uiColor
|
||||
if let fillColor = buttonModel?.enabledColors.fill {
|
||||
backgroundColor = fillColor
|
||||
}
|
||||
if let borderColor = buttonModel?.borderColor {
|
||||
|
||||
if let borderColor = buttonModel?.enabledColors.border {
|
||||
layer.borderWidth = 1
|
||||
layer.borderColor = borderColor.cgColor
|
||||
self.borderColor = borderColor
|
||||
}
|
||||
} else {
|
||||
if let fillColor = buttonModel?.disabledFillColor {
|
||||
backgroundColor = fillColor.uiColor
|
||||
if let fillColor = buttonModel?.disabledColors.fill {
|
||||
backgroundColor = fillColor
|
||||
}
|
||||
if let borderColor = buttonModel?.disabledBorderColor {
|
||||
|
||||
if let borderColor = buttonModel?.disabledColors.border {
|
||||
layer.borderWidth = 1
|
||||
layer.borderColor = borderColor.cgColor
|
||||
self.borderColor = borderColor
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -94,38 +119,53 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
PillButton.getHeight(for: buttonModel?.size, size: size)
|
||||
}
|
||||
|
||||
public static func getHeight(for buttonSize: ButtonSize?, size: CGFloat) -> CGFloat {
|
||||
public static func getHeight(for buttonSize: Styler.Button.Size?, size: CGFloat) -> CGFloat {
|
||||
|
||||
switch buttonSize {
|
||||
case .tiny:
|
||||
return MFSizeObject(standardSize: ButtonHeight.tiny.rawValue, standardiPadPortraitSize: 34, iPadProLandscapeSize: 38)?.getValueBased(onSize: size) ?? ButtonHeight.tiny.rawValue
|
||||
let tinyHeight = Styler.Button.Size.tiny.getHeight()
|
||||
return MFSizeObject(standardSize: tinyHeight,
|
||||
standardiPadPortraitSize: 34,
|
||||
iPadProLandscapeSize: 38)?.getValueBased(onSize: size) ?? tinyHeight
|
||||
|
||||
default:
|
||||
return MFSizeObject(standardSize: ButtonHeight.standard.rawValue, standardiPadPortraitSize: 46, iPadProLandscapeSize: 50)?.getValueBased(onSize: size) ?? ButtonHeight.standard.rawValue
|
||||
let standardHeight = Styler.Button.Size.standard.getHeight()
|
||||
return MFSizeObject(standardSize: standardHeight,
|
||||
standardiPadPortraitSize: 46,
|
||||
iPadProLandscapeSize: 50)?.getValueBased(onSize: size) ?? standardHeight
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private func getMinimumWidth() -> CGFloat {
|
||||
|
||||
switch buttonModel?.size {
|
||||
case .tiny:
|
||||
return MFSizeObject(standardSize: 49.0, standardiPadPortraitSize: 90.0, iPadProLandscapeSize: 135.0)?.getValueBased(onSize: size) ?? 49.0
|
||||
default:
|
||||
return 151.0
|
||||
return MFSizeObject(standardSize: 49,
|
||||
standardiPadPortraitSize: 90,
|
||||
iPadProLandscapeSize: 135)?.getValueBased(onSize: size) ?? 49
|
||||
|
||||
default: return 151
|
||||
}
|
||||
}
|
||||
|
||||
open override var intrinsicContentSize: CGSize {
|
||||
|
||||
let size = super.intrinsicContentSize
|
||||
let width = size.width + (2 * getInnerPadding())
|
||||
return CGSize(width: max(width, getMinimumWidth()), height: getHeight())
|
||||
}
|
||||
|
||||
// MARK: - MoleculeViewProtocol
|
||||
//--------------------------------------------------
|
||||
// MARK: - MVMCoreViewProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
|
||||
// The button will get styled in the enable check in super.
|
||||
super.set(with: model, delegateObject, additionalData)
|
||||
|
||||
|
||||
guard let model = model as? ButtonModel else { return }
|
||||
setTitle(model.title, for: .normal)
|
||||
|
||||
|
||||
model.updateUI = { [weak self] in
|
||||
MVMCoreDispatchUtility.performBlock(onMainThread: {
|
||||
self?.enableField(model.enabled)
|
||||
@ -134,39 +174,46 @@ open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
|
||||
|
||||
FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate)
|
||||
}
|
||||
|
||||
|
||||
open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
PillButton.getHeight(for: (model as? ButtonModel)?.size, size: MVMCoreUIUtility.getWidth())
|
||||
}
|
||||
|
||||
// MARK: - MVMCoreViewProtocol
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
self.size = size
|
||||
|
||||
invalidateIntrinsicContentSize()
|
||||
|
||||
switch buttonModel?.size {
|
||||
case .tiny:
|
||||
titleLabel?.font = MFFonts.mfFont75Bd(11 * (intrinsicContentSize.height / ButtonHeight.tiny.rawValue))
|
||||
titleLabel?.font = MFFonts.mfFont75Bd(11 * (intrinsicContentSize.height / Styler.Button.Size.tiny.getHeight()))
|
||||
|
||||
default:
|
||||
titleLabel?.font = MFFonts.mfFont75Bd(13 * (intrinsicContentSize.height / ButtonHeight.standard.rawValue))
|
||||
titleLabel?.font = MFFonts.mfFont75Bd(13 * (intrinsicContentSize.height / Styler.Button.Size.standard.getHeight()))
|
||||
}
|
||||
|
||||
layer.cornerRadius = getInnerPadding()
|
||||
}
|
||||
|
||||
|
||||
open override func setupView() {
|
||||
super.setupView()
|
||||
|
||||
titleLabel?.numberOfLines = 1
|
||||
titleLabel?.lineBreakMode = .byTruncatingTail
|
||||
titleLabel?.textAlignment = .center
|
||||
contentHorizontalAlignment = .center
|
||||
stylePrimary()
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - MVMCoreUIViewConstrainingProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
open func horizontalAlignment() -> UIStackView.Alignment {
|
||||
return .center
|
||||
}
|
||||
|
||||
|
||||
public func enableField(_ enable: Bool) {
|
||||
isEnabled = enable
|
||||
}
|
||||
|
||||
@ -22,7 +22,7 @@ public class ListRightVariableButtonAllTextAndLinksModel: ListItemModel, Molecul
|
||||
override public func setDefaults() {
|
||||
super.setDefaults()
|
||||
self.button.size = .tiny
|
||||
self.button.style = ButtonStyle.secondary
|
||||
self.button.style = .secondary
|
||||
}
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
|
||||
@ -9,11 +9,24 @@
|
||||
import UIKit
|
||||
|
||||
@objcMembers open class TwoButtonView: View, MVMCoreUIViewConstrainingProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
open var primaryButton: PillButton = PillButton()
|
||||
open var secondaryButton: PillButton = PillButton()
|
||||
private var stack = UIStackView()
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Constraints
|
||||
//--------------------------------------------------
|
||||
|
||||
private var equalWidthConstraint: NSLayoutConstraint?
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
//--------------------------------------------------
|
||||
|
||||
public init() {
|
||||
super.init(frame: .zero)
|
||||
}
|
||||
@ -26,16 +39,21 @@ import UIKit
|
||||
super.init(frame: frame)
|
||||
}
|
||||
|
||||
public func setDefault() {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Lifecycle
|
||||
//--------------------------------------------------
|
||||
|
||||
public func setDefaultAppearance() {
|
||||
|
||||
primaryButton.stylePrimary()
|
||||
secondaryButton.styleSecondary()
|
||||
}
|
||||
|
||||
// MARK: - MVMCoreViewProtocol
|
||||
open override func updateView(_ size: CGFloat) {
|
||||
super.updateView(size)
|
||||
self.primaryButton.updateView(size)
|
||||
self.secondaryButton.updateView(size)
|
||||
|
||||
primaryButton.updateView(size)
|
||||
secondaryButton.updateView(size)
|
||||
}
|
||||
|
||||
open override func setupView() {
|
||||
@ -52,58 +70,70 @@ import UIKit
|
||||
equalWidthConstraint?.isActive = true
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Stack Manipulation
|
||||
//--------------------------------------------------
|
||||
|
||||
public func showPrimaryButton() {
|
||||
|
||||
if !stack.arrangedSubviews.contains(primaryButton) {
|
||||
stack.addArrangedSubview(primaryButton)
|
||||
primaryButton.isHidden = false
|
||||
}
|
||||
|
||||
if secondaryButton.superview != nil {
|
||||
equalWidthConstraint?.isActive = true
|
||||
}
|
||||
}
|
||||
|
||||
public func showSecondaryButton() {
|
||||
|
||||
if !stack.arrangedSubviews.contains(secondaryButton) {
|
||||
stack.insertArrangedSubview(secondaryButton, at: 0)
|
||||
secondaryButton.isHidden = false
|
||||
}
|
||||
|
||||
if primaryButton.superview != nil {
|
||||
equalWidthConstraint?.isActive = true
|
||||
}
|
||||
}
|
||||
|
||||
public func hidePrimaryButton() {
|
||||
|
||||
if primaryButton.superview != nil {
|
||||
stack.removeArrangedSubview(primaryButton)
|
||||
primaryButton.isHidden = true
|
||||
}
|
||||
|
||||
equalWidthConstraint?.isActive = false
|
||||
}
|
||||
|
||||
public func hideSecondaryButton() {
|
||||
|
||||
if secondaryButton.superview != nil {
|
||||
stack.removeArrangedSubview(secondaryButton)
|
||||
secondaryButton.isHidden = true
|
||||
}
|
||||
|
||||
equalWidthConstraint?.isActive = false
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - MoleculeViewProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
open override func reset() {
|
||||
super.reset()
|
||||
setDefault()
|
||||
}
|
||||
|
||||
// MARK: - MVMCoreUIViewConstrainingProtocol
|
||||
open func horizontalAlignment() -> UIStackView.Alignment {
|
||||
return .center
|
||||
|
||||
setDefaultAppearance()
|
||||
}
|
||||
|
||||
// MARK: - MoleculeViewProtocol
|
||||
public override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
|
||||
|
||||
guard let model = model as? TwoButtonViewModel,
|
||||
let buttonModel = model.primaryButton ?? model.secondaryButton else { return 0 }
|
||||
let buttonModel = model.primaryButton ?? model.secondaryButton
|
||||
else { return 0 }
|
||||
|
||||
return PillButton.estimatedHeight(with: buttonModel, delegateObject)
|
||||
}
|
||||
|
||||
@ -118,6 +148,7 @@ import UIKit
|
||||
} else {
|
||||
hideSecondaryButton()
|
||||
}
|
||||
|
||||
if let primaryModel = model.primaryButton {
|
||||
showPrimaryButton()
|
||||
primaryButton.set(with: primaryModel, delegateObject, additionalData)
|
||||
@ -125,4 +156,11 @@ import UIKit
|
||||
hidePrimaryButton()
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------
|
||||
// MARK: - MVMCoreUIViewConstrainingProtocol
|
||||
//--------------------------------------------------
|
||||
|
||||
open func horizontalAlignment() -> UIStackView.Alignment {
|
||||
return .center
|
||||
}
|
||||
}
|
||||
|
||||
@ -8,35 +8,54 @@
|
||||
|
||||
import UIKit
|
||||
|
||||
|
||||
public class TwoButtonViewModel: MoleculeModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public static var identifier: String = "twoButtonView"
|
||||
public var backgroundColor: Color?
|
||||
public var primaryButton: ButtonModel?
|
||||
public var secondaryButton: ButtonModel?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case moleculeName
|
||||
case backgroundColor
|
||||
case primaryButton
|
||||
case secondaryButton
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initialzer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(_ primaryButton: ButtonModel?, _ secondaryButton: ButtonModel?) {
|
||||
self.primaryButton = primaryButton
|
||||
self.secondaryButton = secondaryButton
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
|
||||
primaryButton = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .primaryButton)
|
||||
if primaryButton?.style == nil {
|
||||
primaryButton?.style = .primary
|
||||
}
|
||||
secondaryButton = try typeContainer.decodeIfPresent(ButtonModel.self, forKey: .secondaryButton)
|
||||
// Default value
|
||||
if secondaryButton?.style == nil {
|
||||
secondaryButton?.style = .secondary
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public func encode(to encoder: Encoder) throws {
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encode(moleculeName, forKey: .moleculeName)
|
||||
|
||||
@ -8,24 +8,39 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
|
||||
@objcMembers public class TemplateModel: MVMControllerModelProtocol {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
public class var identifier: String {
|
||||
return ""
|
||||
}
|
||||
|
||||
public var pageType: String
|
||||
public var template: String {
|
||||
// Although this is done in the extension, it is needed for the encoding.
|
||||
return Self.identifier
|
||||
}
|
||||
|
||||
public var backgroundColor: Color?
|
||||
public var screenHeading: String?
|
||||
public var navigationItem: (NavigationItemModelProtocol & MoleculeModelProtocol)?
|
||||
public var formRules: [FormGroupRule]?
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializer
|
||||
//--------------------------------------------------
|
||||
|
||||
public init(pageType: String) {
|
||||
self.pageType = pageType
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Keys
|
||||
//--------------------------------------------------
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case pageType
|
||||
case template
|
||||
@ -34,6 +49,10 @@ import Foundation
|
||||
case formRules
|
||||
case navigationItem
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Codec
|
||||
//--------------------------------------------------
|
||||
|
||||
required public init(from decoder: Decoder) throws {
|
||||
let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
|
||||
|
||||
@ -24,25 +24,25 @@ import UIKit
|
||||
|
||||
open override func viewForTop() -> UIView? {
|
||||
guard let headerModel = templateModel?.header,
|
||||
let molecule = MoleculeObjectMapping.shared()?.createMolecule(headerModel, delegateObject: delegateObjectIVar) else {
|
||||
return nil
|
||||
}
|
||||
let molecule = MoleculeObjectMapping.shared()?.createMolecule(headerModel, delegateObject: delegateObjectIVar)
|
||||
else { return nil }
|
||||
|
||||
return molecule
|
||||
}
|
||||
|
||||
open override func viewForMiddle() -> UIView? {
|
||||
guard let middleModel = templateModel?.middle,
|
||||
let molecule = MoleculeObjectMapping.shared()?.createMolecule(middleModel, delegateObject: delegateObjectIVar) else {
|
||||
return nil
|
||||
}
|
||||
let molecule = MoleculeObjectMapping.shared()?.createMolecule(middleModel, delegateObject: delegateObjectIVar)
|
||||
else { return nil }
|
||||
|
||||
return molecule
|
||||
}
|
||||
|
||||
override open func viewForBottom() -> UIView? {
|
||||
guard let footerModel = templateModel?.footer,
|
||||
let molecule = MoleculeObjectMapping.shared()?.createMolecule(footerModel, delegateObject: delegateObjectIVar) else {
|
||||
return nil
|
||||
}
|
||||
let molecule = MoleculeObjectMapping.shared()?.createMolecule(footerModel, delegateObject: delegateObjectIVar)
|
||||
else { return nil }
|
||||
|
||||
return molecule
|
||||
}
|
||||
|
||||
|
||||
@ -81,6 +81,7 @@ open class TextViewModel: TextEntryFieldModel {
|
||||
}
|
||||
|
||||
public override func encode(to encoder: Encoder) throws {
|
||||
try super.encode(to: encoder)
|
||||
var container = encoder.container(keyedBy: CodingKeys.self)
|
||||
try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
|
||||
try container.encodeIfPresent(height, forKey: .height)
|
||||
|
||||
@ -258,7 +258,7 @@ import UIKit
|
||||
viewRespectsSystemMinimumLayoutMargins = false
|
||||
|
||||
// Presents from the bottom.
|
||||
modalPresentationStyle = MVMCoreGetterUtility.isOnIPad() ? UIModalPresentationStyle.formSheet : UIModalPresentationStyle.overCurrentContext
|
||||
modalPresentationStyle = MVMCoreGetterUtility.isOnIPad() ? .formSheet : .overCurrentContext
|
||||
|
||||
// Create the default delegate object.
|
||||
delegateObjectIVar = MVMCoreUIDelegateObject.create(withDelegateForAll: self)
|
||||
@ -339,18 +339,18 @@ import UIKit
|
||||
}
|
||||
|
||||
// MARK: - MVMCoreActionDelegateProtocol
|
||||
open func handleOpenPage(for requestParameters: MVMCoreRequestParameters, actionInformation: [AnyHashable : Any]?, additionalData: [AnyHashable : Any]?) {
|
||||
open func handleOpenPage(for requestParameters: MVMCoreRequestParameters, actionInformation: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) {
|
||||
formValidator?.addFormParams(requestParameters: requestParameters)
|
||||
requestParameters.parentPageType = loadObject?.pageJSON?.optionalStringForKey("parentPageType")
|
||||
MVMCoreActionHandler.defaultHandleOpenPage(for: requestParameters, additionalData: additionalData, delegateObject: delegateObject())
|
||||
}
|
||||
|
||||
open func logAction(withActionInformation actionInformation: [AnyHashable : Any]?, additionalData: [AnyHashable : Any]?) {
|
||||
open func logAction(withActionInformation actionInformation: [AnyHashable: Any]?, additionalData: [AnyHashable: Any]?) {
|
||||
MVMCoreUILoggingHandler.shared()?.defaultLogAction(forController: self, actionInformation: actionInformation, additionalData: additionalData)
|
||||
}
|
||||
|
||||
// MARK: - MoleculeDelegateProtocol
|
||||
open func getModuleWithName(_ name: String?) -> [AnyHashable : Any]? {
|
||||
open func getModuleWithName(_ name: String?) -> [AnyHashable: Any]? {
|
||||
guard let name = name else { return nil }
|
||||
return loadObject?.modulesJSON?.optionalDictionaryForKey(name)
|
||||
}
|
||||
@ -391,7 +391,7 @@ import UIKit
|
||||
view.accessibilityElements = [pickerView, toolBar]
|
||||
}
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
|
||||
UIAccessibility.post(notification: UIAccessibility.Notification.layoutChanged, argument: textField.inputView)
|
||||
UIAccessibility.post(notification: .layoutChanged, argument: textField.inputView)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -400,7 +400,7 @@ import UIKit
|
||||
if textField === selectedField {
|
||||
if UIAccessibility.isVoiceOverRunning {
|
||||
view.accessibilityElements = nil
|
||||
UIAccessibility.post(notification: UIAccessibility.Notification.layoutChanged, argument: textField)
|
||||
UIAccessibility.post(notification: .layoutChanged, argument: textField)
|
||||
}
|
||||
selectedField = nil
|
||||
}
|
||||
|
||||
@ -9,8 +9,10 @@
|
||||
import UIKit
|
||||
|
||||
open class Container: View, ContainerProtocol {
|
||||
|
||||
public var view: UIView?
|
||||
let containerHelper = ContainerHelper()
|
||||
|
||||
var containerModel: ContainerModelProtocol? {
|
||||
get { return model as? ContainerModelProtocol }
|
||||
}
|
||||
|
||||
@ -55,6 +55,13 @@ public final class Color: Codable {
|
||||
determineRGBA()
|
||||
}
|
||||
|
||||
public init?(uiColor: UIColor?) {
|
||||
guard let uiColor = uiColor else { return nil }
|
||||
self.uiColor = uiColor
|
||||
hex = UIColor.hexString(for: uiColor) ?? ""
|
||||
determineRGBA()
|
||||
}
|
||||
|
||||
init?(name: String) {
|
||||
guard let colorTuple = UIColor.names[name] else { return nil }
|
||||
self.uiColor = colorTuple.uiColor
|
||||
|
||||
@ -172,6 +172,29 @@ open class Styler {
|
||||
}
|
||||
}
|
||||
|
||||
public enum Button {
|
||||
|
||||
public enum Style: String, Codable {
|
||||
case primary
|
||||
case secondary
|
||||
}
|
||||
|
||||
public enum Size: String, Codable {
|
||||
case standard
|
||||
case tiny
|
||||
|
||||
func getHeight() -> CGFloat {
|
||||
switch self {
|
||||
case .standard:
|
||||
return 42
|
||||
|
||||
case .tiny:
|
||||
return 20
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Functions
|
||||
//--------------------------------------------------
|
||||
|
||||
Loading…
Reference in New Issue
Block a user