From a0405e11c38f2e2ab0efad47f41d3bb8f396c8a1 Mon Sep 17 00:00:00 2001 From: Alican Aycil Date: Thu, 14 Mar 2024 15:55:04 +0100 Subject: [PATCH 1/6] [RadioButton#853] Fix size of radio button --- .../RadioButton/View/UIKit/RadioButtonUIView.swift | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/core/Sources/Components/RadioButton/View/UIKit/RadioButtonUIView.swift b/core/Sources/Components/RadioButton/View/UIKit/RadioButtonUIView.swift index d9f1afbcc..0ff665e67 100644 --- a/core/Sources/Components/RadioButton/View/UIKit/RadioButtonUIView.swift +++ b/core/Sources/Components/RadioButton/View/UIKit/RadioButtonUIView.swift @@ -12,9 +12,8 @@ import UIKit // MARK: - Constants private enum Constants { - static let toggleViewHeight: CGFloat = 28 - static let toggleViewSpacing: CGFloat = 4 - static let textLabelTopSpacing: CGFloat = 3 + static let toggleViewHeight: CGFloat = 32 + static let textLabelTopSpacing: CGFloat = 5 static let haloWidth: CGFloat = 4 } From 03030439728d27e3d2cabab88de1d22f1a2fbead Mon Sep 17 00:00:00 2001 From: Alican Aycil Date: Thu, 21 Mar 2024 19:25:43 +0100 Subject: [PATCH 2/6] [RadioButton#853] Fix size of swiftui radio button --- .../Components/RadioButton/View/SwiftUI/RadioButtonView.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/Sources/Components/RadioButton/View/SwiftUI/RadioButtonView.swift b/core/Sources/Components/RadioButton/View/SwiftUI/RadioButtonView.swift index 9e8f36e28..fd4ca707e 100644 --- a/core/Sources/Components/RadioButton/View/SwiftUI/RadioButtonView.swift +++ b/core/Sources/Components/RadioButton/View/SwiftUI/RadioButtonView.swift @@ -11,8 +11,8 @@ import SwiftUI private enum Constants { static let pressedLineWidth: CGFloat = 4 static let lineWidth: CGFloat = 2 - static let size: CGFloat = 20 - static let filledSize: CGFloat = 10 + static let size: CGFloat = 24 + static let filledSize: CGFloat = 12 } /// RadioButtonView is a single radio button control. /// Radio buttons are used for selecting a single value from a selection of values. From d1c3fd088fc7cbc0e74764f69869a221a18cf5d4 Mon Sep 17 00:00:00 2001 From: Alican Aycil Date: Fri, 22 Mar 2024 11:24:35 +0100 Subject: [PATCH 3/6] [RadioButton#853] Add demo controllers for testing radio and checkbox together --- .../RadioCheckboxUIViewController.swift | 115 ++++++++++++++++++ .../Controllers/RadioCheckboxView.swift | 67 ++++++++++ .../ListComponentsViewController.swift | 83 +++++++++---- 3 files changed, 238 insertions(+), 27 deletions(-) create mode 100644 spark/Demo/Classes/View/ListView/Controllers/RadioCheckboxUIViewController.swift create mode 100644 spark/Demo/Classes/View/ListView/Controllers/RadioCheckboxView.swift diff --git a/spark/Demo/Classes/View/ListView/Controllers/RadioCheckboxUIViewController.swift b/spark/Demo/Classes/View/ListView/Controllers/RadioCheckboxUIViewController.swift new file mode 100644 index 000000000..f4c4129c1 --- /dev/null +++ b/spark/Demo/Classes/View/ListView/Controllers/RadioCheckboxUIViewController.swift @@ -0,0 +1,115 @@ +// +// RadioCheckboxUIViewController.swift +// SparkDemo +// +// Created by alican.aycil on 22.03.24. +// Copyright © 2024 Adevinta. All rights reserved. +// + +import UIKit +import SparkCore +import Combine + +final class RadioCheckboxUIViewController: UIViewController { + + private let theme = SparkThemePublisher.shared.theme + private var cancellables = Set() + + private lazy var alignment: CheckboxUIView = { + let view = CheckboxUIView( + theme: self.theme, + text: "Alignment: Click to change postion.", + checkedImage: DemoIconography.shared.checkmark.uiImage, + isEnabled: true, + selectionState: .selected, + alignment: .left + ) + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + + private lazy var lineView: UIView = { + let view = UIView() + view.backgroundColor = UIColor.lightGray + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + + private lazy var checkboxGroup: CheckboxGroupUIView = { + var items = [ + CheckboxGroupItemDefault(title: "Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.", id: "1", selectionState: .selected, isEnabled: true), + CheckboxGroupItemDefault(title: "Hello World", id: "2", selectionState: .selected, isEnabled: true) + ] + let view = CheckboxGroupUIView( + checkedImage: DemoIconography.shared.checkmark.uiImage, + items: items, + alignment: alignment.isSelected ? CheckboxAlignment.left : CheckboxAlignment.right, + theme: self.theme, + intent: .main, + accessibilityIdentifierPrefix: "Checkbox" + ) + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + + private lazy var radioButtonGroup: RadioButtonUIGroupView = { + var items = [ + RadioButtonUIItem(id: 0, label: "Hello World"), + RadioButtonUIItem(id: 1, label: "Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.") + ] + let view = RadioButtonUIGroupView( + theme: self.theme, + intent: .main, + selectedID: 0, + items: items, + labelAlignment: alignment.isSelected ? RadioButtonLabelAlignment.trailing : RadioButtonLabelAlignment.leading, + groupLayout: .vertical + ) + view.translatesAutoresizingMaskIntoConstraints = false + return view + }() + + override func viewDidLoad() { + super.viewDidLoad() + self.navigationItem.title = "Radio Checkbox UIKit" + + self.setupView() + self.subscribe() + } + + private func setupView() { + self.view.backgroundColor = UIColor.systemBackground + + self.view.addSubview(alignment) + self.view.addSubview(lineView) + self.view.addSubview(checkboxGroup) + self.view.addSubview(radioButtonGroup) + + NSLayoutConstraint.activate([ + + self.alignment.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor, constant: 16), + self.alignment.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 16), + self.alignment.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -16), + + self.lineView.topAnchor.constraint(equalTo: self.alignment.bottomAnchor, constant: 32), + self.lineView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 16), + self.lineView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -16), + self.lineView.heightAnchor.constraint(equalToConstant: 1), + + self.checkboxGroup.topAnchor.constraint(equalTo: self.lineView.bottomAnchor, constant: 32), + self.checkboxGroup.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 16), + self.checkboxGroup.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -16), + + self.radioButtonGroup.topAnchor.constraint(equalTo: self.checkboxGroup.bottomAnchor, constant: 16), + self.radioButtonGroup.leadingAnchor.constraint(equalTo: self.view.leadingAnchor, constant: 16), + self.radioButtonGroup.trailingAnchor.constraint(equalTo: self.view.trailingAnchor, constant: -16) + ]) + } + + private func subscribe() { + self.alignment.publisher.subscribe(in: &self.cancellables) { [weak self] isSelected in + self?.radioButtonGroup.labelAlignment = isSelected == .selected ? RadioButtonLabelAlignment.trailing : RadioButtonLabelAlignment.leading + self?.checkboxGroup.alignment = isSelected == .selected ? CheckboxAlignment.left : CheckboxAlignment.right + } + } +} diff --git a/spark/Demo/Classes/View/ListView/Controllers/RadioCheckboxView.swift b/spark/Demo/Classes/View/ListView/Controllers/RadioCheckboxView.swift new file mode 100644 index 000000000..05362368f --- /dev/null +++ b/spark/Demo/Classes/View/ListView/Controllers/RadioCheckboxView.swift @@ -0,0 +1,67 @@ +// +// RadioCheckboxView.swift +// SparkDemo +// +// Created by alican.aycil on 22.03.24. +// Copyright © 2024 Adevinta. All rights reserved. +// + +import Spark +import SparkCore +import SwiftUI + +struct RadioCheckboxView: View { + + // MARK: - Properties + @State private var theme: Theme = SparkThemePublisher.shared.theme + @State private var alignment: CheckboxAlignment = .left + @State private var selectedIcon = CheckboxListView.Icons.checkedImage + @State private var selectedID: Int? = 0 + @State private var items: [any CheckboxGroupItemProtocol] = [ + CheckboxGroupItemDefault(title: "Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.", id: "1", selectionState: .selected, isEnabled: true), + CheckboxGroupItemDefault(title: "Hello World", id: "2", selectionState: .selected, isEnabled: true) + ] + @State private var radioGroupItems: [RadioButtonItem] = [ + RadioButtonItem(id: 0, label: "Hello World"), + RadioButtonItem(id: 1, label: "Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.") + ] + + + // MARK: - View + var body: some View { + Component( + name: "Radio Checkbox SwiftUI", + configuration: { + + EnumSelector( + title: "Alignment", + dialogTitle: "Select a Alignment", + values: CheckboxAlignment.allCases, + value: self.$alignment + ) + }, + integration: { + VStack(alignment: .leading) { + CheckboxGroupView( + checkedImage: self.selectedIcon.image, + items: self.$items, + layout: .vertical, + alignment: self.alignment, + theme: self.theme, + intent: .main, + accessibilityIdentifierPrefix: "checkbox-group" + ) + + RadioButtonGroupView( + theme: self.theme, + intent: .main, + selectedID: self.$selectedID, + items: self.radioGroupItems, + labelAlignment: self.alignment == .left ? .trailing : .leading, + groupLayout: .vertical + ) + } + } + ) + } +} diff --git a/spark/Demo/Classes/View/ListView/ListComponentsViewController.swift b/spark/Demo/Classes/View/ListView/ListComponentsViewController.swift index d47e86461..7ac8b27af 100644 --- a/spark/Demo/Classes/View/ListView/ListComponentsViewController.swift +++ b/spark/Demo/Classes/View/ListView/ListComponentsViewController.swift @@ -54,8 +54,9 @@ final class ListComponentsViewController: UICollectionViewController { private func setupData() { /// CollectionView append sections and items var snapShot = SnapShot() - snapShot.appendSections([.all]) - snapShot.appendItems(uiComponentAllCases.map{ $0.rawValue }, toSection: .all) + snapShot.appendSections([.list, .random]) + snapShot.appendItems(uiComponentAllCases.map{ $0.rawValue }, toSection: .list) + snapShot.appendItems(Row.allCases.map{ $0.name }, toSection: .random) collectionViewDataSource.apply(snapShot) } } @@ -76,58 +77,86 @@ extension ListComponentsViewController { var viewController: UIViewController! - switch uiComponentAllCases[indexPath.row] { + switch Section.allCases[indexPath.section] { + case .list: + viewController = self.listSectionControllers(index: indexPath.row) + case .random: + viewController = self.randomSectionControllers(index: indexPath.row) + } + + guard viewController != nil else { return } + self.navigationController?.pushViewController(viewController, animated: true) + } + + private func listSectionControllers(index: Int) -> UIViewController? { + + switch uiComponentAllCases[index] { case .badge: - viewController = ListViewController() + return ListViewController() case .button: - viewController = ListViewController() + return ListViewController() case .checkbox: - viewController = ListViewController() + return ListViewController() case .checkboxGroup: - viewController = ListViewController() + return ListViewController() case .chip: - viewController = ListViewController() + return ListViewController() case .icon: - viewController = ListViewController() + return ListViewController() case .progressBarIndeterminate: - viewController = ListViewController() + return ListViewController() case .progressBarSingle: - viewController = ListViewController() + return ListViewController() case .radioButton: - viewController = ListViewController() + return ListViewController() case .radioButtonGroup: - viewController = ListViewController() + return ListViewController() case .ratingDisplay: - viewController = ListViewController() + return ListViewController() case .ratingInput: - viewController = ListViewController() + return ListViewController() case .spinner: - viewController = ListViewController() + return ListViewController() case .star: - viewController = ListViewController() + return ListViewController() case .switchButton: - viewController = ListViewController() + return ListViewController() case .tab: - viewController = ListViewController() + return ListViewController() case .tag: - viewController = ListViewController() + return ListViewController() case .textField: - viewController = ListViewController() + return ListViewController() case .addOnTextField: - viewController = ListViewController() + return ListViewController() default: - break + return nil + } + } + + private func randomSectionControllers(index: Int) -> UIViewController? { + switch Row.allCases[index] { + case .radioCheckboxSwiftui: + return UIHostingController( + rootView: RadioCheckboxView().environment(\.navigationController, self.navigationController) + ) + case .radioCheckboxUikit: + return RadioCheckboxUIViewController() } - guard viewController != nil else { return } - self.navigationController?.pushViewController(viewController, animated: true) } } // MARK: - Enums private extension ListComponentsViewController { - enum Section { - case all + enum Section: CaseIterable { + case list + case random + } + + enum Row: CaseIterable { + case radioCheckboxSwiftui + case radioCheckboxUikit } } From 0abd0609d46120435739706d013355e4911cfbde Mon Sep 17 00:00:00 2001 From: Alican Aycil Date: Mon, 25 Mar 2024 17:45:56 +0100 Subject: [PATCH 4/6] [CheckboxGroup#864] Add isDisabled parameter to uikit checkbox group --- .../View/UIKit/CheckboxGroupUIView.swift | 14 ++++++++++++++ .../CheckboxGroupComponentUIView.swift | 5 +++++ .../CheckboxGroupComponentUIViewModel.swift | 16 ++++++++++++++++ 3 files changed, 35 insertions(+) diff --git a/core/Sources/Components/Checkbox/View/UIKit/CheckboxGroupUIView.swift b/core/Sources/Components/Checkbox/View/UIKit/CheckboxGroupUIView.swift index 77003e11a..113ca5c7c 100644 --- a/core/Sources/Components/Checkbox/View/UIKit/CheckboxGroupUIView.swift +++ b/core/Sources/Components/Checkbox/View/UIKit/CheckboxGroupUIView.swift @@ -124,6 +124,20 @@ public final class CheckboxGroupUIView: UIControl { self.itemsStackView.arrangedSubviews.compactMap { $0 as? CheckboxUIView } } + /// A Boolean value indicating whether the component is in the enabled state. + public override var isEnabled: Bool { + didSet{ + guard isEnabled != oldValue else { return } + if isEnabled { + self.checkboxes.enumerated().forEach { index, item in + item.isEnabled = self.items.indices.contains(index) ? self.items[index].isEnabled : true + } + } else { + self.checkboxes.forEach { $0.isEnabled = false } + } + } + } + // MARK: - Initialization /// Not implemented. Please use another init. diff --git a/spark/Demo/Classes/View/Components/Checkbox/UIKit/CheckboxGroup/CheckboxGroupComponentUIView.swift b/spark/Demo/Classes/View/Components/Checkbox/UIKit/CheckboxGroup/CheckboxGroupComponentUIView.swift index a64c580e9..9ee6960d8 100644 --- a/spark/Demo/Classes/View/Components/Checkbox/UIKit/CheckboxGroup/CheckboxGroupComponentUIView.swift +++ b/spark/Demo/Classes/View/Components/Checkbox/UIKit/CheckboxGroup/CheckboxGroupComponentUIView.swift @@ -81,6 +81,11 @@ final class CheckboxGroupComponentUIView: ComponentUIView { self.componentView.title = showGroupTitle ? viewModel.title : "" } + self.viewModel.$isEnabled.subscribe(in: &self.cancellables) { [weak self] isEnabled in + guard let self = self else { return } + self.componentView.isEnabled = isEnabled + } + self.viewModel.$groupType.subscribe(in: &self.cancellables) { [weak self] type in guard let self = self else { return } self.viewModel.groupTypeConfigurationItemViewModel.buttonTitle = type.name diff --git a/spark/Demo/Classes/View/Components/Checkbox/UIKit/CheckboxGroup/CheckboxGroupComponentUIViewModel.swift b/spark/Demo/Classes/View/Components/Checkbox/UIKit/CheckboxGroup/CheckboxGroupComponentUIViewModel.swift index b7b65ec5d..d6f0d5d09 100644 --- a/spark/Demo/Classes/View/Components/Checkbox/UIKit/CheckboxGroup/CheckboxGroupComponentUIViewModel.swift +++ b/spark/Demo/Classes/View/Components/Checkbox/UIKit/CheckboxGroup/CheckboxGroupComponentUIViewModel.swift @@ -81,6 +81,14 @@ final class CheckboxGroupComponentUIViewModel: ComponentUIViewModel { ) }() + lazy var isEnableConfigurationItemViewModel: ComponentsConfigurationItemUIViewModel = { + return .init( + name: "Is Enable", + type: .toggle(isOn: self.isEnabled), + target: (source: self, action: #selector(self.toggleIsEnable)) + ) + }() + lazy var iconConfigurationItemViewModel: ComponentsConfigurationItemUIViewModel = { return .init( name: "Icons", @@ -142,6 +150,7 @@ final class CheckboxGroupComponentUIViewModel: ComponentUIViewModel { @Published var isAlignmentLeft: Bool @Published var isLayoutVertical: Bool @Published var showGroupTitle: Bool + @Published var isEnabled: Bool @Published var icon: [String: UIImage] @Published var groupType: CheckboxGroupType @@ -151,6 +160,7 @@ final class CheckboxGroupComponentUIViewModel: ComponentUIViewModel { isAlignmentLeft: Bool = true, isLayoutVertical: Bool = false, showGroupTitle: Bool = false, + isEnabled: Bool = true, icon: [String: UIImage] = ["Checkmark": DemoIconography.shared.checkmark.uiImage], groupType: CheckboxGroupType = .doubleMix ) { @@ -159,6 +169,7 @@ final class CheckboxGroupComponentUIViewModel: ComponentUIViewModel { self.isAlignmentLeft = isAlignmentLeft self.isLayoutVertical = isLayoutVertical self.showGroupTitle = showGroupTitle + self.isEnabled = isEnabled self.icon = icon self.groupType = groupType super.init(identifier: "Checkbox Group") @@ -169,6 +180,7 @@ final class CheckboxGroupComponentUIViewModel: ComponentUIViewModel { self.alignmentConfigurationItemViewModel, self.layoutConfigurationItemViewModel, self.titleConfigurationItemViewModel, + self.isEnableConfigurationItemViewModel, self.iconConfigurationItemViewModel, self.groupTypeConfigurationItemViewModel, self.itemsSelectionStateConfigurationItemViewModel @@ -199,6 +211,10 @@ extension CheckboxGroupComponentUIViewModel { self.showGroupTitle.toggle() } + @objc func toggleIsEnable() { + self.isEnabled.toggle() + } + @objc func presentIconSheet() { self.showIconSheetSubject.send(icons) } From 2e18c12bce01a02374b62660c2cfe3b361e187e7 Mon Sep 17 00:00:00 2001 From: Alican Aycil Date: Mon, 25 Mar 2024 17:47:01 +0100 Subject: [PATCH 5/6] [CheckboxGroup#864] Fix partially disable issue on swiftui checkbox group --- .../Components/Checkbox/View/SwiftUI/CheckboxGroupView.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/core/Sources/Components/Checkbox/View/SwiftUI/CheckboxGroupView.swift b/core/Sources/Components/Checkbox/View/SwiftUI/CheckboxGroupView.swift index 41fc056df..b25a8a143 100644 --- a/core/Sources/Components/Checkbox/View/SwiftUI/CheckboxGroupView.swift +++ b/core/Sources/Components/Checkbox/View/SwiftUI/CheckboxGroupView.swift @@ -166,6 +166,7 @@ public struct CheckboxGroupView: View { isEnabled: item.isEnabled.wrappedValue, selectionState: item.selectionState ) + .disabled(!item.isEnabled.wrappedValue) .accessibilityIdentifier(identifier) } } From 21ff38d35383d079036b77781d8b1abe8155db6c Mon Sep 17 00:00:00 2001 From: "louis.borlee" Date: Tue, 26 Mar 2024 10:31:28 +0100 Subject: [PATCH 6/6] [Slider#1977] Updated Slider handle size from 24x24 to 32x32 --- core/Sources/Components/Slider/Constant/SliderConstants.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/Sources/Components/Slider/Constant/SliderConstants.swift b/core/Sources/Components/Slider/Constant/SliderConstants.swift index b44c8001c..ca5702562 100644 --- a/core/Sources/Components/Slider/Constant/SliderConstants.swift +++ b/core/Sources/Components/Slider/Constant/SliderConstants.swift @@ -9,7 +9,7 @@ import Foundation enum SliderConstants { - static let handleSize = CGSize(width: 24, height: 24) - static let activeIndicatorSize = CGSize(width: 32, height: 32) + static let handleSize = CGSize(width: 32, height: 32) + static let activeIndicatorSize = CGSize(width: 40, height: 40) static let barHeight: CGFloat = 4.0 }