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

# Conflicts:
#	VDS.xcodeproj/project.pbxproj
#	VDS/Components/Notification/Notification.swift

Signed-off-by: Matt Bruce <matt.bruce@verizon.com>
This commit is contained in:
Matt Bruce 2023-03-30 10:21:03 -05:00
commit 60dd7a103e
19 changed files with 192 additions and 277 deletions

View File

@ -46,7 +46,6 @@
EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E30522950DDA60082B959 /* TitleLockup.swift */; };
EA5E3058295105A40082B959 /* Tilelet.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E3057295105A40082B959 /* Tilelet.swift */; };
EA5E305A29510F8B0082B959 /* EnumSubset.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA5E305929510F8B0082B959 /* EnumSubset.swift */; };
EA89200228AECF2A006B9984 /* UIButton+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200128AECF2A006B9984 /* UIButton+Publisher.swift */; };
EA89200428AECF4B006B9984 /* UITextField+Publisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */; };
EA89200628B526D6006B9984 /* CheckboxGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89200528B526D6006B9984 /* CheckboxGroup.swift */; };
EA89201328B568D8006B9984 /* RadioBox.swift in Sources */ = {isa = PBXBuildFile; fileRef = EA89201228B568D8006B9984 /* RadioBox.swift */; };
@ -78,7 +77,6 @@
EAB1D29C28A5618900DAE764 /* RadioButtonGroup.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D29B28A5618900DAE764 /* RadioButtonGroup.swift */; };
EAB1D2CD28ABE76100DAE764 /* Withable.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D2CC28ABE76000DAE764 /* Withable.swift */; };
EAB1D2CF28ABEF2B00DAE764 /* Typography.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D2CE28ABEF2B00DAE764 /* Typography.swift */; };
EAB1D2E628AE842000DAE764 /* Publisher+Bind.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D2E328AE842000DAE764 /* Publisher+Bind.swift */; };
EAB1D2EA28AE84AA00DAE764 /* UIControlPublisher.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB1D2E928AE84AA00DAE764 /* UIControlPublisher.swift */; };
EAB5FED429267EB300998C17 /* UIView.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FED329267EB300998C17 /* UIView.swift */; };
EAB5FEED2927E1B200998C17 /* ButtonGroupPositionLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAB5FEEC2927E1B200998C17 /* ButtonGroupPositionLayout.swift */; };
@ -93,6 +91,7 @@
EAC9258C2911C9DE00091998 /* InputField.swift in Sources */ = {isa = PBXBuildFile; fileRef = EAC925872911C9DE00091998 /* InputField.swift */; };
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 */; };
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 */; };
@ -163,7 +162,6 @@
EA5E30522950DDA60082B959 /* TitleLockup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TitleLockup.swift; sourceTree = "<group>"; };
EA5E3057295105A40082B959 /* Tilelet.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Tilelet.swift; sourceTree = "<group>"; };
EA5E305929510F8B0082B959 /* EnumSubset.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnumSubset.swift; sourceTree = "<group>"; };
EA89200128AECF2A006B9984 /* UIButton+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIButton+Publisher.swift"; sourceTree = "<group>"; };
EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UITextField+Publisher.swift"; sourceTree = "<group>"; };
EA89200528B526D6006B9984 /* CheckboxGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheckboxGroup.swift; sourceTree = "<group>"; };
EA89201228B568D8006B9984 /* RadioBox.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioBox.swift; sourceTree = "<group>"; };
@ -196,7 +194,6 @@
EAB1D29B28A5618900DAE764 /* RadioButtonGroup.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadioButtonGroup.swift; sourceTree = "<group>"; };
EAB1D2CC28ABE76000DAE764 /* Withable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Withable.swift; sourceTree = "<group>"; };
EAB1D2CE28ABEF2B00DAE764 /* Typography.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Typography.swift; sourceTree = "<group>"; };
EAB1D2E328AE842000DAE764 /* Publisher+Bind.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Publisher+Bind.swift"; sourceTree = "<group>"; };
EAB1D2E928AE84AA00DAE764 /* UIControlPublisher.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIControlPublisher.swift; sourceTree = "<group>"; };
EAB5FED329267EB300998C17 /* UIView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIView.swift; sourceTree = "<group>"; };
EAB5FEEC2927E1B200998C17 /* ButtonGroupPositionLayout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ButtonGroupPositionLayout.swift; sourceTree = "<group>"; };
@ -210,6 +207,7 @@
EAC925872911C9DE00091998 /* InputField.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InputField.swift; sourceTree = "<group>"; };
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>"; };
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>"; };
@ -370,12 +368,12 @@
EA0FC2BE2912D18200DF80B4 /* Buttons */,
EAF7F092289985E200B287F5 /* Checkbox */,
EA985BF3296C609E00F2FF2E /* Icon */,
EA1F265F28B945070033E859 /* RadioSwatch */,
EA3362412892EF700071C351 /* Label */,
44604AD529CE195300E62B51 /* Line */,
445BA07629C07ABA0036A7C5 /* Notification */,
EA89200B28B530F0006B9984 /* RadioBox */,
EAF7F11428A1470D00B287F5 /* RadioButton */,
EA1F265F28B945070033E859 /* RadioSwatch */,
EAC925852911C9DE00091998 /* TextFields */,
EA5E304A294CBDBB0082B959 /* TileContainer */,
EA5E3056295105930082B959 /* Tilelet */,
@ -414,6 +412,7 @@
isa = PBXGroup;
children = (
EA4DB2FC28D3D0CA00103EE3 /* AnyEquatable.swift */,
EAF1FE9829D4850E00101452 /* Clickable.swift */,
EAA5EEDF28F49DB3003B3210 /* Colorable.swift */,
EA3361A9288B25E40071C351 /* Disabling.swift */,
EA5E305929510F8B0082B959 /* EnumSubset.swift */,
@ -571,8 +570,6 @@
EAB1D2E228AE842000DAE764 /* Publishers */ = {
isa = PBXGroup;
children = (
EAB1D2E328AE842000DAE764 /* Publisher+Bind.swift */,
EA89200128AECF2A006B9984 /* UIButton+Publisher.swift */,
EAB1D2E928AE84AA00DAE764 /* UIControlPublisher.swift */,
EA89200328AECF4B006B9984 /* UITextField+Publisher.swift */,
EAD8D2C028BFDE8B006EB6A6 /* UIGestureRecognizer+Publisher.swift */,
@ -823,6 +820,7 @@
EAF7F09A2899B17200B287F5 /* CATransaction.swift in Sources */,
EAF7F0A2289AFB3900B287F5 /* Errorable.swift in Sources */,
EA985C7D297DAED300F2FF2E /* Primitive.swift in Sources */,
EAF1FE9929D4850E00101452 /* Clickable.swift in Sources */,
EAB5FEF829393A7200998C17 /* ButtonGroupConstants.swift in Sources */,
EA3361AF288B26310071C351 /* FormFieldable.swift in Sources */,
44604AD729CE196600E62B51 /* Line.swift in Sources */,
@ -833,7 +831,6 @@
EA985C1D296CD13600F2FF2E /* BundleManager.swift in Sources */,
EA1F266528B945070033E859 /* RadioSwatch.swift in Sources */,
EA4DB18528CA967F00103EE3 /* SelectorGroupHandlerBase.swift in Sources */,
EA89200228AECF2A006B9984 /* UIButton+Publisher.swift in Sources */,
EAF7F0AB289B13FD00B287F5 /* TextStyleLabelAttribute.swift in Sources */,
EAB1D29C28A5618900DAE764 /* RadioButtonGroup.swift in Sources */,
EA985BE629688F6A00F2FF2E /* TileletBadgeModel.swift in Sources */,
@ -842,7 +839,6 @@
EA5E30532950DDA60082B959 /* TitleLockup.swift in Sources */,
EAA5EEB528ECBFB4003B3210 /* ImageLabelAttribute.swift in Sources */,
EAB5FF0129424ACB00998C17 /* UIControl.swift in Sources */,
EAB1D2E628AE842000DAE764 /* Publisher+Bind.swift in Sources */,
EA985BF5296C60C000F2FF2E /* Icon.swift in Sources */,
EA3361AA288B25E40071C351 /* Disabling.swift in Sources */,
EA3361B6288B2A410071C351 /* Control.swift in Sources */,

View File

@ -10,24 +10,21 @@ import UIKit
import Combine
@objc(VDSControl)
open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoable {
open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoable, Clickable {
//--------------------------------------------------
// MARK: - Combine Properties
//--------------------------------------------------
public var subject = PassthroughSubject<Void, Never>()
public var subscribers = Set<AnyCancellable>()
open var onClickSubscriber: AnyCancellable? {
public var onClickSubscriber: AnyCancellable? {
willSet {
if let onClickSubscriber {
onClickSubscriber.cancel()
}
}
didSet {
enabledHighlight = onClickSubscriber != nil
}
}
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -41,12 +38,12 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab
open override var isSelected: Bool { didSet { didChange() } }
internal var enabledHighlight: Bool = false
public var touchUpInsideCount: Int = 0
var isHighlightAnimating = false
open override var isHighlighted: Bool {
didSet {
if isHighlightAnimating == false && enabledHighlight {
if isHighlightAnimating == false && touchUpInsideCount > 0 {
isHighlightAnimating = true
UIView.animate(withDuration: 0.1, animations: { [weak self] in
self?.updateView()
@ -109,7 +106,7 @@ open class Control: UIControl, Handlerable, ViewProtocol, Resettable, UserInfoab
sendActions(for: .touchUpInside)
return true
}
//--------------------------------------------------
// MARK: - Overrides
//--------------------------------------------------

View File

@ -18,7 +18,8 @@ public protocol Buttonable: UIControl, Surfaceable, Disabling {
}
@objc(VDSButtonBase)
open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettable, UserInfoable {
open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettable, UserInfoable, Clickable {
//--------------------------------------------------
// MARK: - Configuration Properties
//--------------------------------------------------
@ -29,15 +30,12 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab
//--------------------------------------------------
public var subject = PassthroughSubject<Void, Never>()
public var subscribers = Set<AnyCancellable>()
open var onClickSubscriber: AnyCancellable? {
public var onClickSubscriber: AnyCancellable? {
willSet {
if let onClickSubscriber {
onClickSubscriber.cancel()
}
}
didSet {
enabledHighlight = onClickSubscriber != nil
}
}
//--------------------------------------------------
@ -60,13 +58,13 @@ open class ButtonBase: UIButton, Buttonable, Handlerable, ViewProtocol, Resettab
open var userInfo = [String: Primitive]()
internal var enabledHighlight: Bool = false
public var touchUpInsideCount: Int = 0
internal var isHighlightAnimating = false
open override var isHighlighted: Bool {
didSet {
if isHighlightAnimating == false && enabledHighlight {
if isHighlightAnimating == false && touchUpInsideCount > 0 {
isHighlightAnimating = true
UIView.animate(withDuration: 0.1, animations: { [weak self] in
self?.updateView()

View File

@ -12,22 +12,9 @@ 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(VDSCheckbox)
public class Checkbox: CheckboxBase{}
@objc(VDSSoloCheckbox)
public class SoloCheckbox: CheckboxBase{
public override func initialSetup() {
super.initialSetup()
onClickSubscriber = publisher(for: .touchUpInside)
.sink { control in
control.toggle()
}
}
}
@objc(VDSCheckboxBase)
open class CheckboxBase: Control, Errorable {
open class Checkbox: Control, Errorable {
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
@ -164,6 +151,13 @@ open class CheckboxBase: Control, Errorable {
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
open override func initialSetup() {
super.initialSetup()
onClick = { control in
control.toggle()
}
}
open override func setup() {
super.setup()

View File

@ -9,31 +9,24 @@ import Foundation
import UIKit
@objc(VDSCheckboxGroup)
public class CheckboxGroup: CheckboxGroupBase<Checkbox> {
public override func didSelect(_ selectedControl: Checkbox) {
selectedControl.toggle()
if selectedControl.isSelected, showError{
showError.toggle()
}
valueChanged()
}
}
public class CheckboxGroupBase<HandlerType: CheckboxBase>: SelectorGroupHandlerBase<HandlerType> {
public class CheckboxGroup: SelectorGroupHandlerBase<Checkbox> {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
public override var selectorViews: [HandlerType] {
public var selectedHandlers: [Checkbox]? {
let selected = selectorViews.filter{ $0.isSelected == true }
guard selected.count > 0 else { return nil }
return selected
}
public override var selectorViews: [Checkbox] {
didSet {
for selector in selectorViews {
if !mainStackView.arrangedSubviews.contains(selector) {
selector
.publisher(for: .touchUpInside)
.sink { [weak self] handler in
self?.didSelect(handler)
}.store(in: &subscribers)
selector.onClick = { [weak self] handler in
self?.didSelect(handler)
}
mainStackView.addArrangedSubview(selector)
}
}
@ -79,11 +72,13 @@ public class CheckboxGroupBase<HandlerType: CheckboxBase>: SelectorGroupHandlerB
mainStackView.pinToSuperView()
}
public var selectedHandlers: [HandlerType]? {
let selected = selectorViews.filter{ $0.isSelected == true }
guard selected.count > 0 else { return nil }
return selected
public override func didSelect(_ selectedControl: Checkbox) {
selectedControl.toggle()
if selectedControl.isSelected, showError{
showError.toggle()
}
valueChanged()
}
}

View File

@ -8,6 +8,7 @@
import Foundation
import UIKit
import VDSColorTokens
import Combine
@objc(VDSNotification)
/// A VDS Component that will render a view with information
@ -100,7 +101,7 @@ public class Notification: View {
}
//Text
open var titleText: String? { didSet{didChange()}}
open var titleText: String = "" { didSet{didChange()}}
open var subTitleText: String? { didSet{didChange()}}
@ -117,6 +118,20 @@ public class Notification: View {
$0.use = .secondary
}
open var onCloseClick: ((Notification)->())? {
didSet {
if let onCloseClick {
onCloseSubscriber = closeButton
.publisher(for: UITapGestureRecognizer())
.sink { _ in
onCloseClick(self)
}
} else {
onCloseSubscriber = nil
}
}
}
internal var onCloseSubscriber: AnyCancellable?
//--------------------------------------------------
// MARK: - Properties
//--------------------------------------------------
@ -183,13 +198,7 @@ public class Notification: View {
mainStackView.addArrangedSubview(typeIcon)
mainStackView.addArrangedSubview(labelButtonView)
mainStackView.addArrangedSubview(closeButton)
labelButtonView.addArrangedSubview(labelsView)
closeButton.publisher(for: UITapGestureRecognizer()).sink { [weak self] _ in
self?.didClickOnCloseButton()
}.store(in: &subscribers)
//labels
titleLabel.textColorConfiguration = textColorConfig.eraseToAnyColorable()
subTitleLabel.textColorConfiguration = textColorConfig.eraseToAnyColorable()
@ -231,7 +240,7 @@ public class Notification: View {
titleLabel.surface = surface
subTitleLabel.surface = surface
if let titleText {
if !titleText.isEmpty {
titleLabel.text = titleText
labelsView.addArrangedSubview(titleLabel)
} else {
@ -252,22 +261,14 @@ public class Notification: View {
if let primaryButtonModel {
primaryButton.text = primaryButtonModel.text
primaryButton.surface = surface
primaryButton.onClickSubscriber = primaryButton
.publisher(for: .touchUpInside)
.sink(receiveValue: { button in
primaryButtonModel.onClick(button)
})
primaryButton.onClick = primaryButtonModel.onClick
buttons.append(primaryButton)
}
if let secondaryButtonModel {
secondaryButton.text = secondaryButtonModel.text
secondaryButton.surface = surface
secondaryButton.onClickSubscriber = secondaryButton
.publisher(for: .touchUpInside)
.sink(receiveValue: { button in
secondaryButtonModel.onClick(button)
})
secondaryButton.onClick = secondaryButtonModel.onClick
buttons.append(secondaryButton)
}
@ -286,9 +287,5 @@ public class Notification: View {
.pinTrailing()
}
}
func didClickOnCloseButton() {
print("Notification close button clicked!!!")
}
}

View File

@ -12,22 +12,8 @@ import VDSFormControlsTokens
import Combine
@objc(VDSRadioBox)
public class RadioBox: RadioBoxBase{}
@objc(VDSSoloRadioBox)
public class SoloRadioBox: RadioBoxBase{
open class RadioBox: Control {
public override func initialSetup() {
super.initialSetup()
onClickSubscriber = publisher(for: .touchUpInside)
.sink { control in
control.toggle()
}
}
}
@objc(VDSRadioBoxBase)
open class RadioBoxBase: Control{
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
@ -138,7 +124,13 @@ open class RadioBoxBase: Control{
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
open override func initialSetup() {
super.initialSetup()
onClick = { control in
control.toggle()
}
}
open override func setup() {
super.setup()

View File

@ -9,30 +9,18 @@ import Foundation
import UIKit
@objc(VDSRadioBoxGroup)
public class RadioBoxGroup: RadioBoxGroupBase<RadioBox> {
public override func didSelect(_ selectedControl: RadioBox) {
let oldSelectedControl = selectorViews.filter { $0.isSelected == true }.first
oldSelectedControl?.toggle()
selectedControl.toggle()
valueChanged()
}
}
public class RadioBoxGroupBase<HandlerType: RadioBoxBase>: SelectorGroupSelectedHandlerBase<HandlerType> {
public class RadioBoxGroup: SelectorGroupSelectedHandlerBase<RadioBox> {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
public override var selectorViews: [HandlerType] {
public override var selectorViews: [RadioBox] {
didSet {
for selector in selectorViews {
if !mainStackView.arrangedSubviews.contains(selector) {
selector
.publisher(for: .touchUpInside)
.sink { [weak self] handler in
self?.didSelect(handler)
}.store(in: &subscribers)
selector.onClick = { [weak self] handler in
self?.didSelect(handler)
}
mainStackView.addArrangedSubview(selector)
}
}
@ -84,4 +72,11 @@ public class RadioBoxGroupBase<HandlerType: RadioBoxBase>: SelectorGroupSelected
}
}.store(in: &subscribers)
}
open override func didSelect(_ selectedControl: RadioBox) {
let oldSelectedControl = selectorViews.filter { $0.isSelected == true }.first
oldSelectedControl?.toggle()
selectedControl.toggle()
valueChanged()
}
}

View File

@ -11,30 +11,8 @@ import VDSColorTokens
import VDSFormControlsTokens
@objc(VDSRadioButton)
public class RadioButton: RadioButtonBase {
//for groups allows "toggle"
open override func toggle() {
//removed error
if showError && isSelected == false {
showError.toggle()
}
isSelected.toggle()
}
}
@objc(VDSSoloRadioButton)
public class SoloRadioButton: RadioButtonBase {
public override func initialSetup() {
super.initialSetup()
onClickSubscriber = publisher(for: .touchUpInside)
.sink { control in
control.toggle()
}
}
}
@objc(VDSRadioButtonBase)
open class RadioButtonBase: Control, Errorable {
open class RadioButton: Control, Errorable {
//--------------------------------------------------
// MARK: - Initializers
//--------------------------------------------------
@ -158,7 +136,13 @@ open class RadioButtonBase: Control, Errorable {
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
open override func initialSetup() {
super.initialSetup()
onClick = { control in
control.toggle()
}
}
open override func setup() {
super.setup()

View File

@ -9,32 +9,18 @@ import Foundation
import UIKit
@objc(VDSRadioButtonGroup)
public class RadioButtonGroup: RadioButtonGroupBase<RadioButton> {
public override func didSelect(_ selectedControl: RadioButton) {
selectedHandler?.toggle()
selectedControl.toggle()
if showError {
showError = false
}
valueChanged()
}
}
public class RadioButtonGroupBase<HandlerType: RadioButtonBase>: SelectorGroupSelectedHandlerBase<HandlerType> {
public class RadioButtonGroup: SelectorGroupSelectedHandlerBase<RadioButton> {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
public override var selectorViews: [HandlerType] {
public override var selectorViews: [RadioButton] {
didSet {
for selector in selectorViews {
if !mainStackView.arrangedSubviews.contains(selector) {
selector
.publisher(for: .touchUpInside)
.sink { [weak self] handler in
self?.didSelect(handler)
}.store(in: &subscribers)
selector.onClick = { [weak self] handler in
self?.didSelect(handler)
}
mainStackView.addArrangedSubview(selector)
}
}
@ -81,4 +67,22 @@ public class RadioButtonGroupBase<HandlerType: RadioButtonBase>: SelectorGroupSe
mainStackView.pinToSuperView()
}
public override func didSelect(_ selectedControl: RadioButton) {
if let selectedHandler {
updateToggle(selectedHandler)
}
updateToggle(selectedControl)
if showError {
showError = false
}
valueChanged()
}
private func updateToggle(_ radioButton: RadioButton) {
if radioButton.showError && radioButton.isSelected == false {
radioButton.showError.toggle()
}
radioButton.isSelected.toggle()
}
}

View File

@ -12,26 +12,7 @@ import VDSFormControlsTokens
import Combine
@objc(VDSRadioSwatch)
public class RadioSwatch: RadioSwatchBase{
//for groups allows "toggle"
open override func toggle() {
isSelected.toggle()
}
}
@objc(VDSSoloRadioSwatch)
public class SolorRadioSwatch: RadioSwatchBase{
public override func initialSetup() {
super.initialSetup()
onClickSubscriber = publisher(for: .touchUpInside)
.sink { control in
control.toggle()
}
}
}
@objc(VDSRadioSwatchBase)
open class RadioSwatchBase: Control {
open class RadioSwatch: Control {
//--------------------------------------------------
// MARK: - Initializers
@ -50,7 +31,7 @@ open class RadioSwatchBase: Control {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
//--------------------------------------------------
public var selectorView = UIView().with {
$0.translatesAutoresizingMaskIntoConstraints = false
}
@ -78,7 +59,13 @@ open class RadioSwatchBase: Control {
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
open override func initialSetup() {
super.initialSetup()
onClick = { control in
control.toggle()
}
}
open override func setup() {
super.setup()

View File

@ -10,24 +10,12 @@ import UIKit
import Combine
@objc(VDSRadioSwatchGroup)
public class RadioSwatchGroup: RadioSwatchGroupBase<RadioSwatch> {
public override func didSelect(selector: RadioSwatch) {
selectedHandler?.toggle()
selector.toggle()
label.text = selector.text
didChange()
valueChanged()
}
}
public class RadioSwatchGroupBase<HandlerType: RadioSwatchBase>: SelectorGroupSelectedHandlerBase<HandlerType>, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate {
public class RadioSwatchGroup: SelectorGroupSelectedHandlerBase<RadioSwatch>, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, UICollectionViewDelegate {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
public override var selectorViews: [HandlerType] {
public override var selectorViews: [RadioSwatch] {
didSet {
collectionView.reloadData()
}
@ -160,18 +148,20 @@ public class RadioSwatchGroupBase<HandlerType: RadioSwatchBase>: SelectorGroupSe
public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "collectionViewCell", for: indexPath)
let handler = selectorViews[indexPath.row]
handler.subscribers.forEach{ $0.cancel() }
handler.subscribers.removeAll()
handler.publisher(for: .touchUpInside).sink { [weak self] handler in
handler.onClick = { [weak self] handler in
self?.didSelect(selector: handler)
}.store(in: &handler.subscribers)
}
cell.subviews.forEach { $0.removeFromSuperview() }
cell.addSubview(handler)
handler.pinToSuperView()
return cell
}
open func didSelect(selector: HandlerType) {
fatalError("Must override didSelect")
public func didSelect(selector: RadioSwatch) {
selectedHandler?.toggle()
selector.toggle()
label.text = selector.text
didChange()
valueChanged()
}
}

View File

@ -172,7 +172,6 @@ open class EntryField: Control {
open override func setup() {
super.setup()
enabledHighlight = false
isAccessibilityElement = true
accessibilityTraits = .button
addSubview(stackView)

View File

@ -13,6 +13,7 @@ import Combine
@objc(VDSTilelet)
open class Tilelet: TileContainer {
//--------------------------------------------------
// MARK: - Enums
//--------------------------------------------------
@ -61,8 +62,8 @@ open class Tilelet: TileContainer {
//--------------------------------------------------
// MARK: - Public Properties
//--------------------------------------------------
open override var onClickSubscriber: AnyCancellable? {
//--------------------------------------------------
public override var onClickSubscriber: AnyCancellable? {
didSet {
isAccessibilityElement = onClickSubscriber != nil
}

View File

@ -18,18 +18,7 @@ import Combine
Knob: The circular indicator that slides on the container.
*/
@objc(VDSToggle)
public class Toggle: ToggleBase{
public override func initialSetup() {
super.initialSetup()
publisher(for: .touchUpInside)
.sink { control in
control.toggle()
}.store(in: &subscribers)
}
}
@objc(VDSToggleBase)
open class ToggleBase: Control {
open class Toggle: Control {
//--------------------------------------------------
// MARK: - Enums
//--------------------------------------------------
@ -64,6 +53,7 @@ open class ToggleBase: Control {
// MARK: - Private Properties
//--------------------------------------------------
private var stackView = UIStackView().with {
$0.isUserInteractionEnabled = false
$0.translatesAutoresizingMaskIntoConstraints = false
$0.axis = .horizontal
$0.distribution = .fill
@ -80,7 +70,7 @@ open class ToggleBase: Control {
//--------------------------------------------------
// MARK: - Configuration Properties
//--------------------------------------------------
//--------------------------------------------------
// Sizes are from InVision design specs.
public let toggleSize = CGSize(width: 52, height: 24)
public let toggleContainerSize = CGSize(width: 52, height: 44)
@ -223,14 +213,16 @@ open class ToggleBase: Control {
//--------------------------------------------------
// MARK: - Lifecycle
//--------------------------------------------------
open override func initialSetup() {
super.initialSetup()
onClick = { control in
control.toggle()
}
}
open override func setup() {
super.setup()
//add tapGesture to self
publisher(for: UITapGestureRecognizer()).sink { [weak self] _ in
self?.sendActions(for: .touchUpInside)
}.store(in: &subscribers)
isAccessibilityElement = true
accessibilityTraits = .button
addSubview(stackView)
@ -288,7 +280,7 @@ open class ToggleBase: Control {
toggleView.backgroundColor = toggleColorConfiguration.getColor(self)
knobView.backgroundColor = knobColorConfiguration.getColor(self)
}
/// This will toggle the state of the Toggle and execute the actionBlock if provided.
open func toggle() {
isOn.toggle()

View File

@ -0,0 +1,39 @@
//
// Clickable.swift
// VDS
//
// Created by Matt Bruce on 3/29/23.
//
import Foundation
import UIKit
import Combine
public protocol Clickable: Handlerable where Self: UIControl {
var touchUpInsideCount: Int { get set }
var onClickSubscriber: AnyCancellable? { get set }
}
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 {
if let newValue {
onClickSubscriber = publisher(for: .touchUpInside)
.sink { c in
newValue(c)
}
} else {
onClickSubscriber?.cancel()
onClickSubscriber = nil
}
}
}
}

View File

@ -1,24 +0,0 @@
//
// Publisher+Bind.swift
// VDS
//
// Created by Matt Bruce on 8/18/22.
//
import Foundation
import Combine
public typealias Binding = Subscriber
public extension Publisher where Failure == Never {
func bind<B: Binding>(subscriber: B) -> AnyCancellable
where B.Failure == Never, B.Input == Output {
handleEvents(receiveSubscription: { subscription in
subscriber.receive(subscription: subscription)
})
.sink { value in
_ = subscriber.receive(value)
}
}
}

View File

@ -1,17 +0,0 @@
//
// Button+Publisher.swift
// VDS
//
// Created by Matt Bruce on 8/18/22.
//
import Foundation
import UIKit
import Combine
extension UIButton {
public var tapPublisher: AnyPublisher<UIButton, Never> {
publisher(for: .touchUpInside)
.eraseToAnyPublisher()
}
}

View File

@ -21,10 +21,8 @@ public final class UIControlSubscription<SubscriberType: Subscriber, Control: UI
self.event = event
//allow highlight for VDS.Controls on "onClick" events
if let c = control as? VDS.Control, event == .touchUpInside {
c.enabledHighlight = true
} else if let c = control as? VDS.ButtonBase, event == .touchUpInside {
c.enabledHighlight = true
if let c = control as? Clickable, event == .touchUpInside {
c.touchUpInsideCount += 1
}
control.addTarget(self, action: #selector(eventHandler), for: event)
}
@ -40,10 +38,8 @@ public final class UIControlSubscription<SubscriberType: Subscriber, Control: UI
deinit {
//remove highlight for VDS.Controls on "onClick" events
if let c = control as? VDS.Control, event == .touchUpInside {
c.enabledHighlight = false
} else if let c = control as? VDS.ButtonBase, event == .touchUpInside {
c.enabledHighlight = false
if let c = control as? Clickable, event == .touchUpInside, c.touchUpInsideCount > 0 {
c.touchUpInsideCount -= 1
}
}