diff --git a/.Demo/App/SceneDelegate.swift b/.Demo/App/SceneDelegate.swift index 7b7732f45..5532a9fb2 100644 --- a/.Demo/App/SceneDelegate.swift +++ b/.Demo/App/SceneDelegate.swift @@ -7,6 +7,10 @@ // import UIKit +import SwiftUI +import SparkSnackbar +import SparkButton +import SparkTheming class SceneDelegate: UIResponder, UIWindowSceneDelegate { @@ -16,6 +20,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { guard let windowScene = scene as? UIWindowScene else { return } let window = UIWindow(windowScene: windowScene) + SparkConfiguration.load() window.rootViewController = SparkTabbarController() self.window = window window.makeKeyAndVisible() diff --git a/.Demo/Classes/Enum/Components.swift b/.Demo/Classes/Enum/Components.swift new file mode 100644 index 000000000..d81c599a5 --- /dev/null +++ b/.Demo/Classes/Enum/Components.swift @@ -0,0 +1,13 @@ +// +// Components.swift +// SparkDemo +// +// Created by louis.borlee on 19/09/2024. +// Copyright © 2024 Adevinta. All rights reserved. +// + +import Foundation + +enum Components: CaseIterable { + case snackbar +} diff --git a/.Demo/Classes/Tabbar/SparkTabbarController.swift b/.Demo/Classes/Tabbar/SparkTabbarController.swift index 403800928..dd63f0842 100644 --- a/.Demo/Classes/Tabbar/SparkTabbarController.swift +++ b/.Demo/Classes/Tabbar/SparkTabbarController.swift @@ -35,18 +35,16 @@ public final class SparkTabbarController: UITabBarController { }() /// Third Tab - private lazy var listViewController: UIViewController = { - let layout = ComponentsViewController.makeLayout() - let viewController = UINavigationController(rootViewController: ListComponentsViewController(collectionViewLayout: layout)) - viewController.tabBarItem = UITabBarItem(title: "List", image: UIImage(systemName: "list.bullet.rectangle"), tag: 0) + private lazy var uiKitViewController: UIViewController = { + let viewController = UIHostingController(rootView: NewComponentsView(isUIKit: true)) + viewController.tabBarItem = UITabBarItem(title: "UIKit", image: UIImage(systemName: "u.circle"), tag: 0) return viewController }() /// Fourth Tab - private lazy var settingsViewController: UIViewController = { - var layout = SettingsViewController.makeLayout() - let viewController = UINavigationController(rootViewController: SettingsViewController(collectionViewLayout: layout)) - viewController.tabBarItem = UITabBarItem(title: "Settings", image: UIImage(systemName: "gear"), tag: 0) + private lazy var swiftUIViewController: UIViewController = { + let viewController = UIHostingController(rootView: NewComponentsView(isUIKit: false)) + viewController.tabBarItem = UITabBarItem(title: "SwiftUI", image: UIImage(systemName: "s.circle"), tag: 0) return viewController }() @@ -67,8 +65,8 @@ public final class SparkTabbarController: UITabBarController { viewControllers = [ self.themeViewController, self.componentVersionViewController, - self.listViewController, - self.settingsViewController + self.uiKitViewController, + self.swiftUIViewController ] } diff --git a/.Demo/Classes/View/Components/Main/Configuration/SwiftUI/OptionalEnumSelector.swift b/.Demo/Classes/View/Components/Main/Configuration/SwiftUI/OptionalEnumSelector.swift new file mode 100644 index 000000000..7a92a5814 --- /dev/null +++ b/.Demo/Classes/View/Components/Main/Configuration/SwiftUI/OptionalEnumSelector.swift @@ -0,0 +1,41 @@ +// +// OptionalEnumSelector.swift +// SparkDemo +// +// Created by louis.borlee on 19/09/2024. +// Copyright © 2024 Adevinta. All rights reserved. +// + +import SwiftUI + +struct OptionalEnumSelector: View where Value: CaseIterable & Hashable { + let title: String + let dialogTitle: String + let values: [Value] + @Binding var value: Value? + + var nameFormatter: (Value?) -> String = { value in + return value?.name ?? "Default" + } + + @State private var isPresented = false + + var body: some View { + HStack() { + Text("\(title): ").bold() + Button(self.nameFormatter(value)) { + self.isPresented = true + } + .confirmationDialog(dialogTitle, isPresented: self.$isPresented) { + ForEach(self.values, id: \.self) { value in + Button(self.nameFormatter(value)) { + self.value = value + } + } + Button("Default") { + self.value = nil + } + } + } + } +} diff --git a/.Demo/Classes/View/ListView/Cells/BadgeCell/BadgeCell.swift b/.Demo/Classes/View/ListView/Cells/BadgeCell/BadgeCell.swift deleted file mode 100644 index bfe3b9296..000000000 --- a/.Demo/Classes/View/ListView/Cells/BadgeCell/BadgeCell.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// BadgeTableViewCell.swift -// SparkDemo -// -// Created by alican.aycil on 12.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class BadgeCell: UITableViewCell, Configurable { - - typealias CellConfigartion = BadgeConfiguration - typealias Component = BadgeUIView - - lazy var component: BadgeUIView = { - return BadgeUIView( - theme: SparkThemePublisher.shared.theme, - intent: .main, - size: .medium, - value: 99, - format: .default, - isBorderVisible: false - ) - }() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.theme = configuration.theme - self.component.intent = configuration.intent - self.component.value = configuration.value - self.component.format = configuration.format - } -} diff --git a/.Demo/Classes/View/ListView/Cells/BadgeCell/BadgeConfiguration.swift b/.Demo/Classes/View/ListView/Cells/BadgeCell/BadgeConfiguration.swift deleted file mode 100644 index 55efcb5d1..000000000 --- a/.Demo/Classes/View/ListView/Cells/BadgeCell/BadgeConfiguration.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// BadgeConfiguration.swift -// SparkDemo -// -// Created by alican.aycil on 12.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct BadgeConfiguration: ComponentConfiguration { - var theme: Theme - var intent: BadgeIntentType - var size: BadgeSize - var value: Int - var format: BadgeFormat -} diff --git a/.Demo/Classes/View/ListView/Cells/ButtonCell/ButtonCell.swift b/.Demo/Classes/View/ListView/Cells/ButtonCell/ButtonCell.swift deleted file mode 100644 index 5600dcb0f..000000000 --- a/.Demo/Classes/View/ListView/Cells/ButtonCell/ButtonCell.swift +++ /dev/null @@ -1,77 +0,0 @@ -// -// ButtonCell.swift -// SparkDemo -// -// Created by alican.aycil on 14.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class ButtonCell: UITableViewCell, Configurable { - - typealias CellConfigartion = ButtonConfiguration - typealias Component = ButtonUIView - - lazy var component: ButtonUIView = { - return ButtonUIView( - theme: SparkTheme.shared, - intent: .main, - variant: .filled, - size: .medium, - shape: .rounded, - alignment: .leadingImage - ) - }() - - var attributeString: NSAttributedString { - let text: String = "Hello world" - let attributeString = NSMutableAttributedString( - string: text, - attributes: [.font: UIFont.italicSystemFont(ofSize: 18)] - ) - let attributes: [NSMutableAttributedString.Key: Any] = [ - .font: UIFont( - descriptor: UIFontDescriptor().withSymbolicTraits([.traitBold, .traitItalic]) ?? UIFontDescriptor(), - size: 18 - ), - .foregroundColor: UIColor.red - ] - attributeString.setAttributes(attributes, range: NSRange(location: 0, length: 5)) - return attributeString - } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.theme = configuration.theme - self.component.intent = configuration.intent - self.component.variant = configuration.variant - self.component.size = configuration.size - self.component.shape = configuration.shape - self.component.alignment = configuration.alignment - self.component.isEnabled = configuration.isEnabled - - switch configuration.content { - case .text: - self.component.setTitle("Button", for: .normal) - self.component.setImage(nil, for: .normal) - case .imageAndText: - self.component.setTitle("Hello World", for: .normal) - self.component.setImage(UIImage(systemName: "book.circle"), for: .normal) - case .attributedText: - self.component.setAttributedTitle(self.attributeString, for: .normal) - self.component.setImage(nil, for: .normal) - default: - break - } - } -} diff --git a/.Demo/Classes/View/ListView/Cells/ButtonCell/ButtonConfiguration.swift b/.Demo/Classes/View/ListView/Cells/ButtonCell/ButtonConfiguration.swift deleted file mode 100644 index 87dda6239..000000000 --- a/.Demo/Classes/View/ListView/Cells/ButtonCell/ButtonConfiguration.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// ButtonConfiguration.swift -// SparkDemo -// -// Created by alican.aycil on 14.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct ButtonConfiguration: ComponentConfiguration { - var theme: Theme - var intent: ButtonIntent - var variant: ButtonVariant - var size: ButtonSize - var shape: ButtonShape - var alignment: ButtonAlignment - var content: ButtonContentDefault - var isEnabled: Bool -} diff --git a/.Demo/Classes/View/ListView/Cells/CheckboxCell/CheckboxCell.swift b/.Demo/Classes/View/ListView/Cells/CheckboxCell/CheckboxCell.swift deleted file mode 100644 index 8d1ad8a2b..000000000 --- a/.Demo/Classes/View/ListView/Cells/CheckboxCell/CheckboxCell.swift +++ /dev/null @@ -1,55 +0,0 @@ -// -// CheckboxCell.swift -// Spark -// -// Created by alican.aycil on 14.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class CheckboxCell: UITableViewCell, Configurable { - - typealias CellConfigartion = CheckboxConfiguration - typealias Component = CheckboxUIView - - lazy var component: CheckboxUIView = { - return CheckboxUIView( - theme: SparkTheme.shared, - text: "Checkbox", - checkedImage: DemoIconography.shared.checkmark.uiImage, - isEnabled: true, - selectionState: .selected, - alignment: .left - ) - }() - - var stackViewAlignment: UIStackView.Alignment { - return .fill - } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.isEnabled = configuration.isEnabled - self.component.theme = configuration.theme - self.component.intent = configuration.intent - self.component.alignment = configuration.alignment - self.component.text = configuration.text - self.component.selectionState = configuration.selectionState - - if let icon = configuration.icon { - self.component.checkedImage = icon - } else { - self.component.checkedImage = DemoIconography.shared.checkmark.uiImage - } - } -} diff --git a/.Demo/Classes/View/ListView/Cells/CheckboxCell/CheckboxConfiguration.swift b/.Demo/Classes/View/ListView/Cells/CheckboxCell/CheckboxConfiguration.swift deleted file mode 100644 index fbaab43be..000000000 --- a/.Demo/Classes/View/ListView/Cells/CheckboxCell/CheckboxConfiguration.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// CheckboxConfiguration.swift -// Spark -// -// Created by alican.aycil on 14.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct CheckboxConfiguration: ComponentConfiguration { - var theme: Theme - var intent: CheckboxIntent - var isEnabled: Bool - var alignment: CheckboxAlignment - var text: String - var icon: UIImage? - var selectionState: CheckboxSelectionState -} diff --git a/.Demo/Classes/View/ListView/Cells/CheckboxGroupCell/CheckboxGroupCell.swift b/.Demo/Classes/View/ListView/Cells/CheckboxGroupCell/CheckboxGroupCell.swift deleted file mode 100644 index a4b85a37f..000000000 --- a/.Demo/Classes/View/ListView/Cells/CheckboxGroupCell/CheckboxGroupCell.swift +++ /dev/null @@ -1,58 +0,0 @@ -// -// CheckboxGroupCell.swift -// SparkDemo -// -// Created by alican.aycil on 21.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class CheckboxGroupCell: UITableViewCell, Configurable { - - typealias CellConfigartion = CheckboxGroupConfiguration - typealias Component = CheckboxGroupUIView - - var stackViewAlignment: UIStackView.Alignment { - return .fill - } - - lazy var component: CheckboxGroupUIView = { - let items = [ - CheckboxGroupItemDefault(title: "Text", id: "1", selectionState: .selected, isEnabled: true) - ] - - return CheckboxGroupUIView( - checkedImage: DemoIconography.shared.checkmark.uiImage, - items: items, - alignment: .left, - theme: SparkTheme.shared, - intent: .main, - accessibilityIdentifierPrefix: "CheckboxGroup" - ) - }() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.updateItems(configuration.items) - self.component.theme = configuration.theme - self.component.intent = configuration.intent - self.component.alignment = configuration.alignment - self.component.layout = configuration.layout - - if configuration.showGroupTitle { - self.component.title = "Checkbox group title" - } else { - self.component.title = nil - } - } -} diff --git a/.Demo/Classes/View/ListView/Cells/CheckboxGroupCell/CheckboxGroupConfiguration.swift b/.Demo/Classes/View/ListView/Cells/CheckboxGroupCell/CheckboxGroupConfiguration.swift deleted file mode 100644 index 62ad286e7..000000000 --- a/.Demo/Classes/View/ListView/Cells/CheckboxGroupCell/CheckboxGroupConfiguration.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// CheckboxGroupConfiguration.swift -// SparkDemo -// -// Created by alican.aycil on 21.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct CheckboxGroupConfiguration: ComponentConfiguration { - var theme: Theme - var intent: CheckboxIntent - var alignment: CheckboxAlignment - var layout: CheckboxGroupLayout - var showGroupTitle: Bool - var items: [any CheckboxGroupItemProtocol] -} diff --git a/.Demo/Classes/View/ListView/Cells/ChipCell/ChipCell.swift b/.Demo/Classes/View/ListView/Cells/ChipCell/ChipCell.swift deleted file mode 100644 index b176faca6..000000000 --- a/.Demo/Classes/View/ListView/Cells/ChipCell/ChipCell.swift +++ /dev/null @@ -1,46 +0,0 @@ -// -// ChipCell.swift -// Spark -// -// Created by alican.aycil on 13.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class ChipCell: UITableViewCell, Configurable { - - typealias CellConfigartion = ChipConfiguration - typealias Component = ChipUIView - - lazy var component: ChipUIView = { - return ChipUIView( - theme: SparkTheme.shared, - intent: .basic, - variant: .outlined, - label: "No Title" - ) - }() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.theme = configuration.theme - self.component.intent = configuration.intent - self.component.variant = configuration.variant - self.component.alignment = configuration.alignment - self.component.isEnabled = configuration.isEnabled - self.component.isSelected = configuration.isSelected - self.component.text = configuration.title - self.component.icon = configuration.icon - self.component.action = {} - } -} diff --git a/.Demo/Classes/View/ListView/Cells/ChipCell/ChipConfiguration.swift b/.Demo/Classes/View/ListView/Cells/ChipCell/ChipConfiguration.swift deleted file mode 100644 index 1d3903ab8..000000000 --- a/.Demo/Classes/View/ListView/Cells/ChipCell/ChipConfiguration.swift +++ /dev/null @@ -1,21 +0,0 @@ -// -// ChipConfiguration.swift -// Spark -// -// Created by alican.aycil on 13.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct ChipConfiguration: ComponentConfiguration { - var theme: Theme - var intent: ChipIntent - var variant: ChipVariant - var alignment: ChipAlignment - var isEnabled: Bool - var isSelected: Bool - var title: String? - var icon: UIImage? -} diff --git a/.Demo/Classes/View/ListView/Cells/IconCell/IconCell.swift b/.Demo/Classes/View/ListView/Cells/IconCell/IconCell.swift deleted file mode 100644 index 53219596a..000000000 --- a/.Demo/Classes/View/ListView/Cells/IconCell/IconCell.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// IconCell.swift -// SparkDemo -// -// Created by alican.aycil on 14.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class IconCell: UITableViewCell, Configurable { - - typealias CellConfigartion = IconConfiguration - typealias Component = IconUIView - - lazy var component: IconUIView = { - return IconUIView( - iconImage: UIImage(systemName: "lock.circle") ?? UIImage(), - theme: SparkTheme.shared, - intent: .main, - size: .medium - ) - }() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.theme = configuration.theme - self.component.intent = configuration.intent - self.component.size = configuration.size - } -} diff --git a/.Demo/Classes/View/ListView/Cells/IconCell/IconConfiguration.swift b/.Demo/Classes/View/ListView/Cells/IconCell/IconConfiguration.swift deleted file mode 100644 index f113b5efd..000000000 --- a/.Demo/Classes/View/ListView/Cells/IconCell/IconConfiguration.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// IconConfiguration.swift -// SparkDemo -// -// Created by alican.aycil on 14.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct IconConfiguration: ComponentConfiguration { - var theme: Theme - var intent: IconIntent - var size: IconSize -} diff --git a/.Demo/Classes/View/ListView/Cells/ProgressBarIndeterminateCell/ProgressBarIndeterminateCell.swift b/.Demo/Classes/View/ListView/Cells/ProgressBarIndeterminateCell/ProgressBarIndeterminateCell.swift deleted file mode 100644 index f10e43bf3..000000000 --- a/.Demo/Classes/View/ListView/Cells/ProgressBarIndeterminateCell/ProgressBarIndeterminateCell.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// ProgressBarIndeterminateCell.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class ProgressBarIndeterminateCell: UITableViewCell, Configurable { - - typealias CellConfigartion = ProgressBarIndeterminateConfiguration - typealias Component = ProgressBarIndeterminateUIView - - lazy var component: ProgressBarIndeterminateUIView = { - return ProgressBarIndeterminateUIView( - theme: SparkTheme.shared, - intent: .main, - shape: .square - ) - }() - - var stackViewAlignment: UIStackView.Alignment { - return .fill - } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.theme = configuration.theme - self.component.intent = configuration.intent - configuration.isAnimated ? self.component.startAnimating() : self.component.stopAnimating() - } -} diff --git a/.Demo/Classes/View/ListView/Cells/ProgressBarIndeterminateCell/ProgressBarIndeterminateConfiguration.swift b/.Demo/Classes/View/ListView/Cells/ProgressBarIndeterminateCell/ProgressBarIndeterminateConfiguration.swift deleted file mode 100644 index deddf7d1f..000000000 --- a/.Demo/Classes/View/ListView/Cells/ProgressBarIndeterminateCell/ProgressBarIndeterminateConfiguration.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// ProgressBarIndeterminateConfiguration.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct ProgressBarIndeterminateConfiguration: ComponentConfiguration { - var theme: Theme - var intent: ProgressBarIntent - var isAnimated: Bool -} diff --git a/.Demo/Classes/View/ListView/Cells/ProgressBarSingleCell/ProgressBarSingleCell.swift b/.Demo/Classes/View/ListView/Cells/ProgressBarSingleCell/ProgressBarSingleCell.swift deleted file mode 100644 index 740fa1195..000000000 --- a/.Demo/Classes/View/ListView/Cells/ProgressBarSingleCell/ProgressBarSingleCell.swift +++ /dev/null @@ -1,43 +0,0 @@ -// -// ProgressBarSingleCell.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class ProgressBarSingleCell: UITableViewCell, Configurable { - - typealias CellConfigartion = ProgressBarSingleConfiguration - typealias Component = ProgressBarUIView - - lazy var component: ProgressBarUIView = { - return ProgressBarUIView( - theme: SparkTheme.shared, - intent: .main, - shape: .square - ) - }() - - var stackViewAlignment: UIStackView.Alignment { - return .fill - } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.theme = configuration.theme - self.component.intent = configuration.intent - self.component.value = configuration.value - } -} diff --git a/.Demo/Classes/View/ListView/Cells/ProgressBarSingleCell/ProgressBarSingleConfiguration.swift b/.Demo/Classes/View/ListView/Cells/ProgressBarSingleCell/ProgressBarSingleConfiguration.swift deleted file mode 100644 index c287dc305..000000000 --- a/.Demo/Classes/View/ListView/Cells/ProgressBarSingleCell/ProgressBarSingleConfiguration.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// ProgressBarSingleConfiguration.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct ProgressBarSingleConfiguration: ComponentConfiguration { - var theme: Theme - var intent: ProgressBarIntent - var value: CGFloat -} diff --git a/.Demo/Classes/View/ListView/Cells/RadioButtonCell/RadioButtonCell.swift b/.Demo/Classes/View/ListView/Cells/RadioButtonCell/RadioButtonCell.swift deleted file mode 100644 index 16a37cd2f..000000000 --- a/.Demo/Classes/View/ListView/Cells/RadioButtonCell/RadioButtonCell.swift +++ /dev/null @@ -1,48 +0,0 @@ -// -// RadioButtonCell.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class RadioButtonCell: UITableViewCell, Configurable { - - typealias CellConfigartion = RadioButtonConfiguration - typealias Component = RadioButtonUIView - - lazy var component: RadioButtonUIView = { - return RadioButtonUIView( - theme: SparkTheme.shared, - intent: .main, - id: 99, - label: NSAttributedString(string: "Sample of toggle on radio button"), - isSelected: true - ) - }() - - var stackViewAlignment: UIStackView.Alignment { - return .fill - } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.theme = configuration.theme - self.component.intent = configuration.intent - self.component.labelAlignment = configuration.alignment - self.component.isSelected = configuration.isSelected - self.component.isEnabled = configuration.isEnabled - self.component.text = configuration.text - } -} diff --git a/.Demo/Classes/View/ListView/Cells/RadioButtonCell/RadioButtonConfiguration.swift b/.Demo/Classes/View/ListView/Cells/RadioButtonCell/RadioButtonConfiguration.swift deleted file mode 100644 index 61d33e2a8..000000000 --- a/.Demo/Classes/View/ListView/Cells/RadioButtonCell/RadioButtonConfiguration.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// RadioButtonConfiguration.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct RadioButtonConfiguration: ComponentConfiguration { - var theme: Theme - var intent: RadioButtonIntent - var alignment: RadioButtonLabelAlignment - var isSelected: Bool - var isEnabled: Bool - var text: String -} diff --git a/.Demo/Classes/View/ListView/Cells/RadioButtonGroupCell/RadioButtonGroupCell.swift b/.Demo/Classes/View/ListView/Cells/RadioButtonGroupCell/RadioButtonGroupCell.swift deleted file mode 100644 index 371dd375e..000000000 --- a/.Demo/Classes/View/ListView/Cells/RadioButtonGroupCell/RadioButtonGroupCell.swift +++ /dev/null @@ -1,71 +0,0 @@ -// -// RadioButtonGroupCell.swift -// SparkDemo -// -// Created by alican.aycil on 21.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class RadioButtonGroupCell: UITableViewCell, Configurable { - - typealias CellConfigartion = RadioButtonGroupConfiguration - typealias Component = RadioButtonUIGroupView - - var attributeString: NSAttributedString { - let text: String = "Hello world" - let attributeString = NSMutableAttributedString( - string: text, - attributes: [.font: UIFont.italicSystemFont(ofSize: 18)] - ) - let attributes: [NSMutableAttributedString.Key: Any] = [ - .font: UIFont( - descriptor: UIFontDescriptor().withSymbolicTraits([.traitBold, .traitItalic]) ?? UIFontDescriptor(), - size: 18 - ), - .foregroundColor: UIColor.red - ] - attributeString.setAttributes(attributes, range: NSRange(location: 0, length: 5)) - return attributeString - } - - lazy var component: RadioButtonUIGroupView = { - let items = [ - RadioButtonUIItem.init(id: 0, label: "This is"), - RadioButtonUIItem.init(id: 1, label: "This is an example of a multi-line text which is very long and in which the user should read all the information."), - RadioButtonUIItem.init(id: 2, label: self.attributeString) - ] - return RadioButtonUIGroupView( - theme: SparkTheme.shared, - intent: .main, - selectedID: 0, - items: items, - labelAlignment: .trailing, - groupLayout: .vertical - ) - }() - - var stackViewAlignment: UIStackView.Alignment { - return .fill - } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.theme = configuration.theme - self.component.intent = configuration.intent - self.component.groupLayout = configuration.layout - self.component.isEnabled = configuration.isEnabled - self.component.selectedID = configuration.selectedID - self.component.labelAlignment = configuration.alignment - } -} diff --git a/.Demo/Classes/View/ListView/Cells/RadioButtonGroupCell/RadioButtonGroupConfiguration.swift b/.Demo/Classes/View/ListView/Cells/RadioButtonGroupCell/RadioButtonGroupConfiguration.swift deleted file mode 100644 index 2ecfbbbf7..000000000 --- a/.Demo/Classes/View/ListView/Cells/RadioButtonGroupCell/RadioButtonGroupConfiguration.swift +++ /dev/null @@ -1,20 +0,0 @@ -// -// RadioButtonGroupConfiguration.swift -// SparkDemo -// -// Created by alican.aycil on 21.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct RadioButtonGroupConfiguration: ComponentConfiguration { - var theme: Theme - var intent: RadioButtonIntent - var alignment: RadioButtonLabelAlignment - var layout: RadioButtonGroupLayout - var isEnabled: Bool - var selectedID: Int -} - diff --git a/.Demo/Classes/View/ListView/Cells/RatingDisplayCell/RatingDisplayCell.swift b/.Demo/Classes/View/ListView/Cells/RatingDisplayCell/RatingDisplayCell.swift deleted file mode 100644 index 65a68ee2f..000000000 --- a/.Demo/Classes/View/ListView/Cells/RatingDisplayCell/RatingDisplayCell.swift +++ /dev/null @@ -1,40 +0,0 @@ -// -// RatingDisplayCell.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class RatingDisplayCell: UITableViewCell, Configurable { - - typealias CellConfigartion = RatingDisplayConfiguration - typealias Component = RatingDisplayUIView - - lazy var component: RatingDisplayUIView = { - return RatingDisplayUIView( - theme: SparkTheme.shared, - intent: .main - ) - }() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.theme = configuration.theme - self.component.intent = configuration.intent - self.component.size = configuration.size - self.component.rating = configuration.rating - self.component.count = configuration.count - } -} diff --git a/.Demo/Classes/View/ListView/Cells/RatingDisplayCell/RatingDisplayConfiguration.swift b/.Demo/Classes/View/ListView/Cells/RatingDisplayCell/RatingDisplayConfiguration.swift deleted file mode 100644 index da8878d01..000000000 --- a/.Demo/Classes/View/ListView/Cells/RatingDisplayCell/RatingDisplayConfiguration.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// RatingDisplayConfiguration.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct RatingDisplayConfiguration: ComponentConfiguration { - var theme: Theme - var intent: RatingIntent - var size: RatingDisplaySize - var rating: CGFloat - var count: RatingStarsCount -} diff --git a/.Demo/Classes/View/ListView/Cells/RatingInputCell/RatingInputCell.swift b/.Demo/Classes/View/ListView/Cells/RatingInputCell/RatingInputCell.swift deleted file mode 100644 index ec3c53d25..000000000 --- a/.Demo/Classes/View/ListView/Cells/RatingInputCell/RatingInputCell.swift +++ /dev/null @@ -1,39 +0,0 @@ -// -// RatingInputCell.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class RatingInputCell: UITableViewCell, Configurable { - - typealias CellConfigartion = RatingInputConfiguration - typealias Component = RatingInputUIView - - lazy var component: RatingInputUIView = { - return RatingInputUIView( - theme: SparkTheme.shared, - intent: .main - ) - }() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.theme = configuration.theme - self.component.intent = configuration.intent - self.component.rating = configuration.rating - self.component.isEnabled = configuration.isEnabled - } -} diff --git a/.Demo/Classes/View/ListView/Cells/RatingInputCell/RatingInputConfiguration.swift b/.Demo/Classes/View/ListView/Cells/RatingInputCell/RatingInputConfiguration.swift deleted file mode 100644 index 45a3fe7a1..000000000 --- a/.Demo/Classes/View/ListView/Cells/RatingInputCell/RatingInputConfiguration.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// RatingInputConfiguration.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct RatingInputConfiguration: ComponentConfiguration { - var theme: Theme - var intent: RatingIntent - var rating: CGFloat - var isEnabled: Bool -} diff --git a/.Demo/Classes/View/ListView/Cells/SpinnerCell/SpinnerCell.swift b/.Demo/Classes/View/ListView/Cells/SpinnerCell/SpinnerCell.swift deleted file mode 100644 index f3dba444c..000000000 --- a/.Demo/Classes/View/ListView/Cells/SpinnerCell/SpinnerCell.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// SpinnerCell.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class SpinnerCell: UITableViewCell, Configurable { - - typealias CellConfigartion = SpinnerConfiguration - typealias Component = SpinnerUIView - - lazy var component: SpinnerUIView = { - return SpinnerUIView( - theme: SparkTheme.shared - ) - }() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.theme = configuration.theme - self.component.intent = configuration.intent - self.component.spinnerSize = configuration.size - } -} diff --git a/.Demo/Classes/View/ListView/Cells/SpinnerCell/SpinnerConfiguration.swift b/.Demo/Classes/View/ListView/Cells/SpinnerCell/SpinnerConfiguration.swift deleted file mode 100644 index 4fe24625d..000000000 --- a/.Demo/Classes/View/ListView/Cells/SpinnerCell/SpinnerConfiguration.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// SpinnerConfiguration.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct SpinnerConfiguration: ComponentConfiguration { - var theme: Theme - var intent: SpinnerIntent - var size: SpinnerSize -} diff --git a/.Demo/Classes/View/ListView/Cells/StarCell/StarCell.swift b/.Demo/Classes/View/ListView/Cells/StarCell/StarCell.swift deleted file mode 100644 index ac40a9137..000000000 --- a/.Demo/Classes/View/ListView/Cells/StarCell/StarCell.swift +++ /dev/null @@ -1,53 +0,0 @@ -// -// StarCell.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class StarCell: UITableViewCell, Configurable { - - typealias CellConfigartion = StarCellConfiguration - typealias Component = StarUIView - - lazy var component: StarUIView = { - let configuration = StarConfiguration( - numberOfVertices: 5, - vertexSize: CGFloat(0.65), - cornerRadiusSize: CGFloat(0.15) - ) - return StarUIView( - rating: CGFloat(0.5), - fillMode: StarFillMode.half, - lineWidth: 2, - borderColor: UIColor.blue, - fillColor: UIColor.lightGray, - configuration: configuration - ) - }() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - - NSLayoutConstraint.activate([ - self.component.widthAnchor.constraint(equalToConstant: 50), - self.component.heightAnchor.constraint(equalToConstant: 50) - ]) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.fillColor = configuration.fillColor - self.component.borderColor = configuration.borderColor - self.component.numberOfVertices = configuration.numberOfVertices - self.component.fillMode = configuration.fillMode - } -} diff --git a/.Demo/Classes/View/ListView/Cells/StarCell/StarConfiguration.swift b/.Demo/Classes/View/ListView/Cells/StarCell/StarConfiguration.swift deleted file mode 100644 index e4ca090a0..000000000 --- a/.Demo/Classes/View/ListView/Cells/StarCell/StarConfiguration.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// StarConfiguration.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct StarCellConfiguration: ComponentConfiguration { - var theme: Theme - var borderColor: UIColor - var fillColor: UIColor - var numberOfVertices: Int - var fillMode: StarFillMode -} diff --git a/.Demo/Classes/View/ListView/Cells/SwitchButtonCell/SwitchButtonCell.swift b/.Demo/Classes/View/ListView/Cells/SwitchButtonCell/SwitchButtonCell.swift deleted file mode 100644 index d244a83dc..000000000 --- a/.Demo/Classes/View/ListView/Cells/SwitchButtonCell/SwitchButtonCell.swift +++ /dev/null @@ -1,76 +0,0 @@ -// -// SwitchCell.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class SwitchCell: UITableViewCell, Configurable { - - typealias CellConfigartion = SwitchConfiguration - typealias Component = SwitchUIView - - lazy var component: SwitchUIView = { - return SwitchUIView( - theme: SparkTheme.shared, - isOn: true, - alignment: .left, - intent: .main, - isEnabled: true, - images: .init( - on: UIImage(named: "check") ?? UIImage(), - off: UIImage(named: "close") ?? UIImage() - ), - text: "Text" - ) - }() - - var attributeString: NSAttributedString { - let text: String = "Hello world" - let attributeString = NSMutableAttributedString( - string: text, - attributes: [.font: UIFont.italicSystemFont(ofSize: 18)] - ) - let attributes: [NSMutableAttributedString.Key: Any] = [ - .font: UIFont( - descriptor: UIFontDescriptor().withSymbolicTraits([.traitBold, .traitItalic]) ?? UIFontDescriptor(), - size: 18 - ), - .foregroundColor: UIColor.red - ] - attributeString.setAttributes(attributes, range: NSRange(location: 0, length: 5)) - return attributeString - } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.theme = configuration.theme - self.component.intent = configuration.intent - self.component.alignment = configuration.alignment - self.component.isOn = configuration.isOn - self.component.isEnabled = configuration.isEnabled - - switch configuration.textContent { - case .attributedText: - self.component.attributedText = self.attributeString - case .multilineText: - self.component.text = "This is an example of a multi-line text which is very long and in which the user should read all the information." - case .text: - self.component.text = "Text" - case .none: - self.component.text = nil - } - } -} diff --git a/.Demo/Classes/View/ListView/Cells/SwitchButtonCell/SwitchButtonConfiguration.swift b/.Demo/Classes/View/ListView/Cells/SwitchButtonCell/SwitchButtonConfiguration.swift deleted file mode 100644 index 2344a45a9..000000000 --- a/.Demo/Classes/View/ListView/Cells/SwitchButtonCell/SwitchButtonConfiguration.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// SwitchConfiguration.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct SwitchConfiguration: ComponentConfiguration { - var theme: Theme - var intent: SwitchIntent - var alignment: SwitchAlignment - var textContent: SwitchTextContentDefault - var isOn: Bool - var isEnabled: Bool -} diff --git a/.Demo/Classes/View/ListView/Cells/TabCell/TabCell.swift b/.Demo/Classes/View/ListView/Cells/TabCell/TabCell.swift deleted file mode 100644 index 9a73259ab..000000000 --- a/.Demo/Classes/View/ListView/Cells/TabCell/TabCell.swift +++ /dev/null @@ -1,60 +0,0 @@ -// -// TabCell.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class TabCell: UITableViewCell, Configurable { - - typealias CellConfigartion = TabConfiguration - typealias Component = TabUIView - - lazy var component: TabUIView = { - return TabUIView( - theme: SparkTheme.shared, - intent: .main, - tabSize: .md, - content: [] - ) - }() - - var badge: BadgeUIView { - let badge = BadgeUIView( - theme: SparkTheme.shared, - intent: .danger, - value: 99 - ) - badge.translatesAutoresizingMaskIntoConstraints = false - badge.isBorderVisible = false - badge.size = .medium - return badge - } - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.theme = configuration.theme - self.component.intent = configuration.intent - self.component.tabSize = configuration.size - self.component.apportionsSegmentWidthsByContent = !configuration.isEqualWidth - self.component.setSegments(withContent: configuration.contents) - - if configuration.showBadge { - self.component.setBadge(self.badge, forSegementAt: 1) - } else { - self.component.setBadge(nil, forSegementAt: 1) - } - } -} diff --git a/.Demo/Classes/View/ListView/Cells/TabCell/TabConfiguration.swift b/.Demo/Classes/View/ListView/Cells/TabCell/TabConfiguration.swift deleted file mode 100644 index ae32a1f27..000000000 --- a/.Demo/Classes/View/ListView/Cells/TabCell/TabConfiguration.swift +++ /dev/null @@ -1,19 +0,0 @@ -// -// TabConfiguration.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct TabConfiguration: ComponentConfiguration { - var theme: Theme - var intent: TabIntent - var size: TabSize - var contents: [TabUIItemContent] - var showBadge: Bool - var isEqualWidth: Bool -} diff --git a/.Demo/Classes/View/ListView/Cells/TagCell/TagCell.swift b/.Demo/Classes/View/ListView/Cells/TagCell/TagCell.swift deleted file mode 100644 index 2b8b92bb7..000000000 --- a/.Demo/Classes/View/ListView/Cells/TagCell/TagCell.swift +++ /dev/null @@ -1,57 +0,0 @@ -// -// TagCell.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -final class TagCell: UITableViewCell, Configurable { - - typealias CellConfigartion = TagConfiguration - typealias Component = TagUIView - - lazy var component: TagUIView = { - return TagUIView( - theme: SparkTheme.shared, - intent: .main, - variant: .filled, - text: "Tag" - ) - }() - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - self.setupView() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func configureCell(configuration: CellConfigartion) { - self.component.theme = configuration.theme - self.component.intent = configuration.intent - self.component.variant = configuration.variant - - switch configuration.content { - case .icon: - self.component.iconImage = UIImage(systemName: "pencil.tip.crop.circle") - self.component.text = nil - case .text, .longText: - self.component.text = "Tag 1" - self.component.iconImage = nil - case .attributedText, .longAttributedText: - self.component.attributedText = NSAttributedString(string: "Tag 3") - case .iconAndText, .iconAndLongText: - self.component.text = "Tag 2" - self.component.iconImage = UIImage(systemName: "pencil.tip.crop.circle") - case .iconAndAttributedText, .iconAndLongAttributedText: - self.component.attributedText = NSAttributedString(string: "Tag 4") - self.component.iconImage = UIImage(systemName: "pencil.tip.crop.circle") - } - } -} diff --git a/.Demo/Classes/View/ListView/Cells/TagCell/TagConfiguration.swift b/.Demo/Classes/View/ListView/Cells/TagCell/TagConfiguration.swift deleted file mode 100644 index 9da190cf0..000000000 --- a/.Demo/Classes/View/ListView/Cells/TagCell/TagConfiguration.swift +++ /dev/null @@ -1,17 +0,0 @@ -// -// TagConfiguration.swift -// SparkDemo -// -// Created by alican.aycil on 19.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SparkCore - -struct TagConfiguration: ComponentConfiguration { - var theme: Theme - var intent: TagIntent - var variant: TagVariant - var content: TagContent -} diff --git a/.Demo/Classes/View/ListView/Controllers/RadioCheckboxUIViewController.swift b/.Demo/Classes/View/ListView/Controllers/RadioCheckboxUIViewController.swift deleted file mode 100644 index 95a45fbd5..000000000 --- a/.Demo/Classes/View/ListView/Controllers/RadioCheckboxUIViewController.swift +++ /dev/null @@ -1,116 +0,0 @@ -// -// RadioCheckboxUIViewController.swift -// SparkDemo -// -// Created by alican.aycil on 22.03.24. -// Copyright © 2024 Adevinta. All rights reserved. -// - -import UIKit -import Combine -import SparkCore -@_spi(SI_SPI) import SparkCommon - -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/.Demo/Classes/View/ListView/Controllers/RadioCheckboxView.swift b/.Demo/Classes/View/ListView/Controllers/RadioCheckboxView.swift deleted file mode 100644 index e1ca9ba94..000000000 --- a/.Demo/Classes/View/ListView/Controllers/RadioCheckboxView.swift +++ /dev/null @@ -1,66 +0,0 @@ -// -// RadioCheckboxView.swift -// SparkDemo -// -// Created by alican.aycil on 22.03.24. -// Copyright © 2024 Adevinta. All rights reserved. -// - -@_spi(SI_SPI) import SparkCommon -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/.Demo/Classes/View/ListView/ListComponentsViewController.swift b/.Demo/Classes/View/ListView/ListComponentsViewController.swift deleted file mode 100644 index b8d6c232d..000000000 --- a/.Demo/Classes/View/ListView/ListComponentsViewController.swift +++ /dev/null @@ -1,160 +0,0 @@ -// -// ListComponentsViewController.swift -// Spark -// -// Created by alican.aycil on 13.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SwiftUI - -final class ListComponentsViewController: UICollectionViewController { - - // MARK: - Typealias - fileprivate typealias DataSource = UICollectionViewDiffableDataSource - fileprivate typealias SnapShot = NSDiffableDataSourceSnapshot - - // MARK: - Properties - private let reuseIdentifier = "defaultCell" - - var uiComponentAllCases: [UIComponent] { - var all = UIComponent.allCases - all.insert(.checkboxGroup, at: 3) - all.insert(.radioButtonGroup, at: 9) - return all - } - - private lazy var collectionViewDataSource: DataSource = { - /// CollectionView cell registration - let cellRegistration = UICollectionView.CellRegistration { - (cell: UICollectionViewListCell, indexPath: IndexPath, title: String) in - var contentConfiguration = cell.defaultContentConfiguration() - contentConfiguration.text = title - cell.contentConfiguration = contentConfiguration - cell.accessories = [.disclosureIndicator(options: .init(tintColor: .systemGray3))] - } - /// CollectionView diffable data source - return DataSource(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in - return collectionView.dequeueConfiguredReusableCell( - using: cellRegistration, for: indexPath, item: itemIdentifier) - } - }() - - // MARK: - ViewDidLoad - override func viewDidLoad() { - super.viewDidLoad() - navigationController?.navigationBar.prefersLargeTitles = true - navigationItem.title = "List" - setupData() - } - - private func setupData() { - /// CollectionView append sections and items - var snapShot = SnapShot() - snapShot.appendSections([.list, .random]) - snapShot.appendItems(uiComponentAllCases.map{ $0.rawValue }, toSection: .list) - snapShot.appendItems(Row.allCases.map{ $0.name }, toSection: .random) - collectionViewDataSource.apply(snapShot) - } -} - -// MARK: - CollectionViewLayout -extension ListComponentsViewController { - - static func makeLayout() -> UICollectionViewCompositionalLayout { - let listConfiguration = UICollectionLayoutListConfiguration(appearance: .insetGrouped) - return UICollectionViewCompositionalLayout.list(using: listConfiguration) - } -} - -// MARK: - CollectionViewDelegates -extension ListComponentsViewController { - - override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - - var viewController: UIViewController! - - 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: - return ListViewController() - case .button: - return ListViewController() - case .checkbox: - return ListViewController() - case .checkboxGroup: - return ListViewController() - case .chip: - return ListViewController() - case .icon: - return ListViewController() - case .progressBarIndeterminate: - return ListViewController() - case .progressBarSingle: - return ListViewController() - case .radioButton: - return ListViewController() - case .radioButtonGroup: - return ListViewController() - case .ratingDisplay: - return ListViewController() - case .ratingInput: - return ListViewController() - case .spinner: - return ListViewController() - case .star: - return ListViewController() - case .switch: - return ListViewController() - case .tab: - return ListViewController() - case .tag: - return ListViewController() - default: - 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() - } - } -} - -// MARK: - Enums -private extension ListComponentsViewController { - - enum Section: CaseIterable { - case list - case random - } - - enum Row: CaseIterable { - case radioCheckboxSwiftui - case radioCheckboxUikit - } -} - -private extension UIComponent { - static let checkboxGroup = UIComponent(rawValue: "Checkbox Group") - static let radioButtonGroup = UIComponent(rawValue: "Radio Button Group") -} diff --git a/.Demo/Classes/View/ListView/ListView+Protocols.swift b/.Demo/Classes/View/ListView/ListView+Protocols.swift deleted file mode 100644 index 6362af27b..000000000 --- a/.Demo/Classes/View/ListView/ListView+Protocols.swift +++ /dev/null @@ -1,56 +0,0 @@ -// -// Configurable.swift -// SparkDemo -// -// Created by alican.aycil on 30.11.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import SparkCore -import UIKit - -protocol ComponentConfiguration { - var theme: Theme { get set } -} - -protocol Configurable: AnyObject { - associatedtype CellConfigartion: ComponentConfiguration - associatedtype Component: UIView - - static var reuseIdentifier: String { get } - var component: Component { get set } - var stackViewAlignment: UIStackView.Alignment { get } - - func configureCell(configuration: CellConfigartion) - func setupView() -} - -extension Configurable where Self: UITableViewCell { - - static var reuseIdentifier: String { - return String(describing: Self.self) - } - - var stackViewAlignment: UIStackView.Alignment { - return .leading - } - - func setupView() { - let stackView = UIStackView(arrangedSubviews: [self.component]) - stackView.axis = .vertical - stackView.alignment = self.stackViewAlignment - stackView.translatesAutoresizingMaskIntoConstraints = false - - self.contentView.addSubview(stackView) - - let bottomAnchor: NSLayoutConstraint = stackView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor, constant: -16) - bottomAnchor.priority = .init(999) - - NSLayoutConstraint.activate([ - stackView.topAnchor.constraint(equalTo: self.contentView.topAnchor, constant: 16), - stackView.leadingAnchor.constraint(equalTo: self.contentView.leadingAnchor, constant: 16), - stackView.trailingAnchor.constraint(equalTo: self.contentView.trailingAnchor, constant: -16), - bottomAnchor - ]) - } -} diff --git a/.Demo/Classes/View/ListView/ListViewController.swift b/.Demo/Classes/View/ListView/ListViewController.swift deleted file mode 100644 index dfa0f9094..000000000 --- a/.Demo/Classes/View/ListView/ListViewController.swift +++ /dev/null @@ -1,95 +0,0 @@ -// -// ListViewController.swift -// SparkDemo -// -// Created by alican.aycil on 30.11.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import Combine - -final class ListViewController: UITableViewController { - - private var dataSource = ListViewDataSource() - private var listProtocol = ListViewDelegate() - - override func viewDidLoad() { - super.viewDidLoad() - navigationItem.title = Cell.reuseIdentifier - navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Add Item", style: .plain, target: self, action: #selector(self.addNewComponentToList)) - - self.setupTableView() - } - - private func setupTableView() { - self.tableView.dataSource = self.dataSource - self.tableView.delegate = self.listProtocol - self.tableView.allowsSelection = false - self.registerCells() - } - - private func registerCells() { - switch Cell.self { - - case is BadgeCell.Type: - self.tableView.register(BadgeCell.self, forCellReuseIdentifier: BadgeCell.reuseIdentifier) - - case is ButtonCell.Type: - self.tableView.register(ButtonCell.self, forCellReuseIdentifier: ButtonCell.reuseIdentifier) - - case is CheckboxCell.Type: - self.tableView.register(CheckboxCell.self, forCellReuseIdentifier: CheckboxCell.reuseIdentifier) - - case is CheckboxGroupCell.Type: - self.tableView.register(CheckboxGroupCell.self, forCellReuseIdentifier: CheckboxGroupCell.reuseIdentifier) - - case is ChipCell.Type: - self.tableView.register(ChipCell.self, forCellReuseIdentifier: ChipCell.reuseIdentifier) - - case is IconCell.Type: - self.tableView.register(IconCell.self, forCellReuseIdentifier: IconCell.reuseIdentifier) - - case is ProgressBarIndeterminateCell.Type: - self.tableView.register(ProgressBarIndeterminateCell.self, forCellReuseIdentifier: ProgressBarIndeterminateCell.reuseIdentifier) - - case is ProgressBarSingleCell.Type: - self.tableView.register(ProgressBarSingleCell.self, forCellReuseIdentifier: ProgressBarSingleCell.reuseIdentifier) - - case is RadioButtonCell.Type: - self.tableView.register(RadioButtonCell.self, forCellReuseIdentifier: RadioButtonCell.reuseIdentifier) - - case is RadioButtonGroupCell.Type: - self.tableView.register(RadioButtonGroupCell.self, forCellReuseIdentifier: RadioButtonGroupCell.reuseIdentifier) - - case is RatingDisplayCell.Type: - self.tableView.register(RatingDisplayCell.self, forCellReuseIdentifier: RatingDisplayCell.reuseIdentifier) - - case is RatingInputCell.Type: - self.tableView.register(RatingInputCell.self, forCellReuseIdentifier: RatingInputCell.reuseIdentifier) - - case is SpinnerCell.Type: - self.tableView.register(SpinnerCell.self, forCellReuseIdentifier: SpinnerCell.reuseIdentifier) - - case is StarCell.Type: - self.tableView.register(StarCell.self, forCellReuseIdentifier: StarCell.reuseIdentifier) - - case is SwitchCell.Type: - self.tableView.register(SwitchCell.self, forCellReuseIdentifier: SwitchCell.reuseIdentifier) - - case is TabCell.Type: - self.tableView.register(TabCell.self, forCellReuseIdentifier: TabCell.reuseIdentifier) - - case is TagCell.Type: - self.tableView.register(TagCell.self, forCellReuseIdentifier: TagCell.reuseIdentifier) - - default: - break - } - } - - @objc func addNewComponentToList() { - self.dataSource.setupData(newItem: true) - self.tableView.reloadData() - } -} diff --git a/.Demo/Classes/View/ListView/ListViewDatasource.swift b/.Demo/Classes/View/ListView/ListViewDatasource.swift deleted file mode 100644 index fdb264124..000000000 --- a/.Demo/Classes/View/ListView/ListViewDatasource.swift +++ /dev/null @@ -1,366 +0,0 @@ -// -// ListViewDatasource.swift -// SparkDemo -// -// Created by alican.aycil on 30.11.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import Combine -import UIKit -import SparkCore - -final class ListViewDataSource: NSObject, UITableViewDataSource { - - var configurations: [ComponentConfiguration] = [] - - override init() { - super.init() - self.setupData() - } - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - self.configurations.count - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - - let configuration = configurations[indexPath.row] - switch configuration { - - /// Badge - case let badgeConfiguration as BadgeConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: BadgeCell.reuseIdentifier, for: indexPath) as? BadgeCell { - cell.configureCell(configuration: badgeConfiguration) - return cell - } - return UITableViewCell() - - /// Button - case let buttonConfiguration as ButtonConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: ButtonCell.reuseIdentifier, for: indexPath) as? ButtonCell { - cell.configureCell(configuration: buttonConfiguration) - return cell - } - return UITableViewCell() - - /// Checkbox - case let checkboxConfiguration as CheckboxConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: CheckboxCell.reuseIdentifier, for: indexPath) as? CheckboxCell { - cell.configureCell(configuration: checkboxConfiguration) - return cell - } - return UITableViewCell() - - /// Checkbox Group - case let checkboxGroupConfiguration as CheckboxGroupConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: CheckboxGroupCell.reuseIdentifier, for: indexPath) as? CheckboxGroupCell { - cell.configureCell(configuration: checkboxGroupConfiguration) - return cell - } - return UITableViewCell() - - /// Chip - case let chipConfiguration as ChipConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: ChipCell.reuseIdentifier, for: indexPath) as? ChipCell { - cell.configureCell(configuration: chipConfiguration) - return cell - } - return UITableViewCell() - - /// Icon - case let iconConfiguration as IconConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: IconCell.reuseIdentifier, for: indexPath) as? IconCell { - cell.configureCell(configuration: iconConfiguration) - return cell - } - return UITableViewCell() - - /// Progress Bar Indeterminate - case let progressBarIndeterminateConfiguration as ProgressBarIndeterminateConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: ProgressBarIndeterminateCell.reuseIdentifier, for: indexPath) as? ProgressBarIndeterminateCell { - cell.configureCell(configuration: progressBarIndeterminateConfiguration) - return cell - } - return UITableViewCell() - - /// Progress Bar Single - case let progressBarSingleConfiguration as ProgressBarSingleConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: ProgressBarSingleCell.reuseIdentifier, for: indexPath) as? ProgressBarSingleCell { - cell.configureCell(configuration: progressBarSingleConfiguration) - return cell - } - return UITableViewCell() - - /// Radio Button - case let radioButtonConfiguration as RadioButtonConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: RadioButtonCell.reuseIdentifier, for: indexPath) as? RadioButtonCell { - cell.configureCell(configuration: radioButtonConfiguration) - return cell - } - return UITableViewCell() - - /// Radio Button Group - case let radioButtonGroupConfiguration as RadioButtonGroupConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: RadioButtonGroupCell.reuseIdentifier, for: indexPath) as? RadioButtonGroupCell { - cell.configureCell(configuration: radioButtonGroupConfiguration) - return cell - } - return UITableViewCell() - - /// Rating Display - case let ratingDisplayConfiguration as RatingDisplayConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: RatingDisplayCell.reuseIdentifier, for: indexPath) as? RatingDisplayCell { - cell.configureCell(configuration: ratingDisplayConfiguration) - return cell - } - return UITableViewCell() - - /// Rating Input - case let ratingInputConfiguration as RatingInputConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: RatingInputCell.reuseIdentifier, for: indexPath) as? RatingInputCell { - cell.configureCell(configuration: ratingInputConfiguration) - return cell - } - return UITableViewCell() - - /// Spinner - case let spinnerConfiguration as SpinnerConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: SpinnerCell.reuseIdentifier, for: indexPath) as? SpinnerCell { - cell.configureCell(configuration: spinnerConfiguration) - return cell - } - return UITableViewCell() - - /// Star - case let starConfiguration as StarCellConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: StarCell.reuseIdentifier, for: indexPath) as? StarCell { - cell.configureCell(configuration: starConfiguration) - return cell - } - return UITableViewCell() - - /// Switch Button - case let switchConfiguration as SwitchConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: SwitchCell.reuseIdentifier, for: indexPath) as? SwitchCell { - cell.configureCell(configuration: switchConfiguration) - return cell - } - return UITableViewCell() - - /// Tab - case let tabConfiguration as TabConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: TabCell.reuseIdentifier, for: indexPath) as? TabCell { - cell.configureCell(configuration: tabConfiguration) - return cell - } - return UITableViewCell() - - /// Tag - case let tagConfiguration as TagConfiguration: - if let cell = tableView.dequeueReusableCell(withIdentifier: TagCell.reuseIdentifier, for: indexPath) as? TagCell { - cell.configureCell(configuration: tagConfiguration) - return cell - } - return UITableViewCell() - - default: - return UITableViewCell() - } - } -} - -extension ListViewDataSource { - - func setupData(newItem: Bool = false) { - - var data: [ComponentConfiguration]! - switch Configuration.self { - case is BadgeConfiguration.Type: - data = self.createBadgeConfigurations() - - case is ButtonConfiguration.Type: - data = self.createButtonConfigurations() - - case is CheckboxConfiguration.Type: - data = self.createCheckboxConfigurations() - - case is CheckboxGroupConfiguration.Type: - data = self.createCheckboxGroupConfigurations() - - case is ChipConfiguration.Type: - data = self.createChipConfigurations() - - case is IconConfiguration.Type: - data = self.createIconConfigurations() - - case is ProgressBarIndeterminateConfiguration.Type: - data = self.createProgressBarIndeterminateConfigurations() - - case is ProgressBarSingleConfiguration.Type: - data = self.createProgressBarSingleConfigurations() - - case is RadioButtonConfiguration.Type: - data = self.createRadioButtonConfigurations() - - case is RadioButtonGroupConfiguration.Type: - data = self.createRadioButtonGroupConfigurations() - - case is RatingDisplayConfiguration.Type: - data = self.createRatingDisplayConfigurations() - - case is RatingInputConfiguration.Type: - data = self.createRatingInputConfigurations() - - case is SpinnerConfiguration.Type: - data = self.createSpinnerConfigurations() - - case is StarCellConfiguration.Type: - data = self.createStarConfigurations() - - case is SwitchConfiguration.Type: - data = self.createSwitchConfigurations() - - case is TabConfiguration.Type: - data = self.createTabConfigurations() - - case is TagConfiguration.Type: - data = self.createTagConfigurations() - - default: - break - } - - let randomItem = [data.randomElement() ?? data[0]] - self.configurations += newItem ? randomItem : data - } - - /// Badge - func createBadgeConfigurations() -> [BadgeConfiguration] { - [BadgeConfiguration(theme: SparkTheme.shared, intent: .main, size: .medium, value: 99, format: .default), - BadgeConfiguration(theme: SparkTheme.shared, intent: .basic, size: .small, value: 123456, format: .default), - BadgeConfiguration(theme: SparkTheme.shared, intent: .success, size: .medium, value: 99, format: .custom(formatter: BadgePreviewFormatter()))] - } - - /// Button - func createButtonConfigurations() -> [ButtonConfiguration] { - [ButtonConfiguration(theme: SparkTheme.shared, intent: .main, variant: .filled, size: .medium, shape: .rounded, alignment: .leadingImage, content: .text, isEnabled: false), - ButtonConfiguration(theme: SparkTheme.shared, intent: .basic, variant: .outlined, size: .large, shape: .square, alignment: .trailingImage, content: .imageAndText, isEnabled: true), - ButtonConfiguration(theme: SparkTheme.shared, intent: .success, variant: .ghost, size: .small, shape: .pill, alignment: .leadingImage, content: .attributedText, isEnabled: true) - ] - } - - /// Checkbox - func createCheckboxConfigurations() -> [CheckboxConfiguration] { - [CheckboxConfiguration(theme: SparkTheme.shared, intent: .main, isEnabled: true, alignment: .left, text: "Hello World", selectionState: .indeterminate), - CheckboxConfiguration(theme: SparkTheme.shared, intent: .basic, isEnabled: true, alignment: .right, text: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. 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.", selectionState: .unselected), - CheckboxConfiguration(theme: SparkTheme.shared, intent: .success, isEnabled: false, alignment: .left, text: "Hello World", icon: DemoIconography.shared.close.uiImage, selectionState: .selected) - ] - } - - /// Checkbox Group - func createCheckboxGroupConfigurations() -> [CheckboxGroupConfiguration] { - [CheckboxGroupConfiguration(theme: SparkTheme.shared, intent: .main, alignment: .left, layout: .vertical, showGroupTitle: false, items: [CheckboxGroupItemDefault(title: "Text", id: "1", selectionState: .selected, isEnabled: true), CheckboxGroupItemDefault(title: "Text 2", id: "2", selectionState: .unselected, isEnabled: true)]), - CheckboxGroupConfiguration(theme: SparkTheme.shared, intent: .support, alignment: .left, layout: .horizontal, showGroupTitle: false, items: [CheckboxGroupItemDefault(title: "Text", id: "1", selectionState: .selected, isEnabled: true), CheckboxGroupItemDefault(title: "Lorem Ipsum is simply dummy text of the printing and typesetting industry. 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: "2", selectionState: .indeterminate, isEnabled: true), CheckboxGroupItemDefault(title: "Hello World", id: "3", selectionState: .unselected, isEnabled: true)]), - CheckboxGroupConfiguration(theme: SparkTheme.shared, intent: .info, alignment: .right, layout: .vertical, showGroupTitle: true, items: [CheckboxGroupItemDefault(title: "Text", id: "1", selectionState: .selected, isEnabled: false), CheckboxGroupItemDefault(title: "Text 2", id: "2", selectionState: .unselected, isEnabled: true)])] - } - - /// Chip - func createChipConfigurations() -> [ChipConfiguration] { - [ - ChipConfiguration(theme: SparkTheme.shared, intent: .main, variant: .dashed, alignment: .leadingIcon, isEnabled: true, isSelected: false, title: "Main", icon: UIImage(systemName: "calendar")), - ChipConfiguration(theme: SparkTheme.shared, intent: .basic, variant: .outlined, alignment: .leadingIcon, isEnabled: true, isSelected: false, title: "Basic Enabled", icon: nil), - ChipConfiguration(theme: SparkTheme.shared, intent: .basic, variant: .outlined, alignment: .leadingIcon, isEnabled: true, isSelected: true, title: "Basic Enabled Selected", icon: nil), - ChipConfiguration(theme: SparkTheme.shared, intent: .basic, variant: .outlined, alignment: .trailingIcon, isEnabled: false, isSelected: false, title: "Basic Disabled", icon: UIImage(systemName: "arrowshape.left") ), - ChipConfiguration(theme: SparkTheme.shared, intent: .success, variant: .tinted, alignment: .leadingIcon, isEnabled: true, isSelected: false, title: "Success", icon: nil), - ChipConfiguration(theme: SparkTheme.shared, intent: .success, variant: .tinted, alignment: .leadingIcon, isEnabled: true, isSelected: true, title: "Success Selected", icon: nil) - ] - } - - /// Icon - func createIconConfigurations() -> [IconConfiguration] { - [IconConfiguration(theme: SparkTheme.shared, intent: .main, size: .extraLarge), - IconConfiguration(theme: SparkTheme.shared, intent: .basic, size: .small), - IconConfiguration(theme: SparkTheme.shared, intent: .success, size: .medium)] - } - - /// Progress Bar Indeterminate - func createProgressBarIndeterminateConfigurations() -> [ProgressBarIndeterminateConfiguration] { - [ProgressBarIndeterminateConfiguration(theme: SparkTheme.shared, intent: .main, isAnimated: true), - ProgressBarIndeterminateConfiguration(theme: SparkTheme.shared, intent: .basic, isAnimated: false), - ProgressBarIndeterminateConfiguration(theme: SparkTheme.shared, intent: .success, isAnimated: true)] - } - - /// Progress Bar Single - func createProgressBarSingleConfigurations() -> [ProgressBarSingleConfiguration] { - [ProgressBarSingleConfiguration(theme: SparkTheme.shared, intent: .main, value: 0.5), - ProgressBarSingleConfiguration(theme: SparkTheme.shared, intent: .basic, value: 0.75), - ProgressBarSingleConfiguration(theme: SparkTheme.shared, intent: .success, value: 1.0)] - } - - /// Radio Button - func createRadioButtonConfigurations() -> [RadioButtonConfiguration] { - [RadioButtonConfiguration(theme: SparkTheme.shared, intent: .main, alignment: .trailing, isSelected: true, isEnabled: true, text: "Sample of toggle on radio button"), - RadioButtonConfiguration(theme: SparkTheme.shared, intent: .basic, alignment: .leading, isSelected: false, isEnabled: true, text: "Hello world"), - RadioButtonConfiguration(theme: SparkTheme.shared, intent: .success, alignment: .trailing, isSelected: true, isEnabled: false, text: "This is an example of a multi-line text which is very long and in which the user should read all the information.")] - } - - /// Radio Button Group - func createRadioButtonGroupConfigurations() -> [RadioButtonGroupConfiguration] { - [RadioButtonGroupConfiguration(theme: SparkTheme.shared, intent: .main, alignment: .trailing, layout: .vertical, isEnabled: true, selectedID: 0), - RadioButtonGroupConfiguration(theme: SparkTheme.shared, intent: .basic, alignment: .trailing, layout: .vertical, isEnabled: true, selectedID: 1), - RadioButtonGroupConfiguration(theme: SparkTheme.shared, intent: .success, alignment: .leading, layout: .vertical, isEnabled: false, selectedID: 2)] - } - - /// Rating Display - func createRatingDisplayConfigurations() -> [RatingDisplayConfiguration] { - [RatingDisplayConfiguration(theme: SparkTheme.shared, intent: .main, size: .medium, rating: 3.0, count: .five), - RatingDisplayConfiguration(theme: SparkTheme.shared, intent: .main, size: .medium, rating: 0.5, count: .one), - RatingDisplayConfiguration(theme: SparkTheme.shared, intent: .main, size: .small, rating: 4.0, count: .five)] - } - - /// Rating Input - func createRatingInputConfigurations() -> [RatingInputConfiguration] { - [RatingInputConfiguration(theme: SparkTheme.shared, intent: .main, rating: 0, isEnabled: true), - RatingInputConfiguration(theme: SparkTheme.shared, intent: .main, rating: 3.0, isEnabled: true), - RatingInputConfiguration(theme: SparkTheme.shared, intent: .main, rating: 1.5, isEnabled: false)] - } - - /// Spinner - func createSpinnerConfigurations() -> [SpinnerConfiguration] { - [SpinnerConfiguration(theme: SparkTheme.shared, intent: .main, size: .medium), - SpinnerConfiguration(theme: SparkTheme.shared, intent: .basic, size: .small), - SpinnerConfiguration(theme: SparkTheme.shared, intent: .success, size: .medium)] - } - - /// Star - func createStarConfigurations() -> [StarCellConfiguration] { - [StarCellConfiguration(theme: SparkTheme.shared, borderColor: UIColor.lightGray, fillColor: UIColor.blue, numberOfVertices: 5, fillMode: .full), - StarCellConfiguration(theme: SparkTheme.shared, borderColor: UIColor.lightGray, fillColor: UIColor.green, numberOfVertices: 8, fillMode: .full), - StarCellConfiguration(theme: SparkTheme.shared, borderColor: UIColor.lightGray, fillColor: UIColor.red, numberOfVertices: 5, fillMode: .half)] - } - - /// Switch Button - func createSwitchConfigurations() -> [SwitchConfiguration] { - [SwitchConfiguration(theme: SparkTheme.shared, intent: .main, alignment: .left, textContent: .text, isOn: true, isEnabled: true), - SwitchConfiguration(theme: SparkTheme.shared, intent: .basic, alignment: .right, textContent: .multilineText, isOn: false, isEnabled: true), - SwitchConfiguration(theme: SparkTheme.shared, intent: .success, alignment: .left, textContent: .attributedText, isOn: true, isEnabled: false) - ] - } - - /// Tab - func createTabConfigurations() -> [TabConfiguration] { - [TabConfiguration(theme: SparkTheme.shared, intent: .basic, size: .md, contents: [TabUIItemContent(title: "Tab 1"), TabUIItemContent(icon: UIImage(systemName: "paperplane.fill"), title: "Tab 2")], showBadge: false, isEqualWidth: true), - TabConfiguration(theme: SparkTheme.shared, intent: .main, size: .md, contents: [TabUIItemContent(title: "Tab 1"), TabUIItemContent(icon: UIImage(systemName: "paperplane.fill"), title: "Tab 2")], showBadge: true, isEqualWidth: true), - TabConfiguration(theme: SparkTheme.shared, intent: .support, size: .sm, contents: [TabUIItemContent(title: "Tab 1"), TabUIItemContent(icon: UIImage(systemName: "paperplane.fill"), title: "Tab 2"), TabUIItemContent(icon: UIImage(systemName: "paperplane.fill"), title: "Tab 3")], showBadge: false, isEqualWidth: false) - ] - } - - /// Tag - func createTagConfigurations() -> [TagConfiguration] { - [TagConfiguration(theme: SparkTheme.shared, intent: .main, variant: .filled, content: .text), - TagConfiguration(theme: SparkTheme.shared, intent: .basic, variant: .outlined, content: .icon), - TagConfiguration(theme: SparkTheme.shared, intent: .success, variant: .tinted, content: .iconAndText)] - } - -} diff --git a/.Demo/Classes/View/ListView/ListViewDelegate.swift b/.Demo/Classes/View/ListView/ListViewDelegate.swift deleted file mode 100644 index 11a061972..000000000 --- a/.Demo/Classes/View/ListView/ListViewDelegate.swift +++ /dev/null @@ -1,16 +0,0 @@ -// -// ListViewDelegate.swift -// SparkDemo -// -// Created by alican.aycil on 01.12.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit - -final class ListViewDelegate: NSObject, UITableViewDelegate { - - func tableView(_ tableView: UITableView, estimatedHeightForRowAt indexPath: IndexPath) -> CGFloat { - UITableView.automaticDimension - } -} diff --git a/.Demo/Classes/View/NewComponents/Configuration/EnumSelector/EnumSelectorActionSheetBuilder.swift b/.Demo/Classes/View/NewComponents/Configuration/EnumSelector/EnumSelectorActionSheetBuilder.swift new file mode 100644 index 000000000..d766bd0be --- /dev/null +++ b/.Demo/Classes/View/NewComponents/Configuration/EnumSelector/EnumSelectorActionSheetBuilder.swift @@ -0,0 +1,71 @@ +// +// EnumSelectorActionSheetBuilder.swift +// SparkDemo +// +// Created by louis.borlee on 20/09/2024. +// Copyright © 2024 Adevinta. All rights reserved. +// + +import UIKit + +final class EnumSelectorActionSheetBuilder where Enum: CaseIterable & Hashable { + + private let title: String? + + init(title: String?) { + self.title = title + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + func build(action: @escaping (Enum) -> Void) -> UIAlertController{ + let alertController = UIAlertController( + title: self.title, + message: nil, + preferredStyle: .actionSheet + ) + Enum.allCases.forEach { `case` in + alertController.addAction( + .init( + title: `case`.name, + style: .default, + handler: { _ in + action(`case`) + } + ) + ) + } + return alertController + } + + func build(action: @escaping (Enum?) -> Void) -> UIAlertController{ + let alertController = UIAlertController( + title: self.title, + message: nil, + preferredStyle: .actionSheet + ) + Enum.allCases.forEach { `case` in + alertController.addAction( + .init( + title: `case`.name, + style: .default, + handler: { _ in + action(`case`) + } + ) + ) + } + alertController.addAction( + .init( + title: "Default", + style: .default, + handler: { _ in + action(nil) + } + ) + ) + return alertController + } +} diff --git a/.Demo/Classes/View/NewComponents/Configuration/EnumSelector/EnumSelectorView.swift b/.Demo/Classes/View/NewComponents/Configuration/EnumSelector/EnumSelectorView.swift new file mode 100644 index 000000000..ef424b2fe --- /dev/null +++ b/.Demo/Classes/View/NewComponents/Configuration/EnumSelector/EnumSelectorView.swift @@ -0,0 +1,75 @@ +// +// EnumSelectorView.swift +// SparkDemo +// +// Created by louis.borlee on 20/09/2024. +// Copyright © 2024 Adevinta. All rights reserved. +// + +import UIKit + +final class EnumSelectorView: UIView, ObservableObject where Enum: CaseIterable & Hashable { + + private let title: String + @Published var currentCase: Enum + + private let button = UIButton() + + private weak var presenter: UIViewController? + + init(title: String, currentCase: Enum, presenter: UIViewController?) { + self.title = title + self.currentCase = currentCase + self.presenter = presenter + super.init(frame: .zero) + + self.setupView() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupView() { + let label = UILabel() + label.text = self.title + label.font = SparkTheme.shared.typography.subhead.uiFont + label.adjustsFontForContentSizeCategory = true + + self.button.setTitle(self.currentCase.name, for: .normal) + self.button.configuration = .plain() + + self.button.addAction(.init(handler: { [weak self] _ in + guard let self else { return } + let actionSheetBuilder = EnumSelectorActionSheetBuilder( + title: nil) + let alertController = actionSheetBuilder.build() { [weak self] newCase in + guard let self else { return } + self.currentCase = newCase + self.button.setTitle(newCase.name, for: .normal) + } + alertController.addAction( + .init( + title: "Dismiss", + style: .cancel, + handler: { _ in + alertController.dismiss(animated: true) + } + ) + ) + self.presenter?.present(alertController, isAnimated: true) + }), for: .touchUpInside) + + let stackView = UIStackView(arrangedSubviews: [label, self.button]) + stackView.alignment = .center + stackView.translatesAutoresizingMaskIntoConstraints = false + + self.addSubview(stackView) + NSLayoutConstraint.activate([ + stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor), + stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor), + stackView.topAnchor.constraint(equalTo: self.topAnchor), + stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor) + ]) + } +} diff --git a/.Demo/Classes/View/NewComponents/Configuration/OptionalEnumSelector/OptionalEnumSelectorView.swift b/.Demo/Classes/View/NewComponents/Configuration/OptionalEnumSelector/OptionalEnumSelectorView.swift new file mode 100644 index 000000000..fc9b82e95 --- /dev/null +++ b/.Demo/Classes/View/NewComponents/Configuration/OptionalEnumSelector/OptionalEnumSelectorView.swift @@ -0,0 +1,75 @@ +// +// OptionalEnumSelectorView.swift +// SparkDemo +// +// Created by louis.borlee on 20/09/2024. +// Copyright © 2024 Adevinta. All rights reserved. +// + +import UIKit + +final class OptionalEnumSelectorView: UIView, ObservableObject where Enum: CaseIterable & Hashable { + + private let title: String + @Published var currentCase: Enum? + + private let button = UIButton() + + private weak var presenter: UIViewController? + + init(title: String, currentCase: Enum?, presenter: UIViewController?) { + self.title = title + self.currentCase = currentCase + self.presenter = presenter + super.init(frame: .zero) + + self.setupView() + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + private func setupView() { + let label = UILabel() + label.text = self.title + label.font = SparkTheme.shared.typography.subhead.uiFont + label.adjustsFontForContentSizeCategory = true + + self.button.setTitle(self.currentCase?.name ?? "Default", for: .normal) + self.button.configuration = .plain() + + self.button.addAction(.init(handler: { [weak self] _ in + guard let self else { return } + let actionSheetBuilder = EnumSelectorActionSheetBuilder( + title: nil) + let alertController = actionSheetBuilder.build() { [weak self] newCase in + guard let self else { return } + self.currentCase = newCase + self.button.setTitle(newCase?.name ?? "Default", for: .normal) + } + alertController.addAction( + .init( + title: "Dismiss", + style: .cancel, + handler: { _ in + alertController.dismiss(animated: true) + } + ) + ) + self.presenter?.present(alertController, isAnimated: true) + }), for: .touchUpInside) + + let stackView = UIStackView(arrangedSubviews: [label, self.button]) + stackView.alignment = .center + stackView.translatesAutoresizingMaskIntoConstraints = false + + self.addSubview(stackView) + NSLayoutConstraint.activate([ + stackView.leadingAnchor.constraint(equalTo: self.leadingAnchor), + stackView.trailingAnchor.constraint(equalTo: self.trailingAnchor), + stackView.topAnchor.constraint(equalTo: self.topAnchor), + stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor) + ]) + } +} diff --git a/.Demo/Classes/View/NewComponents/Configuration/Themes/Themes.swift b/.Demo/Classes/View/NewComponents/Configuration/Themes/Themes.swift new file mode 100644 index 000000000..4591642d0 --- /dev/null +++ b/.Demo/Classes/View/NewComponents/Configuration/Themes/Themes.swift @@ -0,0 +1,21 @@ +// +// Themes.swift +// SparkDemo +// +// Created by louis.borlee on 20/09/2024. +// Copyright © 2024 Adevinta. All rights reserved. +// + +import Foundation + +enum Themes: CaseIterable, Hashable { + case spark + case sky + + var current: any Theme { + switch self { + case .sky: return SkyTheme() + case .spark: return SparkTheme.shared + } + } +} diff --git a/.Demo/Classes/View/NewComponents/NewComponentsView.swift b/.Demo/Classes/View/NewComponents/NewComponentsView.swift new file mode 100644 index 000000000..62f3bf6ce --- /dev/null +++ b/.Demo/Classes/View/NewComponents/NewComponentsView.swift @@ -0,0 +1,71 @@ +// +// NewComponentsView.swift +// SparkDemo +// +// Created by louis.borlee on 19/09/2024. +// Copyright © 2024 Adevinta. All rights reserved. +// + +import SwiftUI + +struct NewComponentsView: View { + + let isUIKit: Bool + var body: some View { + NavigationView { + List(Components.allCases, id: \.self) { component in + NavigationLink { + Group { + if self.isUIKit { + component.viewController() + } else { + component.view() + } + } + .navigationTitle(component.name) + .navigationBarTitleDisplayMode(.inline) + } label: { + Text(component.name.capitalizingFirstLetter) + } + + } + .navigationTitle("\(isUIKit ? "UIKit" : "SwiftUI")") + } + } +} + +// MARK: - UIKit +extension Components { + func viewController() -> some View { + switch self { + case .snackbar: + return HostingView(viewController: { SnackbarDemoUIView() }) + } + } + + private struct HostingView: UIViewControllerRepresentable { + + private var viewController: () -> UIViewControllerType + + init(viewController: @escaping () -> UIViewControllerType) { + self.viewController = viewController + } + + func makeUIViewController(context: Context) -> ViewController { + return self.viewController() + } + + func updateUIViewController(_ uiViewController: ViewController, context: Context) { + } + } +} + +// MARK: - SwiftUI +extension Components { + @ViewBuilder func view() -> some View { + switch self { + case .snackbar: + SnackbarDemoView() + } + } +} diff --git a/.Demo/Classes/View/NewComponents/Snackbar/SnackbarDemoUIView.swift b/.Demo/Classes/View/NewComponents/Snackbar/SnackbarDemoUIView.swift new file mode 100644 index 000000000..00879f23a --- /dev/null +++ b/.Demo/Classes/View/NewComponents/Snackbar/SnackbarDemoUIView.swift @@ -0,0 +1,408 @@ +// +// SnackbarDemoUIView.swift +// SparkDemo +// +// Created by louis.borlee on 20/09/2024. +// Copyright © 2024 Adevinta. All rights reserved. +// + +import SwiftUI +import UIKit +import Combine +@_spi(SI_SPI) import SparkCommon +import SparkCore + +final class SnackbarDemoUIView: UIViewController { + + private let scrollView = UIScrollView() + private let verticalStackView = UIStackView() + private lazy var horizontalStackView = UIStackView(arrangedSubviews: [self.leftPaddingView, self.rightPaddingView]) + + private var theme: any Theme { self.themes.current } + private var themes: Themes = .spark { + didSet { + self.snackbar.theme = self.theme + } + } + private var intent: SnackbarIntent = .main { + didSet { + self.snackbar.intent = self.intent + } + } + private var variant: SnackbarVariant? { + didSet { + guard self.variant != oldValue else { return } + if let variant { + self.snackbar.variant = variant + } else { + self.reload() + } + } + } + private var type: SnackbarType? { + didSet { + guard self.type != oldValue else { return } + if let type { + self.snackbar.type = type + } else { + self.reload() + } + } + } + private var image: UIImage? { + didSet { + self.snackbar.setImage(self.image) + } + } + private var showButtonCheckbox: CheckboxUIView? + private var showButton: Bool = false { + didSet { + if self.showButton == false { + self.snackbar.removeButton() + } else { + self.addButton() + } + } + } + + private lazy var labelTextField: TextFieldUIView = { + let textField = TextFieldUIView(theme: self.theme, intent: .neutral) + textField.placeholder = "Label Placeholder" + textField.text = "Default text" + return textField + }() + + private lazy var buttonTextField: TextFieldUIView = { + let textField = TextFieldUIView(theme: self.theme, intent: .neutral) + textField.placeholder = "Button Placeholder" + textField.text = "Tap" + return textField + }() + + private var leftPaddingView = UIView() + private var rightPaddingView = UIView() + + private lazy var snackbar = SnackbarUIView( + theme: self.theme, + intent: self.intent + ) + + private var snackbarWidthConstraint = NSLayoutConstraint() + + private var cancellables = Set() + + override func viewDidLoad() { + super.viewDidLoad() + self.view.backgroundColor = .systemBackground + self.setupView() + } + + private func setupConfiguration() { + self.setupThemeConfiguration() + self.setupIntentConfiguration() + self.setupVariantConfiguration() + self.setupTypeConfiguration() + self.setupImageConfiguration() + self.setupShowButtonConfiguration() + self.setupLeftPaddingConfiguration() + self.setupRightPaddingConfiguration() + self.setupLabelLineNumberConfiguration() + self.setupFullWithConfiguration() + self.setupLabelTextFieldConfiguration() + self.setupButtonTextFieldConfiguration() + } +} + +// MARK: - Setup view +extension SnackbarDemoUIView { + private func setupView() { + self.setupScrollView() + self.setupConfiguration() + self.setupHorizontalStackView() + self.setupComponent() + } + + private func setupScrollView() { + self.scrollView.translatesAutoresizingMaskIntoConstraints = false + + self.verticalStackView.translatesAutoresizingMaskIntoConstraints = false + self.verticalStackView.axis = .vertical + self.verticalStackView.alignment = .leading + self.verticalStackView.spacing = 12 + + self.scrollView.addSubview(self.verticalStackView) + self.view.addSubview(self.scrollView) + + NSLayoutConstraint.activate([ + self.scrollView.leadingAnchor.constraint(equalTo: self.view.leadingAnchor), + self.scrollView.trailingAnchor.constraint(equalTo: self.view.trailingAnchor), + self.scrollView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor), + self.scrollView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor) + ]) + + NSLayoutConstraint.activate([ + self.verticalStackView.leadingAnchor.constraint(equalTo: self.scrollView.leadingAnchor, constant: 12), + self.verticalStackView.topAnchor.constraint(equalTo: self.scrollView.topAnchor, constant: 12), + self.verticalStackView.bottomAnchor.constraint(lessThanOrEqualTo: self.scrollView.bottomAnchor, constant: -20), + self.verticalStackView.centerXAnchor.constraint(equalTo: self.scrollView.centerXAnchor), + self.verticalStackView.widthAnchor.constraint(equalTo: self.view.widthAnchor, constant: -24) + ]) + } + + private func setupHorizontalStackView() { + self.horizontalStackView.spacing = 12 + NSLayoutConstraint.activate([ + self.leftPaddingView.widthAnchor.constraint(equalToConstant: 75), + self.rightPaddingView.widthAnchor.constraint(equalToConstant: 75) + ]) + + self.leftPaddingView.backgroundColor = .systemBlue.withAlphaComponent(0.3) + self.leftPaddingView.setCornerRadius(8) + self.rightPaddingView.backgroundColor = .systemBlue.withAlphaComponent(0.3) + self.rightPaddingView.setCornerRadius(8) + + self.leftPaddingView.isHidden = true + self.rightPaddingView.isHidden = true + + self.verticalStackView.addArrangedSubview(self.horizontalStackView) + } + + private func setupComponent() { + self.snackbar = .init( + theme: self.theme, + intent: self.intent + ) + if let variant { + self.snackbar.variant = variant + } + if let type { + self.snackbar.type = type + } + self.snackbar.setImage(self.image) + self.snackbar.label.text = self.labelTextField.text + + if self.showButtonCheckbox?.selectionState == .selected { + self.addButton() + } + + let container = UIView() + container.addSubview(self.snackbar) + self.snackbar.translatesAutoresizingMaskIntoConstraints = false + + let topAnchorConstraint = self.snackbar.topAnchor.constraint(equalTo: container.topAnchor) + let leadingAnchorConstraint = self.snackbar.leadingAnchor.constraint(equalTo: container.leadingAnchor) + + topAnchorConstraint.priority = .required - 1 + leadingAnchorConstraint.priority = .required - 1 + + NSLayoutConstraint.activate([ + topAnchorConstraint, + leadingAnchorConstraint, + self.snackbar.centerXAnchor.constraint(equalTo: container.centerXAnchor), + self.snackbar.centerYAnchor.constraint(equalTo: container.centerYAnchor) + ]) + + self.horizontalStackView.insertArrangedSubview(container, at: 1) + + self.snackbarWidthConstraint = self.snackbar.widthAnchor.constraint(equalTo: self.verticalStackView.widthAnchor) + self.snackbarWidthConstraint.priority = .defaultHigh + } + + func reload() { + if let superview = self.snackbar.superview, superview.isDescendant(of: self.horizontalStackView) { + self.horizontalStackView.removeArrangedSubview(superview) + superview.removeFromSuperview() + } + self.setupComponent() + } + + private func addButton() { + let button = self.snackbar.addButton() + button.setTitle(self.buttonTextField.text, for: .normal) + } +} + +// MARK: - Setup configuration +extension SnackbarDemoUIView { + private func setupThemeConfiguration() { + let themeConfiguration = EnumSelectorView( + title: "Theme:", + currentCase: self.themes, + presenter: self + ) + themeConfiguration.$currentCase.dropFirst().subscribe( + in: &self.cancellables) { [weak self] newTheme in + guard let self else { return } + self.themes = newTheme + } + self.verticalStackView.addArrangedSubview(themeConfiguration) + self.verticalStackView.setCustomSpacing(0, after: themeConfiguration) + } + + private func setupIntentConfiguration() { + let intentConfiguration = EnumSelectorView( + title: "Intent:", + currentCase: self.intent, + presenter: self + ) + intentConfiguration.$currentCase.dropFirst().subscribe( + in: &self.cancellables) { [weak self] newIntent in + guard let self else { return } + self.intent = newIntent + } + self.verticalStackView.addArrangedSubview(intentConfiguration) + self.verticalStackView.setCustomSpacing(0, after: intentConfiguration) + } + + private func setupVariantConfiguration() { + let variantConfiguration = OptionalEnumSelectorView( + title: "Variant:", + currentCase: self.variant, + presenter: self + ) + variantConfiguration.$currentCase.dropFirst().subscribe( + in: &self.cancellables) { [weak self] newVariant in + guard let self else { return } + self.variant = newVariant + } + self.verticalStackView.addArrangedSubview(variantConfiguration) + self.verticalStackView.setCustomSpacing(0, after: variantConfiguration) + } + + private func setupTypeConfiguration() { + let typeConfiguration = OptionalEnumSelectorView( + title: "Type:", + currentCase: self.type, + presenter: self + ) + typeConfiguration.$currentCase.dropFirst().subscribe( + in: &self.cancellables) { [weak self] newType in + guard let self else { return } + self.type = newType + } + self.verticalStackView.addArrangedSubview(typeConfiguration) + } + + private func setupImageConfiguration() { + let checkbox = CheckboxUIView( + theme: self.theme, + intent: .basic, + text: "With image", + checkedImage: .init(systemName: "checkmark")?.withRenderingMode(.alwaysTemplate) ?? UIImage(), + selectionState: .unselected, + alignment: .left + ) + checkbox.publisher.subscribe(in: &self.cancellables) { [weak self] state in + guard let self else { return } + switch state { + case .selected: + self.image = .init(systemName: "externaldrive.fill.badge.minus") + default: + self.image = nil + } + } + self.verticalStackView.addArrangedSubview(checkbox) + } + + private func setupShowButtonConfiguration() { + let checkbox = CheckboxUIView( + theme: self.theme, + intent: .basic, + text: "With button", + checkedImage: .init(systemName: "checkmark")?.withRenderingMode(.alwaysTemplate) ?? UIImage(), + selectionState: .unselected, + alignment: .left + ) + checkbox.publisher.subscribe(in: &self.cancellables) { [weak self] state in + guard let self else { return } + self.showButton = state == .selected ? true : false + } + self.showButtonCheckbox = checkbox + self.verticalStackView.addArrangedSubview(checkbox) + } + + private func setupLeftPaddingConfiguration() { + let checkbox = CheckboxUIView( + theme: self.theme, + intent: .basic, + text: "With left padding", + checkedImage: .init(systemName: "checkmark")?.withRenderingMode(.alwaysTemplate) ?? UIImage(), + selectionState: .unselected, + alignment: .left + ) + checkbox.publisher.subscribe(in: &self.cancellables) { [weak self] state in + guard let self else { return } + self.leftPaddingView.isHidden = state == .selected ? false : true + } + self.verticalStackView.addArrangedSubview(checkbox) + } + + private func setupRightPaddingConfiguration() { + let checkbox = CheckboxUIView( + theme: self.theme, + intent: .basic, + text: "With right padding", + checkedImage: .init(systemName: "checkmark")?.withRenderingMode(.alwaysTemplate) ?? UIImage(), + selectionState: .unselected, + alignment: .left + ) + checkbox.publisher.subscribe(in: &self.cancellables) { [weak self] state in + guard let self else { return } + self.rightPaddingView.isHidden = state == .selected ? false : true + } + self.verticalStackView.addArrangedSubview(checkbox) + } + + private func setupLabelLineNumberConfiguration() { + let checkbox = CheckboxUIView( + theme: self.theme, + intent: .basic, + text: "Is multiline", + checkedImage: .init(systemName: "checkmark")?.withRenderingMode(.alwaysTemplate) ?? UIImage(), + selectionState: .unselected, + alignment: .left + ) + checkbox.publisher.subscribe(in: &self.cancellables) { [weak self] state in + guard let self else { return } + self.snackbar.label.numberOfLines = state == .selected ? 0 : 1 + } + self.verticalStackView.addArrangedSubview(checkbox) + } + + private func setupFullWithConfiguration() { + let checkbox = CheckboxUIView( + theme: self.theme, + intent: .basic, + text: "Is full width", + checkedImage: .init(systemName: "checkmark")?.withRenderingMode(.alwaysTemplate) ?? UIImage(), + selectionState: .unselected, + alignment: .left + ) + checkbox.publisher.subscribe(in: &self.cancellables) { [weak self] state in + guard let self else { return } + self.snackbarWidthConstraint.isActive.toggle() + } + self.verticalStackView.addArrangedSubview(checkbox) + } + + private func setupLabelTextFieldConfiguration() { + self.labelTextField.addAction(.init(handler: { _ in + self.snackbar.label.text = self.labelTextField.text + }), for: .editingChanged) + self.verticalStackView.addArrangedSubview(self.labelTextField) + NSLayoutConstraint.activate([ + self.labelTextField.widthAnchor.constraint(equalTo: self.verticalStackView.widthAnchor) + ]) + } + + private func setupButtonTextFieldConfiguration() { + self.buttonTextField.addAction(.init(handler: { _ in + self.snackbar.buttonView?.setTitle(self.buttonTextField.text, for: .normal) + }), for: .editingChanged) + self.verticalStackView.addArrangedSubview(self.buttonTextField) + NSLayoutConstraint.activate([ + self.buttonTextField.widthAnchor.constraint(equalTo: self.verticalStackView.widthAnchor) + ]) + self.verticalStackView.setCustomSpacing(20, after: self.buttonTextField) + } +} diff --git a/.Demo/Classes/View/NewComponents/Snackbar/SnackbarDemoView.swift b/.Demo/Classes/View/NewComponents/Snackbar/SnackbarDemoView.swift new file mode 100644 index 000000000..28036e17b --- /dev/null +++ b/.Demo/Classes/View/NewComponents/Snackbar/SnackbarDemoView.swift @@ -0,0 +1,205 @@ +// +// SnackbarDemoView.swift +// SparkDemo +// +// Created by louis.borlee on 19/09/2024. +// Copyright © 2024 Adevinta. All rights reserved. +// + +import SwiftUI +import SparkSnackbar +import SparkButton + +struct SnackbarDemoView: View { + + @State var theme: any Theme = SparkTheme.shared + @State var intent: SnackbarIntent = .basic + @State var type: SnackbarType? + @State var variant: SnackbarVariant? + @State var showImage: Bool = false + + @State var text: String = "This is the snackbar text" + @State var buttonTitle: String = "Tap" + + @State var maxNumberOfLines: Int = 0 + + @State var withLeftPadding: Bool = false + @State var withRightPadding: Bool = false + + @FocusState var isFocused: Bool + + var body: some View { + ScrollView { + VStack(alignment: .leading, spacing: 20) { + componentsConfiguration() + content { + VStack(spacing: 16) { + modifiedSnackbar(emptySnackbar()) + modifiedSnackbar(snackbarWithButton()) + modifiedSnackbar(snackbarWithCustomView()) + } + } + paddingConfiguration() + } + .lineLimit(self.maxNumberOfLines == 0 ? nil : self.maxNumberOfLines) + .padding(12) + } + } + + @ViewBuilder private func componentsConfiguration() -> some View { + VStack(alignment: .leading, spacing: 12) { + ThemeSelector(theme: self.$theme) + EnumSelector( + title: "Intent", + dialogTitle: "Select an intent", + values: SnackbarIntent.allCases, + value: self.$intent + ) + OptionalEnumSelector( + title: "Type", + dialogTitle: "Select a type", + values: SnackbarType.allCases, + value: self.$type + ) + OptionalEnumSelector( + title: "Variant", + dialogTitle: "Select a variant", + values: SnackbarVariant.allCases, + value: self.$variant + ) + TextFieldView( + "Snackbar text", + text: self.$text, + theme: self.theme, + intent: .neutral + ) + TextFieldView( + "Button title", + text: self.$buttonTitle, + theme: self.theme, + intent: .neutral + ) + RangeSelector( + title: "Maximum number of lines", + range: 0...10, + selectedValue: self.$maxNumberOfLines + ) + } + } + + @ViewBuilder private func content(_ content: @escaping () -> some View) -> some View { + HStack { + if withLeftPadding { + paddingView() + } + content() + if withRightPadding { + paddingView() + } + } + } + + @ViewBuilder private func paddingConfiguration() -> some View { + VStack(alignment: .leading, spacing: 12) { + SwitchView( + theme: self.theme, + intent: .info, + alignment: .left, + isOn: self.$withLeftPadding + ) + .text("With left padding") + SwitchView( + theme: self.theme, + intent: .info, + alignment: .left, + isOn: self.$withRightPadding + ) + .text("With right padding") + } + } + + @ViewBuilder private func emptySnackbar() -> SnackbarView { + SnackbarView( + theme: self.theme, + intent: self.intent, + image: self.image()) { + Text(self.text) + } + } + + @ViewBuilder private func snackbarWithButton() -> SnackbarView { + SnackbarView( + theme: self.theme, + intent: self.intent, + image: self.image()) { + Text(self.text) + } button: { configuration in + ButtonView( + theme: self.theme, + intent: configuration.intent, + variant: configuration.variant, + size: configuration.size, + shape: configuration.shape, + alignment: .leadingImage) { + self.showImage.toggle() + } + .title(self.buttonTitle, for: .normal) + } + } + + @ViewBuilder private func snackbarWithCustomView() -> SnackbarView { + SnackbarView( + theme: self.theme, + intent: self.intent, + image: self.image()) { + Text(self.text) + } button: { configuration in + HStack { + IconButtonView( + theme: self.theme, + intent: .danger, + variant: .filled, + size: .large, + shape: .pill, + action: { + self.showImage.toggle() + } + ) + .image(.init(systemName: "externaldrive"), for: .normal) + IconButtonView( + theme: self.theme, + intent: .success, + variant: .contrast, + size: .small, + shape: .square, + action: { + self.showImage.toggle() + } + ) + .image(.init(systemName: "externaldrive.fill"), for: .normal) + } + } + } + + private func modifiedSnackbar(_ snackbar: SnackbarView) -> SnackbarView { + var copy = snackbar + if let variant { + copy = copy.variant(variant) + } + if let type { + copy = copy.type(type) + } + return copy + } + + @ViewBuilder private func image() -> Image? { + self.showImage ? Image(systemName: "info.square") : nil + } + + @ViewBuilder func paddingView() -> some View { + Color.blue + .opacity(0.3) + .frame(width: 75) + .cornerRadius(8) + } +} diff --git a/.Demo/Classes/View/SettingsViewController.swift b/.Demo/Classes/View/SettingsViewController.swift deleted file mode 100644 index dbdf947d6..000000000 --- a/.Demo/Classes/View/SettingsViewController.swift +++ /dev/null @@ -1,102 +0,0 @@ -// -// SettingsViewController.swift -// SparkDemo -// -// Created by alican.aycil on 11.09.23. -// Copyright © 2023 Adevinta. All rights reserved. -// - -import UIKit -import SwiftUI - -final class SettingsViewController: UICollectionViewController { - - // MARK: - Typealias - typealias DataSource = UICollectionViewDiffableDataSource - typealias SnapShot = NSDiffableDataSourceSnapshot - - // MARK: - Properties - private let reuseIdentifier = "defaultCell" - - private lazy var collectionViewDataSource: DataSource = { - /// CollectionView cell registration - let cellRegistration = UICollectionView.CellRegistration { - (cell: UICollectionViewListCell, indexPath: IndexPath, title: String) in - var contentConfiguration = cell.defaultContentConfiguration() - contentConfiguration.text = title - cell.contentConfiguration = contentConfiguration - cell.accessories = [.disclosureIndicator(options: .init(tintColor: .systemGray3))] - } - /// CollectionView diffable data source - return DataSource(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in - return collectionView.dequeueConfiguredReusableCell( - using: cellRegistration, for: indexPath, item: itemIdentifier) - } - }() - - // MARK: - ViewDidLoad - override func viewDidLoad() { - super.viewDidLoad() - navigationController?.navigationBar.prefersLargeTitles = true - navigationItem.title = "Settings" - setupData() - } - - private func setupData() { - /// CollectionView append sections and items - var snapShot = SnapShot() - snapShot.appendSections([.all]) - snapShot.appendItems(Row.allCases.map{ $0.name }, toSection: .all) - collectionViewDataSource.apply(snapShot) - } -} - -// MARK: - CollectionViewLayout -extension SettingsViewController { - - static func makeLayout() -> UICollectionViewCompositionalLayout { - let listConfiguration = UICollectionLayoutListConfiguration(appearance: .insetGrouped) - return UICollectionViewCompositionalLayout.list(using: listConfiguration) - } -} - -// MARK: - CollectionViewDelegates -extension SettingsViewController { - - override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - let section = Row.allCases[indexPath.row] - switch section { - case .appearance: - self.presentAppearanceSheet() - } - } -} - -// MARK: - Navigation -extension SettingsViewController { - - private func presentAppearanceSheet() { - - let actionSheet = SparkActionSheet.init( - values: [.unspecified, .light, . dark], - texts: ["Unspecified", "Light", "Dark"] - ) { mode in - UIApplication.shared.windows.forEach { window in - window.overrideUserInterfaceStyle = mode - } - } - self.present(actionSheet, isAnimated: true) - } -} - -// MARK: - Enums -extension SettingsViewController { - - enum Section { - case all - } - - enum Row: CaseIterable { - case appearance - } -} diff --git a/Package.swift b/Package.swift index 4c2ded248..a2dd78a52 100644 --- a/Package.swift +++ b/Package.swift @@ -98,7 +98,7 @@ let package = Package( ), .package( url: "https://github.com/adevinta/spark-ios-component-snackbar.git", - // path: "../spark-ios-component-snackbar" + //path: "../spark-ios-component-snackbar" /*version*/ "0.0.1"..."999.999.999" ), .package( diff --git a/Sources/Core/Core.swift b/Sources/Core/Core.swift index 598812cb2..552187d06 100644 --- a/Sources/Core/Core.swift +++ b/Sources/Core/Core.swift @@ -16,6 +16,7 @@ @_exported import SparkProgressTracker @_exported import SparkRadioButton @_exported import SparkRating +@_exported import SparkSnackbar @_exported import SparkSlider @_exported import SparkSpinner @_exported import SparkSwitch