Merge branch 'feature/Notification' into 'develop'
Adding Notification component See merge request BPHV_MIPS/vds_ios!53
This commit is contained in:
commit
2902a85c0c
@ -8,8 +8,6 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
445BA07829C07B3D0036A7C5 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = 445BA07729C07B3D0036A7C5 /* Notification.swift */; };
|
||||
44604AD029CE17EC00E62B51 /* NotificationTitleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604ACF29CE17EC00E62B51 /* NotificationTitleModel.swift */; };
|
||||
44604AD229CE180F00E62B51 /* NotificationSubTitleModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD129CE180F00E62B51 /* NotificationSubTitleModel.swift */; };
|
||||
44604AD429CE186A00E62B51 /* NotificationButtonModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */; };
|
||||
44604AD729CE196600E62B51 /* Line.swift in Sources */ = {isa = PBXBuildFile; fileRef = 44604AD629CE196600E62B51 /* Line.swift */; };
|
||||
5F21D7BF28DCEB3D003E7CD6 /* Useable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */; };
|
||||
@ -94,6 +92,7 @@
|
||||
EAC9258F2911C9DE00091998 /* EntryField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC9258B2911C9DE00091998 /* EntryField.swift */; };
|
||||
EAD8D2C128BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */; };
|
||||
EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9829D4850E00101452 /* Clickable.swift */; };
|
||||
EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF1FE9A29DB1A6000101452 /* Changeable.swift */; };
|
||||
EAF7F0952899861000B287F5 /* Checkbox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0932899861000B287F5 /* Checkbox.swift */; };
|
||||
EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F0992899B17200B287F5 /* CATransaction.swift */; };
|
||||
EAF7F09E289AAEC000B287F5 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAF7F09D289AAEC000B287F5 /* Constants.swift */; };
|
||||
@ -125,8 +124,6 @@
|
||||
|
||||
/* Begin PBXFileReference section */
|
||||
445BA07729C07B3D0036A7C5 /* Notification.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = "<group>"; };
|
||||
44604ACF29CE17EC00E62B51 /* NotificationTitleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationTitleModel.swift; sourceTree = "<group>"; };
|
||||
44604AD129CE180F00E62B51 /* NotificationSubTitleModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSubTitleModel.swift; sourceTree = "<group>"; };
|
||||
44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationButtonModel.swift; sourceTree = "<group>"; };
|
||||
44604AD629CE196600E62B51 /* Line.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Line.swift; sourceTree = "<group>"; };
|
||||
5F21D7BE28DCEB3D003E7CD6 /* Useable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Useable.swift; sourceTree = "<group>"; };
|
||||
@ -212,6 +209,7 @@
|
||||
EAC9258B2911C9DE00091998 /* EntryField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EntryField.swift; sourceTree = "<group>"; };
|
||||
EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIGestureRecognizer+Publisher.swift"; sourceTree = "<group>"; };
|
||||
EAF1FE9829D4850E00101452 /* Clickable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Clickable.swift; sourceTree = "<group>"; };
|
||||
EAF1FE9A29DB1A6000101452 /* Changeable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Changeable.swift; sourceTree = "<group>"; };
|
||||
EAF7F0932899861000B287F5 /* Checkbox.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Checkbox.swift; sourceTree = "<group>"; };
|
||||
EAF7F0992899B17200B287F5 /* CATransaction.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CATransaction.swift; sourceTree = "<group>"; };
|
||||
EAF7F09D289AAEC000B287F5 /* Constants.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
|
||||
@ -257,8 +255,6 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
445BA07729C07B3D0036A7C5 /* Notification.swift */,
|
||||
44604ACF29CE17EC00E62B51 /* NotificationTitleModel.swift */,
|
||||
44604AD129CE180F00E62B51 /* NotificationSubTitleModel.swift */,
|
||||
44604AD329CE186A00E62B51 /* NotificationButtonModel.swift */,
|
||||
);
|
||||
path = Notification;
|
||||
@ -418,6 +414,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
EA4DB2FC28D3D0CA00103EE3 /* AnyEquatable.swift */,
|
||||
EAF1FE9A29DB1A6000101452 /* Changeable.swift */,
|
||||
EAF1FE9829D4850E00101452 /* Clickable.swift */,
|
||||
EAA5EEDF28F49DB3003B3210 /* Colorable.swift */,
|
||||
EA3361A9288B25E40071C351 /* Disabling.swift */,
|
||||
@ -792,7 +789,6 @@
|
||||
EA33622E2891EA3C0071C351 /* DispatchQueue+Once.swift in Sources */,
|
||||
EA4DB2FD28D3D0CA00103EE3 /* AnyEquatable.swift in Sources */,
|
||||
EAA5EEB728ECC03A003B3210 /* ToolTipLabelAttribute.swift in Sources */,
|
||||
44604AD029CE17EC00E62B51 /* NotificationTitleModel.swift in Sources */,
|
||||
EA5E305A29510F8B0082B959 /* EnumSubset.swift in Sources */,
|
||||
EA985BF7296C665E00F2FF2E /* IconName.swift in Sources */,
|
||||
EAF7F0AF289B144C00B287F5 /* UnderlineLabelAttribute.swift in Sources */,
|
||||
@ -825,10 +821,10 @@
|
||||
EA3361BD288B2C760071C351 /* TypeAlias.swift in Sources */,
|
||||
EAB1D2CF28ABEF2B00DAE764 /* Typography.swift in Sources */,
|
||||
EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */,
|
||||
EAF1FE9B29DB1A6000101452 /* Changeable.swift in Sources */,
|
||||
EAF7F0A2289AFB3900B287F5 /* Errorable.swift in Sources */,
|
||||
EA985C7D297DAED300F2FF2E /* Primitive.swift in Sources */,
|
||||
EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */,
|
||||
44604AD229CE180F00E62B51 /* NotificationSubTitleModel.swift in Sources */,
|
||||
EAB5FEF829393A7200998C17 /* ButtonGroupConstants.swift in Sources */,
|
||||
EA3361AF288B26310071C351 /* FormFieldable.swift in Sources */,
|
||||
44604AD729CE196600E62B51 /* Line.swift in Sources */,
|
||||
|
||||
@ -7,14 +7,23 @@
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Combine
|
||||
|
||||
public class SelectorGroupHandlerBase<HandlerType: Control>: Control {
|
||||
public class SelectorGroupHandlerBase<HandlerType: Control>: Control, Changeable {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
public var selectorViews: [HandlerType] = []
|
||||
|
||||
public var onChangeSubscriber: AnyCancellable? {
|
||||
willSet {
|
||||
if let onChangeSubscriber {
|
||||
onChangeSubscriber.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Overrides
|
||||
//--------------------------------------------------
|
||||
|
||||
@ -121,7 +121,7 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab
|
||||
translatesAutoresizingMaskIntoConstraints = false
|
||||
accessibilityCustomActions = []
|
||||
setup()
|
||||
setupDidChangeEvent()
|
||||
setupDidChangeEvent(true)
|
||||
updateView()
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,13 +7,13 @@
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Combine
|
||||
import VDSColorTokens
|
||||
import VDSFormControlsTokens
|
||||
import Combine
|
||||
|
||||
/// Checkboxes are a multi-select component through which a customer indicates a choice. If a binary choice, the component is a checkbox. If the choice has multiple options, the component is a ``CheckboxGroup``.
|
||||
@objc(VDSCheckboxBase)
|
||||
open class Checkbox: Control, Errorable {
|
||||
open class Checkbox: Control, Errorable, Changeable {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
@ -63,6 +63,14 @@ open class Checkbox: Control, Errorable {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
public var onChangeSubscriber: AnyCancellable? {
|
||||
willSet {
|
||||
if let onChangeSubscriber {
|
||||
onChangeSubscriber.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open var label = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textPosition = .left
|
||||
|
||||
@ -94,7 +94,7 @@ public class Label: UILabel, Handlerable, ViewProtocol, Resettable, UserInfoable
|
||||
accessibilityCustomActions = []
|
||||
accessibilityTraits = .staticText
|
||||
setup()
|
||||
setupDidChangeEvent()
|
||||
setupDidChangeEvent(true)
|
||||
updateView()
|
||||
}
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ public class Notification: View {
|
||||
// MARK: - Enums
|
||||
//--------------------------------------------------
|
||||
|
||||
public enum NotificationStyle: String, CaseIterable {
|
||||
public enum Style: String, CaseIterable {
|
||||
case info, success, warning, error
|
||||
|
||||
func styleIconName() -> Icon.Name {
|
||||
@ -35,6 +35,10 @@ public class Notification: View {
|
||||
}
|
||||
}
|
||||
|
||||
public enum Layout: String, CaseIterable {
|
||||
case vertical, horizontal
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Private Properties
|
||||
//--------------------------------------------------
|
||||
@ -52,6 +56,14 @@ public class Notification: View {
|
||||
$0.axis = .vertical
|
||||
}
|
||||
|
||||
private var labelButtonView = UIStackView().with {
|
||||
$0.translatesAutoresizingMaskIntoConstraints = false
|
||||
$0.alignment = .top
|
||||
$0.distribution = .fillEqually
|
||||
$0.axis = .vertical
|
||||
$0.spacing = VDSLayout.Spacing.space2X.value
|
||||
}
|
||||
|
||||
private var edgeSpacing: CGFloat {
|
||||
return UIDevice.isIPad ? VDSLayout.Spacing.space5X.value : VDSLayout.Spacing.space4X.value
|
||||
}
|
||||
@ -64,24 +76,40 @@ public class Notification: View {
|
||||
return UIDevice.isIPad ? VDSLayout.Spacing.space5X.value : VDSLayout.Spacing.space4X.value
|
||||
}
|
||||
|
||||
private var minViewWidth: CGFloat {
|
||||
return fullBleed ? 320 : 288
|
||||
}
|
||||
|
||||
///Max view width is for Tablet
|
||||
private var maxViewWidth: CGFloat {
|
||||
return fullBleed ? 1272 : 1232
|
||||
}
|
||||
|
||||
private var maxWidthConstraint: NSLayoutConstraint?
|
||||
|
||||
open var leadingConstraint: NSLayoutConstraint?
|
||||
|
||||
open var trailingConstraint: NSLayoutConstraint?
|
||||
//--------------------------------------------------
|
||||
// MARK: - View Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
open var typeIcon = Icon().with {
|
||||
$0.name = .infoBold
|
||||
$0.size = UIDevice.isIPad ? .medium : .small
|
||||
}
|
||||
|
||||
open var closeButton = Icon().with {
|
||||
$0.name = .close
|
||||
$0.size = UIDevice.isIPad ? .medium : .small
|
||||
}
|
||||
|
||||
open var titleLabel = Label().with {
|
||||
$0.textStyle = .boldBodyLarge
|
||||
$0.textStyle = UIDevice.isIPad ? .boldBodyLarge : .boldBodySmall
|
||||
}
|
||||
|
||||
open var subTitleLabel = Label().with {
|
||||
$0.textStyle = .bodyLarge
|
||||
$0.textStyle = UIDevice.isIPad ? .bodyLarge : .bodySmall
|
||||
}
|
||||
|
||||
open var buttonsView = ButtonGroup().with {
|
||||
@ -89,11 +117,10 @@ public class Notification: View {
|
||||
}
|
||||
|
||||
//Text
|
||||
open var titleText: String = "" { didSet{didChange()}}
|
||||
open var title: String = "" { didSet{didChange()}}
|
||||
|
||||
open var subTitleText: String? { didSet{didChange()}}
|
||||
open var subTitle: String? { didSet{didChange()}}
|
||||
|
||||
#warning("will need to think about this one, probably create a model that has 2 props - text, onClick = (Button) -> () so we are not accessing the button directly. The only reason why I leave it open is for things like accessibility, but not for setting properties outside of this class. More or less follow how Tilelet is working, look at that, below is a temp fix until we can discuss with the guys")
|
||||
//Buttons
|
||||
open var primaryButtonModel: ButtonModel? { didSet{didChange()}}
|
||||
open var primaryButton = Button().with {
|
||||
@ -122,16 +149,31 @@ public class Notification: View {
|
||||
}
|
||||
internal var onCloseSubscriber: AnyCancellable?
|
||||
//--------------------------------------------------
|
||||
// MARK: - Modal Properties
|
||||
// MARK: - Properties
|
||||
//--------------------------------------------------
|
||||
|
||||
open var type: NotificationStyle = .info { didSet{didChange()}}
|
||||
open var hideCloseButton: Bool = false { didSet{didChange()}}
|
||||
|
||||
open var type: Style = .info { didSet{didChange()}}
|
||||
|
||||
open var fullBleed: Bool = false { didSet {didChange()}}
|
||||
|
||||
var _layout: Layout = .vertical
|
||||
open var layout: Layout {
|
||||
set {
|
||||
if !UIDevice.isIPad, newValue == .horizontal { return }
|
||||
_layout = newValue
|
||||
buttonsView.buttonPosition = _layout == .horizontal ? .center : .left
|
||||
didChange()
|
||||
}
|
||||
get { _layout }
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Configuration
|
||||
//--------------------------------------------------
|
||||
private var backgroundColorConfiguration: AnyColorable = {
|
||||
let config = KeyedColorConfiguration<Notification, NotificationStyle>(keyPath: \.type)
|
||||
let config = KeyedColorConfiguration<Notification, Style>(keyPath: \.type)
|
||||
config.setSurfaceColors(VDSColor.feedbackInformationBackgroundOnlight, VDSColor.feedbackInformationBackgroundOndark, forKey: .info)
|
||||
config.setSurfaceColors(VDSColor.feedbackWarningBackgroundOnlight, VDSColor.feedbackWarningBackgroundOndark, forKey: .warning)
|
||||
config.setSurfaceColors(VDSColor.feedbackSuccessBackgroundOnlight, VDSColor.feedbackSuccessBackgroundOndark, forKey: .success)
|
||||
@ -170,11 +212,15 @@ public class Notification: View {
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
heightAnchor.constraint(greaterThanOrEqualToConstant: minViewHeight),
|
||||
mainStackView.heightAnchor.constraint(greaterThanOrEqualToConstant: minContentHeight)
|
||||
mainStackView.heightAnchor.constraint(greaterThanOrEqualToConstant: minContentHeight),
|
||||
widthAnchor.constraint(greaterThanOrEqualToConstant: minViewWidth)
|
||||
])
|
||||
maxWidthConstraint = widthAnchor.constraint(lessThanOrEqualToConstant: maxViewWidth)
|
||||
|
||||
labelButtonView.addArrangedSubview(labelsView)
|
||||
|
||||
mainStackView.addArrangedSubview(typeIcon)
|
||||
mainStackView.addArrangedSubview(labelsView)
|
||||
mainStackView.addArrangedSubview(labelButtonView)
|
||||
mainStackView.addArrangedSubview(closeButton)
|
||||
|
||||
//labels
|
||||
@ -186,14 +232,29 @@ public class Notification: View {
|
||||
super.reset()
|
||||
|
||||
titleLabel.reset()
|
||||
titleLabel.text = ""
|
||||
titleLabel.textStyle = UIDevice.isIPad ? .boldBodyLarge : .boldBodySmall
|
||||
|
||||
subTitleLabel.reset()
|
||||
subTitleLabel.textStyle = UIDevice.isIPad ? .bodyLarge : .bodySmall
|
||||
|
||||
buttonsView.reset()
|
||||
primaryButton.reset()
|
||||
secondaryButton.reset()
|
||||
buttonsView.buttonPosition = .left
|
||||
|
||||
primaryButtonModel = nil
|
||||
secondaryButtonModel = nil
|
||||
|
||||
type = .info
|
||||
typeIcon.size = UIDevice.isIPad ? .medium : .small
|
||||
typeIcon.name = .infoBold
|
||||
|
||||
onCloseClick = nil
|
||||
closeButton.size = UIDevice.isIPad ? .medium : .small
|
||||
closeButton.name = .close
|
||||
|
||||
layout = .vertical
|
||||
hideCloseButton = false
|
||||
fullBleed = false
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
@ -204,6 +265,7 @@ public class Notification: View {
|
||||
updateIcons()
|
||||
updateLabels()
|
||||
updateButtons()
|
||||
setConstraints()
|
||||
}
|
||||
|
||||
private func updateIcons() {
|
||||
@ -211,21 +273,22 @@ public class Notification: View {
|
||||
typeIcon.name = type.styleIconName()
|
||||
typeIcon.color = iconColor
|
||||
closeButton.color = iconColor
|
||||
closeButton.isHidden = hideCloseButton
|
||||
}
|
||||
|
||||
private func updateLabels() {
|
||||
titleLabel.surface = surface
|
||||
subTitleLabel.surface = surface
|
||||
|
||||
if !titleText.isEmpty {
|
||||
titleLabel.text = titleText
|
||||
if !title.isEmpty {
|
||||
titleLabel.text = title
|
||||
labelsView.addArrangedSubview(titleLabel)
|
||||
} else {
|
||||
titleLabel.removeFromSuperview()
|
||||
}
|
||||
|
||||
if let subTitleText {
|
||||
subTitleLabel.text = subTitleText
|
||||
if let subTitle {
|
||||
subTitleLabel.text = subTitle
|
||||
labelsView.addArrangedSubview(subTitleLabel)
|
||||
} else {
|
||||
subTitleLabel.removeFromSuperview()
|
||||
@ -254,14 +317,32 @@ public class Notification: View {
|
||||
buttonsView.removeFromSuperview()
|
||||
} else {
|
||||
labelsView.setCustomSpacing(VDSLayout.Spacing.space3X.value, after: subTitleLabel)
|
||||
///This below doesn't work
|
||||
|
||||
buttonsView.buttons = buttons
|
||||
labelsView.addArrangedSubview(buttonsView)
|
||||
labelButtonView.axis = layout == .vertical ? .vertical : .horizontal
|
||||
labelButtonView.addArrangedSubview(buttonsView)
|
||||
|
||||
buttonsView
|
||||
.pinLeading()
|
||||
.pinTrailing()
|
||||
}
|
||||
}
|
||||
|
||||
private func setConstraints() {
|
||||
|
||||
maxWidthConstraint?.constant = maxViewWidth
|
||||
maxWidthConstraint?.isActive = UIDevice.isIPad
|
||||
|
||||
if leadingConstraint == nil, let superview {
|
||||
leadingConstraint = NSLayoutConstraint(item: self, attribute: .leading, relatedBy: .equal, toItem: superview, attribute: .leading, multiplier: 1, constant: 0)
|
||||
}
|
||||
|
||||
if trailingConstraint == nil, let superview {
|
||||
trailingConstraint = NSLayoutConstraint(item: superview, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1, constant: 0)
|
||||
}
|
||||
|
||||
leadingConstraint?.isActive = fullBleed
|
||||
trailingConstraint?.isActive = fullBleed
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -1,26 +0,0 @@
|
||||
//
|
||||
// NotificationSubTitleModel.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Nadigadda, Sumanth on 24/03/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Notification {
|
||||
public struct SubTitleModel {
|
||||
public var text: String
|
||||
public var textAttributes: [any LabelAttributeModel]?
|
||||
public var textStyle: TextStyle = .bodySmall
|
||||
public var numberOfLines: Int
|
||||
|
||||
public init(text: String,
|
||||
textColor: Use = .primary,
|
||||
textAttributes: [any LabelAttributeModel]? = nil,
|
||||
numberOfLines: Int = 0) {
|
||||
self.text = text
|
||||
self.textAttributes = textAttributes
|
||||
self.numberOfLines = numberOfLines
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,25 +0,0 @@
|
||||
//
|
||||
// NotificationTitleModel.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Nadigadda, Sumanth on 24/03/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
extension Notification {
|
||||
public struct TitleModel {
|
||||
public var text: String
|
||||
public var textAttributes: [any LabelAttributeModel]?
|
||||
public var textStyle: TextStyle = .boldBodySmall
|
||||
public var numberOfLines: Int
|
||||
|
||||
public init(text: String,
|
||||
textAttributes: [any LabelAttributeModel]? = nil,
|
||||
numberOfLines: Int = 0) {
|
||||
self.text = text
|
||||
self.textAttributes = textAttributes
|
||||
self.numberOfLines = numberOfLines
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -7,12 +7,12 @@
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Combine
|
||||
import VDSColorTokens
|
||||
import VDSFormControlsTokens
|
||||
import Combine
|
||||
|
||||
@objc(VDSRadioBox)
|
||||
open class RadioBox: Control {
|
||||
open class RadioBox: Control, Changeable {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
@ -56,6 +56,14 @@ open class RadioBox: Control {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
public var onChangeSubscriber: AnyCancellable? {
|
||||
willSet {
|
||||
if let onChangeSubscriber {
|
||||
onChangeSubscriber.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open var textLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textPosition = .left
|
||||
|
||||
@ -7,11 +7,12 @@
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Combine
|
||||
import VDSColorTokens
|
||||
import VDSFormControlsTokens
|
||||
|
||||
@objc(VDSRadioButton)
|
||||
open class RadioButton: Control, Errorable {
|
||||
open class RadioButton: Control, Errorable, Changeable {
|
||||
|
||||
//--------------------------------------------------
|
||||
// MARK: - Initializers
|
||||
@ -61,6 +62,14 @@ open class RadioButton: Control, Errorable {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
public var onChangeSubscriber: AnyCancellable? {
|
||||
willSet {
|
||||
if let onChangeSubscriber {
|
||||
onChangeSubscriber.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open var label = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.textPosition = .left
|
||||
|
||||
@ -12,7 +12,7 @@ import VDSFormControlsTokens
|
||||
import Combine
|
||||
|
||||
@objc(VDSEntryField)
|
||||
open class EntryField: Control {
|
||||
open class EntryField: Control, Changeable {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Enums
|
||||
//--------------------------------------------------
|
||||
@ -98,6 +98,14 @@ open class EntryField: Control {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
public var onChangeSubscriber: AnyCancellable? {
|
||||
willSet {
|
||||
if let onChangeSubscriber {
|
||||
onChangeSubscriber.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open var titleLabel = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
$0.attributes = []
|
||||
|
||||
@ -18,7 +18,7 @@ import Combine
|
||||
Knob: The circular indicator that slides on the container.
|
||||
*/
|
||||
@objc(VDSToggle)
|
||||
open class Toggle: Control {
|
||||
open class Toggle: Control, Changeable {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Enums
|
||||
//--------------------------------------------------
|
||||
@ -107,6 +107,14 @@ open class Toggle: Control {
|
||||
//--------------------------------------------------
|
||||
// MARK: - Public Properties
|
||||
//--------------------------------------------------
|
||||
public var onChangeSubscriber: AnyCancellable? {
|
||||
willSet {
|
||||
if let onChangeSubscriber {
|
||||
onChangeSubscriber.cancel()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open var label = Label().with {
|
||||
$0.setContentCompressionResistancePriority(.required, for: .vertical)
|
||||
}
|
||||
|
||||
31
VDS/Protocols/Changeable.swift
Normal file
31
VDS/Protocols/Changeable.swift
Normal file
@ -0,0 +1,31 @@
|
||||
//
|
||||
// Changeable.swift
|
||||
// VDS
|
||||
//
|
||||
// Created by Matt Bruce on 4/3/23.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import Combine
|
||||
|
||||
public protocol Changeable: Handlerable where Self: UIControl {
|
||||
var onChangeSubscriber: AnyCancellable? { get set }
|
||||
}
|
||||
|
||||
extension Changeable {
|
||||
public var onChange: ((Self) -> ())? {
|
||||
get { return nil }
|
||||
set {
|
||||
if let newValue {
|
||||
onChangeSubscriber = publisher(for: .valueChanged)
|
||||
.sink { c in
|
||||
newValue(c)
|
||||
}
|
||||
} else {
|
||||
onChangeSubscriber?.cancel()
|
||||
onChangeSubscriber = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -15,13 +15,6 @@ public protocol Clickable: Handlerable where Self: UIControl {
|
||||
}
|
||||
|
||||
extension Clickable {
|
||||
public func addEvent(event: UIControl.Event, block: @escaping (Self)->()) {
|
||||
publisher(for: event)
|
||||
.sink(receiveValue: { c in
|
||||
block(c)
|
||||
}).store(in: &subscribers)
|
||||
}
|
||||
|
||||
public var onClick: ((Self) -> ())? {
|
||||
get { return nil }
|
||||
set {
|
||||
|
||||
@ -17,15 +17,22 @@ public protocol Handlerable: AnyObject, Initable, Disabling, Surfaceable {
|
||||
|
||||
extension Handlerable {
|
||||
|
||||
public func setupDidChangeEvent() {
|
||||
handlerPublisher().sink { [weak self] _ in
|
||||
self?.updateView()
|
||||
public func setupDidChangeEvent(_ debounce: Bool = false) {
|
||||
handlerPublisher(debounce)
|
||||
.sink { [weak self] _ in
|
||||
self?.updateView()
|
||||
}.store(in: &subscribers)
|
||||
}
|
||||
|
||||
public func handlerPublisher() -> AnyPublisher<Void, Never> {
|
||||
subject
|
||||
.eraseToAnyPublisher()
|
||||
public func handlerPublisher(_ debounce: Bool = false) -> AnyPublisher<Void, Never> {
|
||||
if debounce {
|
||||
return subject
|
||||
.debounce(for: .seconds(Constants.StateDebounce), scheduler: RunLoop.main)
|
||||
.eraseToAnyPublisher()
|
||||
} else {
|
||||
return subject
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,3 +41,12 @@ extension Handlerable where Self: UIView {
|
||||
subject.send()
|
||||
}
|
||||
}
|
||||
|
||||
extension Handlerable where Self: UIControl {
|
||||
public func addEvent(event: UIControl.Event, block: @escaping (Self)->()) {
|
||||
publisher(for: event)
|
||||
.sink(receiveValue: { c in
|
||||
block(c)
|
||||
}).store(in: &subscribers)
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user