From 9f19fd47176e85cec0a98884dc1f26854659d42b Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Tue, 20 Feb 2024 16:32:58 +0530 Subject: [PATCH 1/4] added color picker for gradient & backgroundcolor picker --- .../TileContainerViewController.swift | 243 +++++++++++++++++- 1 file changed, 231 insertions(+), 12 deletions(-) diff --git a/VDSSample/ViewControllers/TileContainerViewController.swift b/VDSSample/ViewControllers/TileContainerViewController.swift index ec374ad..98ea78a 100644 --- a/VDSSample/ViewControllers/TileContainerViewController.swift +++ b/VDSSample/ViewControllers/TileContainerViewController.swift @@ -13,10 +13,19 @@ import Combine class TileContainerViewController: BaseViewController { + lazy var colorPicker: UIColorPickerViewController = { + let picker = UIColorPickerViewController() + if case .custom(let hexCode) = component.color { + picker.selectedColor = UIColor(hexString: hexCode) + } + picker.delegate = self + return picker + }() + lazy var backgroundColorPickerSelectorView = { PickerSelectorView(title: "white", picker: self.picker, - items: TileContainer.BackgroundColor.allCases) + items: BackgroundColor.allCases) }() lazy var imageFallbackColorPickerSelectorView = { @@ -35,22 +44,122 @@ class TileContainerViewController: BaseViewController { items: TileContainer.AspectRatio.allCases) }() - var clickableSwitch = Toggle() + lazy var backgroundEffectSelectorView = { + PickerSelectorView(title: "none", + picker: self.picker, + items: BackgroundEffect.allCases) + }() + lazy var gradientColorView1: UIStackView = { + let stackView = UIStackView() + let indicatorWrapper = View() + indicatorWrapper.addSubview(gradientColor1View) + indicatorWrapper.height(32) + indicatorWrapper.pinTop() + indicatorWrapper.pinLeading() + indicatorWrapper.pinBottom() + indicatorWrapper.pinTrailingGreaterThanOrEqualTo(anchor: indicatorWrapper.trailingAnchor) + stackView.addArrangedSubview(indicatorWrapper) + stackView.distribution = .fillEqually + stackView.alignment = .fill + var button = Button().with { instance in + instance.size = .small + instance.use = .secondary + instance.text = "Select" + instance.onClick = { [weak self] in + self?.gradientColorTapped($0, view: self?.gradientColor1View) + } + } + button.tag = 1 + let buttonWrapper = View() + buttonWrapper.addSubview(button) + buttonWrapper.height(32) + button.pinTop() + button.pinTrailing() + button.pinBottom() + button.pinLeadingGreaterThanOrEqualTo(anchor: buttonWrapper.leadingAnchor) + stackView.addArrangedSubview(buttonWrapper) + stackView.tag = 1 + stackView.spacing = 10 + return stackView + }() + + lazy var gradientColorView2: UIStackView = { + let stackView = UIStackView() + stackView.distribution = .fillEqually + stackView.alignment = .fill + stackView.spacing = 10 + let indicatorWrapper = View() + indicatorWrapper.addSubview(gradientColor2View) + indicatorWrapper.height(32) + indicatorWrapper.pinTop() + indicatorWrapper.pinLeading() + indicatorWrapper.pinBottom() + indicatorWrapper.pinTrailingGreaterThanOrEqualTo(anchor: indicatorWrapper.trailingAnchor) + stackView.addArrangedSubview(indicatorWrapper) + var button = Button().with { instance in + instance.size = .small + instance.use = .secondary + instance.text = "Select" + instance.onClick = { [weak self] in + self?.gradientColorTapped($0, view: self?.gradientColor2View) + } + } + button.tag = 2 + let buttonWrapper = View() + buttonWrapper.addSubview(button) + buttonWrapper.height(32) + button.pinTop() + button.pinTrailing() + button.pinBottom() + button.pinLeadingGreaterThanOrEqualTo(anchor: buttonWrapper.leadingAnchor) + stackView.addArrangedSubview(buttonWrapper) + stackView.tag = 2 + return stackView + }() + + var gradientColor1View: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.widthAnchor.constraint(equalToConstant: 20).isActive = true + view.heightAnchor.constraint(equalToConstant: 20).isActive = true + view.tag = 1 + return view + }() + + var gradientColor2View: UIView = { + let view = UIView() + view.translatesAutoresizingMaskIntoConstraints = false + view.widthAnchor.constraint(equalToConstant: 20).isActive = true + view.heightAnchor.constraint(equalToConstant: 20).isActive = true + view.tag = 2 + return view + }() + + var gradientColorsFormStackView = FormSection().with { $0.isHidden = true } + var backgroundColor: BackgroundColor = .secondary + var clickableSwitch = Toggle() var showBackgroundImageSwitch = Toggle() var showBorderSwitch = Toggle() var showDropShadowSwitch = Toggle() - var heightTextField = NumericField() - var widthTextField = NumericField() - + var selectedGradient1Color: String? + var selectedGradient2Color: String? + var colorPickerType: ColorPickerType = .backgroundColor var backgroundImage = UIImage(named: "backgroundTest")! + var selectedGradientColorView: UIView? + + var heightTextField = NumericField().with { + $0.placeholder = "Minimum 100px else it will occupy full container" + } + var widthTextField = NumericField().with { + $0.placeholder = "Minimum 100px else it will occupy full container" + } override func viewDidLoad() { super.viewDidLoad() addContentTopView(view: .makeWrapper(for: component)) component.width = 150 - component.color = .black - + component.color = .secondary setupPicker() setupModel() } @@ -66,13 +175,18 @@ class TileContainerViewController: BaseViewController { addFormRow(label: "Width", view: widthTextField) addFormRow(label: "Height", view: heightTextField) addFormRow(label: "Show Border", view: showBorderSwitch) - //addFormRow(label: "Show Drop Shadow", view: showDropShadowSwitch) + addFormRow(label: "Show Drop Shadow", view: showDropShadowSwitch) addFormRow(label: "Background Color", view: backgroundColorPickerSelectorView) addFormRow(label: "Padding", view: paddingPickerSelectorView) addFormRow(label: "Aspect Ratio", view: scalingTypePickerSelectorView) addFormRow(label: "Background Image", view: showBackgroundImageSwitch) addFormRow(label: "Image Fallback Color", view: imageFallbackColorPickerSelectorView) - + addFormRow(label: "Background Effect", view: backgroundEffectSelectorView) + //Gradient Section + gradientColorsFormStackView.addFormRow(label: "Gradient Color1", view: gradientColorView1) + gradientColorsFormStackView.addFormRow(label: "Gradient Color2", view: gradientColorView2) + append(section: gradientColorsFormStackView) + clickableSwitch.onChange = { [weak self] sender in guard let self else { return } if sender.isOn { @@ -116,7 +230,7 @@ class TileContainerViewController: BaseViewController { func setupModel() { //setup UI surfacePickerSelectorView.text = component.surface.rawValue - backgroundColorPickerSelectorView.text = component.color.rawValue + backgroundColorPickerSelectorView.text = backgroundColor.rawValue paddingPickerSelectorView.text = component.padding.rawValue scalingTypePickerSelectorView.text = component.aspectRatio.rawValue widthTextField.text = component.width != nil ? "\(component.width!)" : "" @@ -131,7 +245,28 @@ class TileContainerViewController: BaseViewController { } backgroundColorPickerSelectorView.onPickerDidSelect = { [weak self] item in - self?.component.color = item + guard let self else { return } + if let color = item.color { + self.component.color = color + } else { + self.colorPickerType = .backgroundColor + self.present(self.colorPicker, animated: true) + } + } + + backgroundEffectSelectorView.onPickerDidSelect = { [weak self] in + guard let self else { return } + if let effect = $0.effect { + self.component.backgroundEffect = effect + self.gradientColorsFormStackView.isHidden = true + self.selectedGradient1Color = nil + self.selectedGradient1Color = nil + self.gradientColor1View.backgroundColor = .clear + self.gradientColor2View.backgroundColor = .clear + } else { + self.colorPickerType = .gradientColors(gradientColor1View) + self.gradientColorsFormStackView.isHidden = false + } } scalingTypePickerSelectorView.onPickerDidSelect = { [weak self] item in @@ -146,13 +281,97 @@ class TileContainerViewController: BaseViewController { self?.component.imageFallbackColor = item } } + + func gradientColorTapped(_ sender: Button, view: UIView?) { + selectedGradientColorView = view + let selectedColor = (sender.tag == 1) ? selectedGradient1Color : selectedGradient2Color + if let selectedColor { + colorPicker.selectedColor = UIColor(hexString: selectedColor) + } + present(colorPicker, animated: true) + } } extension TileContainerViewController: ComponentSampleable { static func makeSample() -> ComponentSample { let component = Self.makeComponent() component.width = 150 - component.color = .black + component.color = .primary return ComponentSample(component: component, trailingPinningType: .lessThanOrEqual) } } + +extension TileContainerViewController: UIColorPickerViewControllerDelegate { + + func colorPickerViewControllerDidFinish(_ viewController: UIColorPickerViewController) { + dismiss(animated: true) + } + + func colorPickerViewControllerDidSelectColor(_ viewController: UIColorPickerViewController) { + guard let hexString = viewController.selectedColor.hexString else { return } + switch colorPickerType { + case .backgroundColor: + component.color = .custom(hexString) + case .gradientColors: + guard let selectedGradientColorView else { return } + if selectedGradientColorView.tag == 1 { + selectedGradient1Color = hexString + } else { + selectedGradient2Color = hexString + } + selectedGradientColorView.backgroundColor = UIColor(hexString: hexString) + if let selectedGradient1Color, let selectedGradient2Color { + component.backgroundEffect = .gradient(selectedGradient1Color, selectedGradient2Color) + } + } + } +} + +extension TileContainerViewController { + + //Created new BackgroundEffect enum for sample app only. Since we defined enum with associated value color defined in TileContainer cannot be RawRepresentable & CaseIterable + enum BackgroundEffect: String, CaseIterable { + case transparency + case gradient + case none + + var effect: TileContainer.BackgroundEffect? { + return switch self { + case .transparency: + .transparency + case .gradient: + nil + case .none: + TileContainer.BackgroundEffect.none + } + } + } + + //Created new BackgroundColor enum for sample app only. Since we defined enum with associated value color defined in TileContainer cannot be RawRepresentable & CaseIterable + enum BackgroundColor: String, CaseIterable { + + case primary, secondary, white, black, gray, custom + + var color: TileContainer.BackgroundColor? { + switch self { + case .primary: + .primary + case .secondary: + .secondary + case .white: + .white + case .black: + .black + case .gray: + .gray + case .custom: + nil + } + } + } + + //Internal helper enum to identiy the configuration + enum ColorPickerType { + case backgroundColor, gradientColors(UIView) + } +} From 1780c9568411faeae40959febc5bf740933b49a3 Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Tue, 20 Feb 2024 19:56:27 +0530 Subject: [PATCH 2/4] removed gray --- VDSSample/ViewControllers/TileContainerViewController.swift | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/VDSSample/ViewControllers/TileContainerViewController.swift b/VDSSample/ViewControllers/TileContainerViewController.swift index 98ea78a..6a58b9c 100644 --- a/VDSSample/ViewControllers/TileContainerViewController.swift +++ b/VDSSample/ViewControllers/TileContainerViewController.swift @@ -350,7 +350,7 @@ extension TileContainerViewController { //Created new BackgroundColor enum for sample app only. Since we defined enum with associated value color defined in TileContainer cannot be RawRepresentable & CaseIterable enum BackgroundColor: String, CaseIterable { - case primary, secondary, white, black, gray, custom + case primary, secondary, white, black, custom var color: TileContainer.BackgroundColor? { switch self { @@ -362,8 +362,6 @@ extension TileContainerViewController { .white case .black: .black - case .gray: - .gray case .custom: nil } From d99bf783f4692be168346537902557c445493e9b Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Tue, 20 Feb 2024 20:58:43 +0530 Subject: [PATCH 3/4] added contentArea background color --- .../TileContainerViewController.swift | 37 +++++++++++++++++-- 1 file changed, 33 insertions(+), 4 deletions(-) diff --git a/VDSSample/ViewControllers/TileContainerViewController.swift b/VDSSample/ViewControllers/TileContainerViewController.swift index 6a58b9c..76782e4 100644 --- a/VDSSample/ViewControllers/TileContainerViewController.swift +++ b/VDSSample/ViewControllers/TileContainerViewController.swift @@ -147,7 +147,12 @@ class TileContainerViewController: BaseViewController { var colorPickerType: ColorPickerType = .backgroundColor var backgroundImage = UIImage(named: "backgroundTest")! var selectedGradientColorView: UIView? - + var contentAreaBackgroundColorButton = Button().with { instance in + instance.size = .small + instance.use = .secondary + instance.text = "Select" + } + var heightTextField = NumericField().with { $0.placeholder = "Minimum 100px else it will occupy full container" } @@ -178,6 +183,10 @@ class TileContainerViewController: BaseViewController { addFormRow(label: "Show Drop Shadow", view: showDropShadowSwitch) addFormRow(label: "Background Color", view: backgroundColorPickerSelectorView) addFormRow(label: "Padding", view: paddingPickerSelectorView) + let rowView = addFormRow(label: "Content area BG color(only for testing padding)", view: contentAreaBackgroundColorButton) + if let rowView = rowView as? UIStackView { + rowView.alignment = .top + } addFormRow(label: "Aspect Ratio", view: scalingTypePickerSelectorView) addFormRow(label: "Background Image", view: showBackgroundImageSwitch) addFormRow(label: "Image Fallback Color", view: imageFallbackColorPickerSelectorView) @@ -264,22 +273,31 @@ class TileContainerViewController: BaseViewController { self.gradientColor1View.backgroundColor = .clear self.gradientColor2View.backgroundColor = .clear } else { - self.colorPickerType = .gradientColors(gradientColor1View) + self.colorPickerType = .gradientColors self.gradientColorsFormStackView.isHidden = false } } scalingTypePickerSelectorView.onPickerDidSelect = { [weak self] item in self?.component.aspectRatio = item + self?.component.layoutIfNeeded() + self?.showDebug(show: self?.debugViewSwitch.isOn ?? false) } paddingPickerSelectorView.onPickerDidSelect = { [weak self] item in self?.component.padding = item } - + imageFallbackColorPickerSelectorView.onPickerDidSelect = { [weak self] item in self?.component.imageFallbackColor = item } + + contentAreaBackgroundColorButton.onClick = { [weak self] _ in + guard let self else { return } + self.colorPickerType = .contentViewBackgroundColor + self.colorPicker.selectedColor = self.component.containerView.backgroundColor ?? .white + self.present(self.colorPicker, animated: true) + } } func gradientColorTapped(_ sender: Button, view: UIView?) { @@ -310,6 +328,8 @@ extension TileContainerViewController: UIColorPickerViewControllerDelegate { func colorPickerViewControllerDidSelectColor(_ viewController: UIColorPickerViewController) { guard let hexString = viewController.selectedColor.hexString else { return } switch colorPickerType { + case .contentViewBackgroundColor: + component.containerView.backgroundColor = UIColor(hexString: hexString) case .backgroundColor: component.color = .custom(hexString) case .gradientColors: @@ -335,6 +355,15 @@ extension TileContainerViewController { case gradient case none + var rawValue: String { + switch self { + case .gradient: + "gradient (select gradient colors to apply)" + default: + String(describing: self) + } + } + var effect: TileContainer.BackgroundEffect? { return switch self { case .transparency: @@ -370,6 +399,6 @@ extension TileContainerViewController { //Internal helper enum to identiy the configuration enum ColorPickerType { - case backgroundColor, gradientColors(UIView) + case backgroundColor, gradientColors, contentViewBackgroundColor } } From 7cf03551ae91fa9d12a5bd5f5569720e9655c206 Mon Sep 17 00:00:00 2001 From: Krishna Kishore Bandaru Date: Wed, 21 Feb 2024 17:47:58 +0530 Subject: [PATCH 4/4] Added custom padding --- .../TileContainerViewController.swift | 61 +++++++++++++++++-- 1 file changed, 56 insertions(+), 5 deletions(-) diff --git a/VDSSample/ViewControllers/TileContainerViewController.swift b/VDSSample/ViewControllers/TileContainerViewController.swift index 76782e4..d1a571b 100644 --- a/VDSSample/ViewControllers/TileContainerViewController.swift +++ b/VDSSample/ViewControllers/TileContainerViewController.swift @@ -35,7 +35,7 @@ class TileContainerViewController: BaseViewController { lazy var paddingPickerSelectorView = { PickerSelectorView(title: "16", picker: self.picker, - items: TileContainer.Padding.allCases) + items: Padding.allCases) }() lazy var scalingTypePickerSelectorView = { @@ -138,6 +138,7 @@ class TileContainerViewController: BaseViewController { var gradientColorsFormStackView = FormSection().with { $0.isHidden = true } var backgroundColor: BackgroundColor = .secondary + var padding: Padding = .padding4X var clickableSwitch = Toggle() var showBackgroundImageSwitch = Toggle() var showBorderSwitch = Toggle() @@ -147,12 +148,19 @@ class TileContainerViewController: BaseViewController { var colorPickerType: ColorPickerType = .backgroundColor var backgroundImage = UIImage(named: "backgroundTest")! var selectedGradientColorView: UIView? + var customPaddingRowView: UIView? + var anyCancellable: AnyCancellable? + var contentAreaBackgroundColorButton = Button().with { instance in instance.size = .small instance.use = .secondary instance.text = "Select" } - + + var paddingTextField = NumericField().with { + $0.placeholder = "Custom Padding" + } + var heightTextField = NumericField().with { $0.placeholder = "Minimum 100px else it will occupy full container" } @@ -183,7 +191,9 @@ class TileContainerViewController: BaseViewController { addFormRow(label: "Show Drop Shadow", view: showDropShadowSwitch) addFormRow(label: "Background Color", view: backgroundColorPickerSelectorView) addFormRow(label: "Padding", view: paddingPickerSelectorView) - let rowView = addFormRow(label: "Content area BG color(only for testing padding)", view: contentAreaBackgroundColorButton) + customPaddingRowView = addFormRow(label: "Custom Padding", view: paddingTextField) + customPaddingRowView?.isHidden = true + let rowView = addFormRow(label: "Content area BG color(only for padding validation)", view: contentAreaBackgroundColorButton) if let rowView = rowView as? UIStackView { rowView.alignment = .top } @@ -195,6 +205,12 @@ class TileContainerViewController: BaseViewController { gradientColorsFormStackView.addFormRow(label: "Gradient Color1", view: gradientColorView1) gradientColorsFormStackView.addFormRow(label: "Gradient Color2", view: gradientColorView2) append(section: gradientColorsFormStackView) + + anyCancellable = paddingTextField.textPublisher.receive(on: RunLoop.main).sink { [weak self] value in + if let value = Float(value) { + self?.component.padding = .custom(CGFloat(value)) + } + } clickableSwitch.onChange = { [weak self] sender in guard let self else { return } @@ -227,12 +243,14 @@ class TileContainerViewController: BaseViewController { .numberPublisher .sink { [weak self] number in self?.component.height = number?.cgFloatValue + self?.component.layoutIfNeeded() }.store(in: &subscribers) widthTextField .numberPublisher .sink { [weak self] number in self?.component.width = number?.cgFloatValue + self?.component.layoutIfNeeded() }.store(in: &subscribers) } @@ -240,7 +258,7 @@ class TileContainerViewController: BaseViewController { //setup UI surfacePickerSelectorView.text = component.surface.rawValue backgroundColorPickerSelectorView.text = backgroundColor.rawValue - paddingPickerSelectorView.text = component.padding.rawValue + paddingPickerSelectorView.text = padding.rawValue scalingTypePickerSelectorView.text = component.aspectRatio.rawValue widthTextField.text = component.width != nil ? "\(component.width!)" : "" heightTextField.text = component.height != nil ? "\(component.height!)" : "" @@ -285,7 +303,13 @@ class TileContainerViewController: BaseViewController { } paddingPickerSelectorView.onPickerDidSelect = { [weak self] item in - self?.component.padding = item + if let value = item.value { + self?.paddingTextField.text = "" + self?.component.padding = value + self?.customPaddingRowView?.isHidden = true + } else { + self?.customPaddingRowView?.isHidden = false + } } imageFallbackColorPickerSelectorView.onPickerDidSelect = { [weak self] item in @@ -401,4 +425,31 @@ extension TileContainerViewController { enum ColorPickerType { case backgroundColor, gradientColors, contentViewBackgroundColor } + + //Internal helper enum to map padding & pass custom padding values + public enum Padding: String, CaseIterable { + case padding2X + case padding4X + case padding6X + case padding8X + case padding12X + case custom + + public var value: TileContainer.Padding? { + return switch self { + case .padding2X: + .padding2X + case .padding4X: + .padding4X + case .padding6X: + .padding6X + case .padding8X: + .padding8X + case .padding12X: + .padding12X + case .custom: + nil + } + } + } }