diff --git a/Apps/Examples/Examples/FioriSwiftUICore/FormCells/ListPicker.swift b/Apps/Examples/Examples/FioriSwiftUICore/FormCells/ListPicker.swift index a84bad65a..b815ef390 100644 --- a/Apps/Examples/Examples/FioriSwiftUICore/FormCells/ListPicker.swift +++ b/Apps/Examples/Examples/FioriSwiftUICore/FormCells/ListPicker.swift @@ -51,6 +51,7 @@ struct ListPickerItemExample: View { case identifiable case objectItem case stringItem + case differentStyles case activeChildren case searchable case searchableListView @@ -86,6 +87,12 @@ struct ListPickerItemExample: View { { Text("StringItem") } + case .differentStyles: + NavigationLink( + destination: ListPickerItemStylesExample()) + { + Text("Different Styles") + } case .activeChildren: NavigationLink( destination: ListPickerItemActiveChildrenExample()) @@ -342,6 +349,40 @@ struct ListPickerItemActiveChildrenExample: View { } } +public struct ListPickerItemStylesExample: View { + private let model = ["First", "Second", "Third", "Fourth", "Fifth"] + + @State var selections: Set = ["Second"] + + @State var isEnabled: Bool = true + @State var axis: Axis = .horizontal + + public var body: some View { + List { + Section("List Picker Item") { + ListPickerItem(key: { + Text("Choice") + }, value: { + let str = Array(selections).joined(separator: ", ") + Text(str) + }, axis: self.axis, + configuration: + ListPickerItemConfiguration(self.model, selection: self.$selections)) + .disabled(!self.isEnabled) + } + + Section("Styles Panel") { + Toggle("Is Enabled", isOn: self.$isEnabled) + Picker("Axis", selection: self.$axis) { + Text("Horizontal").tag(Axis.horizontal) + Text("Vertical").tag(Axis.vertical) + } + } + } + .navigationBarTitle(Text("Form")) + } +} + struct ListPickerItemPreview: PreviewProvider { static var previews: some View { NavigationStack { diff --git a/Sources/FioriSwiftUICore/Models/ModelDefinitions.swift b/Sources/FioriSwiftUICore/Models/ModelDefinitions.swift index f37417bde..ed60a9d48 100644 --- a/Sources/FioriSwiftUICore/Models/ModelDefinitions.swift +++ b/Sources/FioriSwiftUICore/Models/ModelDefinitions.swift @@ -107,7 +107,11 @@ public protocol ActivityItemsModel: ActionItemsComponent {} // sourcery: add_env_props = "listpickerListStyle" // sourcery: add_env_props = "listPickerListViewModifier" // sourcery: virtualPropDestinationConfiguration = "var destinationConfiguration: ListPickerItemConfiguration? = nil" -public protocol ListPickerItemModel: KeyComponent, ValueComponent {} +public protocol ListPickerItemModel: KeyComponent, ValueComponent { + // sourcery: default.value = .horizontal + // sourcery: no_view + var axis: Axis { get } +} // sourcery: generated_component_not_configurable public protocol ProgressIndicatorModel: ProgressIndicatorComponent {} diff --git a/Sources/FioriSwiftUICore/Utils/FioriVStack.swift b/Sources/FioriSwiftUICore/Utils/FioriVStack.swift new file mode 100644 index 000000000..ddf4083ac --- /dev/null +++ b/Sources/FioriSwiftUICore/Utils/FioriVStack.swift @@ -0,0 +1,51 @@ +import SwiftUI + +// This VStack will ignore subviews which width or height is 0, so no extra space will be added. +struct CompactVStack: Layout { + var alignment: HorizontalAlignment + var spacing: CGFloat + + init(alignment: HorizontalAlignment = .center, spacing: CGFloat = 8) { + self.alignment = alignment + self.spacing = spacing + } + + func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) { + guard let containerWidth = proposal.width else { return } + var currentY: CGFloat = bounds.minY + for subview in subviews { + let size = subview.sizeThatFits(ProposedViewSize(width: containerWidth, height: nil)) + let xPosition: CGFloat + switch self.alignment { + case .leading: + xPosition = bounds.minX + case .trailing: + xPosition = bounds.maxX - size.width + default: + xPosition = bounds.midX - size.width / 2 + } + + subview.place(at: CGPoint(x: xPosition, y: currentY), proposal: ProposedViewSize(width: containerWidth, height: size.height)) + currentY += size.height + self.spacing + } + } + + func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize { + guard let containerWidth = proposal.width else { return .zero } + var totalHeight: CGFloat = 0 + var maxWidth: CGFloat = 0 + + for subview in subviews { + let size = subview.sizeThatFits(ProposedViewSize(width: containerWidth, height: nil)) + if size.width > 0, size.height > 0 { + totalHeight += size.height + maxWidth = max(maxWidth, size.width) + totalHeight += self.spacing + } + } + if totalHeight > 0 { + totalHeight -= self.spacing + } + return CGSize(width: maxWidth, height: totalHeight) + } +} diff --git a/Sources/FioriSwiftUICore/Views/KeyValueItem+View.swift b/Sources/FioriSwiftUICore/Views/KeyValueItem+View.swift index 3f0ce0bd0..36b889c37 100644 --- a/Sources/FioriSwiftUICore/Views/KeyValueItem+View.swift +++ b/Sources/FioriSwiftUICore/Views/KeyValueItem+View.swift @@ -1,8 +1,6 @@ import Foundation import SwiftUI -// TODO: - Implement Fiori style definitions - extension Fiori { enum KeyValueItem { typealias KeyCumulative = EmptyModifier @@ -32,11 +30,9 @@ extension Fiori { } } -// TODO: - Implement KeyValueItem View body - extension KeyValueItem: View { public var body: some View { - VStack(alignment: .leading) { + CompactVStack(alignment: .leading) { if _axis == .horizontal { HStack { key @@ -46,7 +42,6 @@ extension KeyValueItem: View { .frame(maxWidth: .infinity) } else { key - .padding(.bottom, 3) value } } diff --git a/Sources/FioriSwiftUICore/Views/ListPickerItem+View.swift b/Sources/FioriSwiftUICore/Views/ListPickerItem+View.swift index 922852a6c..e64d71f09 100644 --- a/Sources/FioriSwiftUICore/Views/ListPickerItem+View.swift +++ b/Sources/FioriSwiftUICore/Views/ListPickerItem+View.swift @@ -8,7 +8,7 @@ extension Fiori { enum ListPickerItem { struct Key: ViewModifier { func body(content: Content) -> some View { - content.font(.fiori(forTextStyle: .headline)).foregroundColor(.preferredColor(.primaryLabel)) + content.font(.fiori(forTextStyle: .subheadline, weight: .bold)).foregroundColor(.preferredColor(.primaryLabel)) } } @@ -34,11 +34,11 @@ extension ListPickerItem: View { NavigationLink( destination: self.destinationView, label: { - KeyValueItem { + KeyValueItem(key: { key - } value: { + }, value: { value - } + }, axis: _axis) } ) } @@ -62,13 +62,15 @@ public extension ListPickerItem { /// - Parameters: /// - key: The key view of the list. /// - value: The value view of the list. + /// - axis: Axis for key and value layout. /// - configuration: The configuration for constructing the list picker. init( @ViewBuilder key: @escaping () -> Key, @ViewBuilder value: @escaping () -> Value, + axis: Axis = .horizontal, configuration: ListPickerItemConfiguration? = nil ) { - self.init(key: key, value: value) + self.init(key: key, value: value, axis: axis) self.destinationConfiguration = configuration } } diff --git a/Sources/FioriSwiftUICore/_generated/ViewModels/API/ListPickerItem+API.generated.swift b/Sources/FioriSwiftUICore/_generated/ViewModels/API/ListPickerItem+API.generated.swift index dc085eb17..73acaaae9 100644 --- a/Sources/FioriSwiftUICore/_generated/ViewModels/API/ListPickerItem+API.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/ViewModels/API/ListPickerItem+API.generated.swift @@ -11,16 +11,19 @@ public struct ListPickerItem { let _key: Key let _value: Value + let _axis: Axis var destinationConfiguration: ListPickerItemConfiguration? = nil private var isModelInit: Bool = false private var isValueNil: Bool = false public init( @ViewBuilder key: () -> Key, - @ViewBuilder value: () -> Value + @ViewBuilder value: () -> Value, + axis: Axis = .horizontal ) { self._key = key() self._value = value() + self._axis = axis } @ViewBuilder var key: some View { @@ -47,12 +50,13 @@ extension ListPickerItem where Key == Text, Value == _ConditionalContent { public init(model: ListPickerItemModel) { - self.init(key: model.key, value: model.value) + self.init(key: model.key, value: model.value, axis: model.axis) } - public init(key: String, value: String? = nil) { + public init(key: String, value: String? = nil, axis: Axis = .horizontal) { self._key = Text(key) self._value = value != nil ? ViewBuilder.buildEither(first: Text(value!)) : ViewBuilder.buildEither(second: EmptyView()) + self._axis = axis isModelInit = true isValueNil = value == nil ? true : false diff --git a/Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/ListPickerItem+Init.generated.swift b/Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/ListPickerItem+Init.generated.swift index 8f97bb729..dda81d83a 100644 --- a/Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/ListPickerItem+Init.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/ViewModels/Init+Extensions/ListPickerItem+Init.generated.swift @@ -4,11 +4,13 @@ import SwiftUI extension ListPickerItem where Value == EmptyView { public init( - @ViewBuilder key: () -> Key + @ViewBuilder key: () -> Key, + axis: Axis = .horizontal ) { self.init( key: key, - value: { EmptyView() } + value: { EmptyView() }, + axis: axis ) } } diff --git a/Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/ListPickerItemModel+Extensions.generated.swift b/Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/ListPickerItemModel+Extensions.generated.swift new file mode 100644 index 000000000..5d472868a --- /dev/null +++ b/Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/ListPickerItemModel+Extensions.generated.swift @@ -0,0 +1,9 @@ +// Generated using Sourcery 2.1.7 — https://github.com/krzysztofzablocki/Sourcery +// DO NOT EDIT +import SwiftUI + +public extension ListPickerItemModel { + var axis: Axis { + return .horizontal + } +}