Skip to content

Commit

Permalink
[Divider] Added UIKit demo
Browse files Browse the repository at this point in the history
  • Loading branch information
LouisBorleeAdevinta committed Jul 31, 2024
1 parent 6b522f6 commit c9561ef
Show file tree
Hide file tree
Showing 5 changed files with 357 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .Demo/Classes/Enum/UIComponent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ struct UIComponent: RawRepresentable, CaseIterable, Equatable {
.iconButton,
.checkbox,
.chip,
.divider,
.formField,
.icon,
.popover,
Expand Down Expand Up @@ -43,6 +44,7 @@ struct UIComponent: RawRepresentable, CaseIterable, Equatable {
static let button = UIComponent(rawValue: "Button")
static let checkbox = UIComponent(rawValue: "Checkbox")
static let chip = UIComponent(rawValue: "Chip")
static let divider = UIComponent(rawValue: "Divider")
static let formField = UIComponent(rawValue: "FormField")
static let icon = UIComponent(rawValue: "Icon")
static let iconButton = UIComponent(rawValue: "Icon Button")
Expand Down
2 changes: 2 additions & 0 deletions .Demo/Classes/View/Components/ComponentsViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ extension ComponentsViewController {
)
case .chip:
viewController = ChipComponentViewController.build()
case .divider:
viewController = DividerComponentUIViewController.build()
case .formField:
viewController = FormFieldComponentUIViewController.build()
case .icon:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//
// DividerComponentUIView.swift
// SparkDemo
//
// Created by louis.borlee on 31/07/2024.
// Copyright © 2024 Adevinta. All rights reserved.
//

import Combine
import UIKit
@_spi(SI_SPI) import SparkCommon

final class DividerComponentUIView: ComponentUIView {

// MARK: - Components
private let componentView: DividerUIView

// MARK: - Properties

private let viewModel: DividerComponentUIViewModel
private var cancellables: Set<AnyCancellable> = []

private var heightConstraint = NSLayoutConstraint()

// MARK: - Initializer
init(viewModel: DividerComponentUIViewModel) {
self.viewModel = viewModel

let divider = DividerUIView(
theme: self.viewModel.theme,
intent: self.viewModel.intent
)
divider.label.text = self.viewModel.text
divider.label.numberOfLines = 0
divider.axis = self.viewModel.axis
divider.alignment = self.viewModel.alignment

self.componentView = divider

super.init(
viewModel: viewModel,
integrationStackViewAlignment: .fill,
componentView: self.componentView
)

// Setup
self.setupSubscriptions()
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

// MARK: - Subscribe
private func setupSubscriptions() {
self.viewModel.$theme.subscribe(in: &self.cancellables) { [weak self] theme in
guard let self = self else { return }
let themes = self.viewModel.themes
let themeTitle: String? = theme is SparkTheme ? themes.first?.title : themes.last?.title

self.viewModel.themeConfigurationItemViewModel.buttonTitle = themeTitle
self.viewModel.configurationViewModel.update(theme: theme)

self.componentView.theme = theme
}

self.viewModel.$intent.subscribe(in: &self.cancellables) { [weak self] intent in
guard let self = self else { return }
self.viewModel.intentConfigurationItemViewModel.buttonTitle = intent.name
self.componentView.intent = intent
}

self.viewModel.$axis.subscribe(in: &self.cancellables) { [weak self] axis in
guard let self = self else { return }
self.viewModel.axisConfigurationItemViewModel.buttonTitle = axis.name
self.componentView.axis = axis
if axis == .vertical {
self.heightConstraint = self.componentView.heightAnchor.constraint(equalToConstant: 300)
self.heightConstraint.isActive = true
} else {
self.heightConstraint.isActive = false
self.componentView.removeConstraint(self.heightConstraint)
}
}

self.viewModel.$alignment.subscribe(in: &self.cancellables) { [weak self] alignment in
guard let self = self else { return }
self.viewModel.alignmentConfigurationItemViewModel.buttonTitle = alignment.name
self.componentView.alignment = alignment
}

self.viewModel.$text.subscribe(in: &self.cancellables) { [weak self] text in
guard let self = self else { return }
self.viewModel.textConfigurationItemViewModel.buttonTitle = text
self.componentView.label.text = text
if let text, text.isEmpty == false {
self.componentView.showLabel = true
} else {
self.componentView.showLabel = false
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
//
// DividerComponentUIViewController.swift
// SparkDemo
//
// Created by louis.borlee on 31/07/2024.
// Copyright © 2024 Adevinta. All rights reserved.
//

import Combine
import SparkCore
import SwiftUI
import UIKit
@_spi(SI_SPI) import SparkCommon

final class DividerComponentUIViewController: UIViewController {

// MARK: - Published Properties
@ObservedObject private var themePublisher = SparkThemePublisher.shared

// MARK: - Properties
let componentView: DividerComponentUIView
let viewModel: DividerComponentUIViewModel
private var cancellables: Set<AnyCancellable> = []

// MARK: - Initializer
init(viewModel: DividerComponentUIViewModel) {
self.viewModel = viewModel
self.componentView = DividerComponentUIView(viewModel: viewModel)
super.init(nibName: nil, bundle: nil)

self.componentView.viewController = self
}

required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}

// MARK: - Lifecycle
override func loadView() {
super.loadView()
view = componentView
}

// MARK: - ViewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
self.navigationItem.title = "Divider"
self.addPublisher()
}

// MARK: - Add Publishers
private func addPublisher() {

self.themePublisher
.$theme
.sink { [weak self] theme in
guard let self = self else { return }
self.viewModel.theme = theme
self.navigationController?.navigationBar.tintColor = theme.colors.main.main.uiColor
}
.store(in: &self.cancellables)

self.viewModel.showThemeSheet.subscribe(in: &self.cancellables) { intents in
self.presentThemeActionSheet(intents)
}

self.viewModel.showIntentSheet.subscribe(in: &self.cancellables) { intents in
self.presentIntentActionSheet(intents)
}

self.viewModel.showAxisSheet.subscribe(in: &self.cancellables) { axis in
self.presentAxisActionSheet(axis)
}

self.viewModel.showAlignmentSheet.subscribe(in: &self.cancellables) { alignments in
self.presentAlignmentActionSheet(alignments)
}
}
}

// MARK: - Builder
extension DividerComponentUIViewController {

static func build() -> DividerComponentUIViewController {
let viewModel = DividerComponentUIViewModel(theme: SparkThemePublisher.shared.theme)
return DividerComponentUIViewController(viewModel: viewModel)
}
}

// MARK: - Navigation
extension DividerComponentUIViewController {

private func presentThemeActionSheet(_ themes: [ThemeCellModel]) {
let actionSheet = SparkActionSheet<Theme>.init(
values: themes.map { $0.theme },
texts: themes.map { $0.title }) { theme in
self.themePublisher.theme = theme
}
self.present(actionSheet, isAnimated: true)
}

private func presentIntentActionSheet(_ intents: [DividerIntent]) {
let actionSheet = SparkActionSheet<DividerIntent>.init(
values: intents,
texts: intents.map { $0.name }) { intent in
self.viewModel.intent = intent
}
self.present(actionSheet, isAnimated: true)
}

private func presentAxisActionSheet(_ axis: [DividerAxis]) {
let actionSheet = SparkActionSheet<DividerAxis>.init(
values: axis,
texts: axis.map { $0.name }) { axis in
self.viewModel.axis = axis
}
self.present(actionSheet, isAnimated: true)
}

private func presentAlignmentActionSheet(_ alignments: [DividerAlignment]) {
let actionSheet = SparkActionSheet<DividerAlignment>.init(
values: alignments,
texts: alignments.map { $0.name }) { alignment in
self.viewModel.alignment = alignment
}
self.present(actionSheet, isAnimated: true)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
//
// DividerComponentUIViewModel.swift
// SparkDemo
//
// Created by louis.borlee on 31/07/2024.
// Copyright © 2024 Adevinta. All rights reserved.
//

import UIKit
import Combine

final class DividerComponentUIViewModel: ComponentUIViewModel, ObservableObject {

let themes = ThemeCellModel.themes

@Published var theme: Theme
@Published var text: String?
@Published var intent = DividerIntent.outline
@Published var axis = DividerAxis.horizontal
@Published var alignment = DividerAlignment.center

// MARK: - Published Properties
var showThemeSheet: AnyPublisher<[ThemeCellModel], Never> {
self.showThemeSheetSubject
.eraseToAnyPublisher()
}
var showIntentSheet: AnyPublisher<[DividerIntent], Never> {
self.showIntentSheetSubject
.eraseToAnyPublisher()
}
var showAxisSheet: AnyPublisher<[DividerAxis], Never> {
self.showAxisSheetSubject
.eraseToAnyPublisher()
}
var showAlignmentSheet: AnyPublisher<[DividerAlignment], Never> {
self.showAlignmentSheetSubject
.eraseToAnyPublisher()
}

private var showThemeSheetSubject: PassthroughSubject<[ThemeCellModel], Never> = .init()
private var showIntentSheetSubject: PassthroughSubject<[DividerIntent], Never> = .init()
private var showAxisSheetSubject: PassthroughSubject<[DividerAxis], Never> = .init()
private var showAlignmentSheetSubject: PassthroughSubject<[DividerAlignment], Never> = .init()

lazy var themeConfigurationItemViewModel: ComponentsConfigurationItemUIViewModel = {
return .init(
name: "Theme",
type: .button,
target: (source: self, action: #selector(self.presentThemeSheet))
)
}()

lazy var intentConfigurationItemViewModel: ComponentsConfigurationItemUIViewModel = {
return .init(
name: "Intent",
type: .button,
target: (source: self, action: #selector(self.presentIntentSheet))
)
}()

lazy var axisConfigurationItemViewModel: ComponentsConfigurationItemUIViewModel = {
return .init(
name: "Axis",
type: .button,
target: (source: self, action: #selector(self.presentAxisSheet))
)
}()

lazy var alignmentConfigurationItemViewModel: ComponentsConfigurationItemUIViewModel = {
return .init(
name: "Alignment",
type: .button,
target: (source: self, action: #selector(self.presentAlignmentSheet))
)
}()

lazy var textConfigurationItemViewModel: ComponentsConfigurationItemUIViewModel = {
return .init(
name: "Text",
type: .input(text: self.text),
target: (source: self, action: #selector(self.textChanged(_:))))
}()

override func configurationItemsViewModel() -> [ComponentsConfigurationItemUIViewModel] {
return [
self.themeConfigurationItemViewModel,
self.intentConfigurationItemViewModel,
self.axisConfigurationItemViewModel,
self.alignmentConfigurationItemViewModel,
self.textConfigurationItemViewModel
]
}

init(theme: any Theme) {
self.theme = theme
super.init(identifier: "Divider")
}

@objc func presentThemeSheet() {
self.showThemeSheetSubject.send(self.themes)
}

@objc func presentIntentSheet() {
self.showIntentSheetSubject.send(DividerIntent.allCases)
}

@objc func presentAxisSheet() {
self.showAxisSheetSubject.send(DividerAxis.allCases)
}

@objc func presentAlignmentSheet() {
self.showAlignmentSheetSubject.send(DividerAlignment.allCases)
}

@objc func textChanged(_ textField: UITextField) {
if textField.text?.isEmpty == false {
self.text = textField.text
} else {
self.text = nil
}
}
}

0 comments on commit c9561ef

Please sign in to comment.