Skip to content

Commit

Permalink
Add orientation
Browse files Browse the repository at this point in the history
  • Loading branch information
ludovic35 committed Feb 4, 2025
1 parent c4e02e5 commit 759bc02
Show file tree
Hide file tree
Showing 6 changed files with 134 additions and 53 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,20 @@ final class SwitchConfigurationModel: ComponentConfiguration {
@Published var divider: Bool {
didSet { updateCode() }
}
@Published var orientation: OUDSSwitch.Orientation {
didSet { updateCode() }
}

// MARK: Initializer

override init() {
enabled = true
switchOnly = false
helperText = true
icon = true
onError = false
divider = true
enabled = true
switchOnly = false
helperText = true
icon = true
onError = false
divider = true
orientation = .default
}

deinit { }
Expand All @@ -65,7 +69,7 @@ final class SwitchConfigurationModel: ComponentConfiguration {
} else {
code =
"""
OUDSSwitch(isOn: $isOn, label: \"Label\"\(helperTextPatern)\(iconPatern)\(onErrorPatern)\(dividerPatern))
OUDSSwitch(isOn: $isOn, label: \"Label\"\(helperTextPatern)\(iconPatern)\(onErrorPatern)\(dividerPatern)\(orienationPatern)
\(disableCode))
"""
}
Expand Down Expand Up @@ -103,6 +107,13 @@ final class SwitchConfigurationModel: ComponentConfiguration {
return ""
}
}
private var orienationPatern: String {
if onError {
return ", orientation: \(orientation.description)"
} else {
return ""
}
}
}

// MARK: - Switch Configuration View
Expand All @@ -124,25 +135,47 @@ struct SwitchConfiguration: View {
.typeHeadingMedium(theme)
.foregroundStyle(theme.colors.colorContentDefault.color(for: colorScheme))

Toggle("app_components_common_helperText_label", isOn: $model.helperText)
.typeHeadingMedium(theme)
.foregroundStyle(theme.colors.colorContentDefault.color(for: colorScheme))
.disabled(model.switchOnly)
if !model.switchOnly {
DesignToolboxChoicePicker(title: "app_components_common_orientation_label", selection: $model.orientation) {
ForEach(OUDSSwitch.Orientation.allCases, id: \.id) { orientation in
Text(LocalizedStringKey(orientation.description)).tag(orientation)
}
}

Toggle("app_components_common_helperText_label", isOn: $model.helperText)
.typeHeadingMedium(theme)
.foregroundStyle(theme.colors.colorContentDefault.color(for: colorScheme))

Toggle("app_components_common_icon_label", isOn: $model.icon)
.typeHeadingMedium(theme)
.foregroundStyle(theme.colors.colorContentDefault.color(for: colorScheme))

Toggle("app_components_common_divider_label", isOn: $model.divider)
.typeHeadingMedium(theme)
.foregroundStyle(theme.colors.colorContentDefault.color(for: colorScheme))

Toggle("app_components_common_onError_label", isOn: $model.onError)
.typeHeadingMedium(theme)
.foregroundStyle(theme.colors.colorContentDefault.color(for: colorScheme))
}
}
}
}

Toggle("app_components_common_icon_label", isOn: $model.icon)
.typeHeadingMedium(theme)
.foregroundStyle(theme.colors.colorContentDefault.color(for: colorScheme))
.disabled(model.switchOnly)
// MARK: Switch Layout Orientation extension

Toggle("app_components_common_divider_label", isOn: $model.divider)
.typeHeadingMedium(theme)
.foregroundStyle(theme.colors.colorContentDefault.color(for: colorScheme))
.disabled(model.switchOnly)
extension OUDSSwitch.Orientation: @retroactive CaseIterable, @retroactive CustomStringConvertible {
nonisolated(unsafe) public static let allCases: [OUDSSwitch.Orientation] = [.default, .inverse]

Toggle("app_components_common_onError_label", isOn: $model.onError)
.typeHeadingMedium(theme)
.foregroundStyle(theme.colors.colorContentDefault.color(for: colorScheme))
.disabled(model.switchOnly)
// Note: Not localized because it is a technical name
public var description: String {
switch self {
case .default:
"Default"
case .inverse:
"Inverse"
}
}

var id: String { description }
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,14 @@ private struct SwitchDemo: View {
Spacer()
}
} else {
OUDSSwitch(isOn: $isOn, label: "app_components_switch_label_text", helperText: helperText, icon: icon, onError: model.onError, divider: model.divider)
OUDSSwitch(
isOn: $isOn,
label: "app_components_switch_label_text",
helperText: helperText,
icon: icon,
onError: model.onError,
divider: model.divider,
orientation: model.orientation)
.disabled(!model.enabled)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@
"app_components_common_icon_label" = "Icon";
"app_components_common_divider_label" = "Divider";
"app_components_common_onError_label" = "On error";
"app_components_common_orientation_label" = "Orientation";

// MARK: Components: Button

Expand Down
62 changes: 40 additions & 22 deletions OUDS/Core/Components/Sources/Switch/Internal/OUDSSwitchLabel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct OUDSSwitchLabel: View {
let icon: Image?
let onError: Bool
let divider: Bool
let orientation: OUDSSwitch.Orientation
}

let internalState: InternalSwitchState
Expand All @@ -37,33 +38,50 @@ struct OUDSSwitchLabel: View {

var body: some View {
HStack(alignment: .top, spacing: theme.listItem.listItemSpaceColumnGap) {
VStack(alignment: .leading, spacing: 0) {
Text(LocalizedStringKey(label.label))
.typeLabelDefaultLarge(theme)
.multilineTextAlignment(.leading)
.foregroundStyle(labelColor)
.frame(maxWidth: .infinity, alignment: .leading)
switch label.orientation {
case .default:
texts
icon
case .inverse:
icon
texts
}
}
}

// MARK: Private helpers

if let helperText = label.helperText {
Text(LocalizedStringKey(helperText))
.typeLabelDefaultMedium(theme)
.multilineTextAlignment(.leading)
.foregroundStyle(helperTextColor)
}
@ViewBuilder
private var icon: some View {
if let icon = label.icon {
HStack(alignment: .center, spacing: 0) {
icon
.resizable()
.renderingMode(.template)
.foregroundStyle(iconColor)
.frame(width: theme.listItem.listItemSizeIcon, height: theme.listItem.listItemSizeIcon)
}
.frame(maxWidth: .infinity, alignment: .leading)
.frame(maxHeight: theme.checkRadio.checkRadioSizeMaxHeightAssetsContainer, alignment: .center)
}
}

if let icon = label.icon {
HStack(alignment: .center, spacing: 0) {
icon
.resizable()
.renderingMode(.template)
.foregroundStyle(iconColor)
.frame(width: theme.listItem.listItemSizeIcon, height: theme.listItem.listItemSizeIcon)
}
.frame(maxHeight: theme.checkRadio.checkRadioSizeMaxHeightAssetsContainer, alignment: .center)
@ViewBuilder
private var texts: some View {
VStack(alignment: .leading, spacing: 0) {
Text(LocalizedStringKey(label.label))
.typeLabelDefaultLarge(theme)
.multilineTextAlignment(.leading)
.foregroundStyle(labelColor)
.frame(maxWidth: .infinity, alignment: .leading)

if let helperText = label.helperText {
Text(LocalizedStringKey(helperText))
.typeLabelDefaultMedium(theme)
.multilineTextAlignment(.leading)
.foregroundStyle(helperTextColor)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
}

private var labelColor: Color {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,12 +36,14 @@ struct OUDSSwitchLabeledStyle: ButtonStyle {

func makeBody(configuration: Configuration) -> some View {
HStack(alignment: .top, spacing: theme.listItem.listItemSpaceColumnGap) {
HStack(alignment: .center, spacing: 0) {
OUDSSwitchButton(internalState: internalState(isPressed: configuration.isPressed), isOn: isOn)
switch label.orientation {
case .default:
toggle(isPressed: configuration.isPressed)
label(isPressed: configuration.isPressed)
case .inverse:
label(isPressed: configuration.isPressed)
toggle(isPressed: configuration.isPressed)
}
.frame(maxHeight: theme.checkRadio.checkRadioSizeMaxHeightAssetsContainer, alignment: .center)

OUDSSwitchLabel(internalState: internalState(isPressed: configuration.isPressed), label: label)
}
.padding(.all, theme.listItem.listItemSpaceInset)
.oudsDivider(show: label.divider)
Expand All @@ -51,6 +53,17 @@ struct OUDSSwitchLabeledStyle: ButtonStyle {
}
}

private func toggle(isPressed: Bool) -> some View {
HStack(alignment: .center, spacing: 0) {
OUDSSwitchButton(internalState: internalState(isPressed: isPressed), isOn: isOn)
}
.frame(maxHeight: theme.checkRadio.checkRadioSizeMaxHeightAssetsContainer, alignment: .center)
}

private func label(isPressed: Bool) -> some View {
OUDSSwitchLabel(internalState: internalState(isPressed: isPressed), label: label)
}

// MARK: Private Helpers

func backgroundColor(state: InternalSwitchState) -> Color {
Expand Down
13 changes: 11 additions & 2 deletions OUDS/Core/Components/Sources/Switch/OUDSSwitch.swift
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,12 @@ public struct OUDSSwitch: View {
case nested
}

/// Used to define the orientation of the Layout
public enum Orientation {
case `default`
case inverse
}

// MARK: Initializers

/// Creates a switch with no label.
Expand All @@ -61,6 +67,7 @@ public struct OUDSSwitch: View {
self.layout = .nested
}

// swiftlint:disable line_length
/// Creates a switch with label and optional helper text, icon, divider.
///
/// - Parameters:
Expand All @@ -71,10 +78,12 @@ public struct OUDSSwitch: View {
/// - icon: An optional icon
/// - onError: It the option is on error
/// - divider: If true a divider is added at the bottom of the view.
public init(isOn: Binding<Bool>, label: String, helperText: String? = nil, icon: Image? = nil, onError: Bool = false, divider: Bool = false) {
/// - orientation: Specify the orientation of the layout. If Default the switch at the leading position, if inverse it is on trailing.
public init(isOn: Binding<Bool>, label: String, helperText: String? = nil, icon: Image? = nil, onError: Bool = false, divider: Bool = false, orientation: Orientation = .default) {
self.isOn = isOn
self.layout = .labeled(.init(label: label, helperText: helperText, icon: icon, onError: onError, divider: divider))
self.layout = .labeled(.init(label: label, helperText: helperText, icon: icon, onError: onError, divider: divider, orientation: orientation))
}
// swiftlint:enable line_length

// MARK: Body

Expand Down

0 comments on commit 759bc02

Please sign in to comment.