Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: 💡 [HCPSDKFIORIUIKIT-2685] FilterFormView Refactor #981

Merged
merged 6 commits into from
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions Apps/Examples/Examples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
6D14F05E2C9290F20053BA98 /* BannerMultiMessageCustomInitExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D14F05D2C9290F20053BA98 /* BannerMultiMessageCustomInitExample.swift */; };
6D3A3DE92CDB5F1E004D4597 /* ObjectCellEnhancementExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D3A3DE82CDB5F1E004D4597 /* ObjectCellEnhancementExample.swift */; };
6D66D7F12D02FC7B00F7A97D /* ActivityItemExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D66D7EF2D02FC7B00F7A97D /* ActivityItemExample.swift */; };
6D6E256D2D378025009A62CA /* FilterFormViewExamples.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6E256C2D378025009A62CA /* FilterFormViewExamples.swift */; };
6D6E86252C50D42000EDB6F4 /* FioriButtonInListExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6E86242C50D42000EDB6F4 /* FioriButtonInListExample.swift */; };
6D6E86292C50E5F900EDB6F4 /* FioriButtonInListMultipleLineExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6E86282C50E5F900EDB6F4 /* FioriButtonInListMultipleLineExample.swift */; };
6D6E86672C50FDBE00EDB6F4 /* FioriButtonInCollectionExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6D6E86662C50FDBE00EDB6F4 /* FioriButtonInCollectionExample.swift */; };
Expand Down Expand Up @@ -279,6 +280,7 @@
6D14F05D2C9290F20053BA98 /* BannerMultiMessageCustomInitExample.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BannerMultiMessageCustomInitExample.swift; sourceTree = "<group>"; };
6D3A3DE82CDB5F1E004D4597 /* ObjectCellEnhancementExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectCellEnhancementExample.swift; sourceTree = "<group>"; };
6D66D7EF2D02FC7B00F7A97D /* ActivityItemExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ActivityItemExample.swift; sourceTree = "<group>"; };
6D6E256C2D378025009A62CA /* FilterFormViewExamples.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FilterFormViewExamples.swift; sourceTree = "<group>"; };
6D6E86242C50D42000EDB6F4 /* FioriButtonInListExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FioriButtonInListExample.swift; sourceTree = "<group>"; };
6D6E86282C50E5F900EDB6F4 /* FioriButtonInListMultipleLineExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FioriButtonInListMultipleLineExample.swift; sourceTree = "<group>"; };
6D6E86662C50FDBE00EDB6F4 /* FioriButtonInCollectionExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FioriButtonInCollectionExample.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -830,6 +832,7 @@
9D0086682BA8F6820004BE15 /* TextFieldFormViewExample.swift */,
9D0086672BA8F6810004BE15 /* TitleFormViewExample.swift */,
9D057DAC2C34826700F5331C /* RatingControlFormViewExample.swift */,
6D6E256C2D378025009A62CA /* FilterFormViewExamples.swift */,
);
path = FormViews;
sourceTree = "<group>";
Expand Down Expand Up @@ -1304,6 +1307,7 @@
9D0086692BA8F6820004BE15 /* TitleFormViewExample.swift in Sources */,
6DEC31F82C47B7850084DD20 /* FioriButtonStyleToggleExample.swift in Sources */,
B141D6BB29261F9E008A8BD6 /* SearchableListViewExample.swift in Sources */,
6D6E256D2D378025009A62CA /* FilterFormViewExamples.swift in Sources */,
C106AD482B33940600FE8B35 /* SearchWithBookmark.swift in Sources */,
975CB76B256C5A7400DB7A15 /* SignatureCaptureViewExample.swift in Sources */,
8AD9DFB125D49967007448EC /* ContactItemStateAndDataBindingExample.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
import FioriSwiftUICore
import FioriThemeManager
import SwiftUI

struct FilterFormViewExamples: View {
let valueOptions: [AttributedString] = ["itemShort", "itemLong", "item222222222222222222", "itemSuperLongLabelDescription", "itemShort2"]
let sortValueOptions: [AttributedString] = ["Received", "Started", "Hold", "Transfer", "Completed", "Pending Review Pending Pending Pending Pending Pending", "Accepted Medium", "Pending", "Completed Medium"]

let priorityOptions: [AttributedString] = ["High", "Medium", "Low"]
let numberOptions: [AttributedString] = ["1", "2", "3", "4"]

@State private var showMandatoryField = false
@State private var customizedMandatoryIndicator = false
@State private var isEnabled = true

@State private var multiSelectionEmptySelectionValue: [Int] = [1, 2]
@State private var multiSelectionNonEmptySelectionValue: [Int] = [1, 2]
@State private var singleSelectionEmptySelectionValue: [Int] = []
@State private var singleSelectionNonEmptySelectionValue: [Int] = []
@State private var singleSelectionNonEmptySelectionDisabledValue: [Int] = [1]
@State private var singleSelectionNonEmptySelectionCustomizedColorValue: [Int] = []

@State private var prioritySelectionValue: [Int] = [0]
@State private var numberSelectionValue: [Int] = [0]
@State private var trySixSelectionValue: [Int] = [0]
@State private var trySevenSelectionValue: [Int] = [0]
@State private var sortFilterSelectionValue: [Int] = [0]
@State private var sortFilterFixedSelectionValue: [Int] = [0]
@State private var sortFilterEmptyTitleSelectionValue: [Int] = [0]

func mandatoryField() -> TextOrIcon? {
if self.customizedMandatoryIndicator {
return .text("#")
} else {
return .text("*")
}
}

var body: some View {
List {
Toggle(isOn: self.$showMandatoryField) {
Text("Mandatory Field")
.font(.fiori(forTextStyle: .subheadline, weight: .semibold))
.foregroundStyle(Color.preferredColor(.primaryLabel))
}
.tint(Color.preferredColor(.tintColor))
Toggle(isOn: self.$customizedMandatoryIndicator) {
Text("Customized Mandatory Indicator")
.font(.fiori(forTextStyle: .subheadline, weight: .semibold))
.foregroundStyle(Color.preferredColor(.primaryLabel))
}
.tint(Color.preferredColor(.tintColor))
Toggle(isOn: self.$isEnabled) {
Text("Enabled")
.font(.fiori(forTextStyle: .subheadline, weight: .semibold))
.foregroundStyle(Color.preferredColor(.primaryLabel))
}
.tint(Color.preferredColor(.tintColor))

FilterFormView(title: "MultiSelection, EmptySelection", mandatoryFieldIndicator: self.mandatoryField(), isRequired: self.showMandatoryField, options: self.valueOptions, errorMessage: "Validation Message", isEnabled: self.isEnabled, allowsMultipleSelection: true, allowsEmptySelection: true, value: self.$multiSelectionEmptySelectionValue, buttonSize: .fixed, onValueChange: { value in
print("MultiSelection, EmptySelection value change: \(value)")
})
.mandatoryFieldIndicatorStyle { conf in
conf.mandatoryFieldIndicator
.foregroundStyle(self.mandatoryFieldIndicatorColor())
}
.informationViewStyle(.success)

FilterFormView(title: "MultiSelection, Non-EmptySelection", mandatoryFieldIndicator: self.mandatoryField(), isRequired: self.showMandatoryField, options: self.valueOptions, errorMessage: "Validation Message", isEnabled: self.isEnabled, allowsMultipleSelection: true, allowsEmptySelection: false, value: self.$multiSelectionNonEmptySelectionValue, buttonSize: .fixed)
.mandatoryFieldIndicatorStyle { conf in
conf.mandatoryFieldIndicator
.foregroundStyle(self.mandatoryFieldIndicatorColor())
}

FilterFormView(title: "SingleSelection, EmptySelection", mandatoryFieldIndicator: self.mandatoryField(), isRequired: self.showMandatoryField, options: self.valueOptions, errorMessage: "Validation Message", isEnabled: self.isEnabled, allowsMultipleSelection: false, allowsEmptySelection: true, value: self.$singleSelectionEmptySelectionValue, buttonSize: .fixed)
.mandatoryFieldIndicatorStyle { conf in
conf.mandatoryFieldIndicator
.foregroundStyle(self.mandatoryFieldIndicatorColor())
}

FilterFormView(title: "SingleSelection, Non-EmptySelection", mandatoryFieldIndicator: self.mandatoryField(), isRequired: self.showMandatoryField, options: self.valueOptions, errorMessage: "Validation Message", isEnabled: self.isEnabled, allowsMultipleSelection: false, allowsEmptySelection: false, value: self.$singleSelectionNonEmptySelectionValue, buttonSize: .fixed)
.mandatoryFieldIndicatorStyle { conf in
conf.mandatoryFieldIndicator
.foregroundStyle(self.mandatoryFieldIndicatorColor())
}

FilterFormView(title: "SingleSelection, Non-EmptySelection, Disabled", mandatoryFieldIndicator: self.mandatoryField(), isRequired: self.showMandatoryField, options: self.valueOptions, errorMessage: "Validation Message", isEnabled: false, allowsMultipleSelection: false, allowsEmptySelection: false, value: self.$singleSelectionNonEmptySelectionDisabledValue, buttonSize: .fixed)
.mandatoryFieldIndicatorStyle { conf in
conf.mandatoryFieldIndicator
.foregroundStyle(self.mandatoryFieldIndicatorColor())
}

FilterFormView(title: {
Text("SingleSelection, Non-EmptySelection, Customized Color, Font")
.foregroundStyle(self.isEnabled ? Color.red : .yellow)
}, mandatoryFieldIndicator: {
TextOrIconView(self.mandatoryField())
.foregroundStyle(self.isEnabled ? Color.green : .preferredColor(.separator))
}, isRequired: self.showMandatoryField, options: self.valueOptions, errorMessage: nil, isEnabled: self.isEnabled, allowsMultipleSelection: false, allowsEmptySelection: false, value: self.$singleSelectionNonEmptySelectionCustomizedColorValue, buttonSize: .fixed)
.mandatoryFieldIndicatorStyle { conf in
conf.mandatoryFieldIndicator
.foregroundStyle(self.mandatoryFieldIndicatorColor())
}
.filterFormOptionAttributes([
.enabledUnselected: [
.foregroundColor: Color.green,
.strokeColor: Color.yellow,
.font: Font.fiori(forTextStyle: .caption1)
],
.enabledSelected: [
.foregroundColor: Color.red,
.strokeColor: Color.orange,
.font: Font.fiori(forTextStyle: .caption1)
]
])

FilterFormView(title: "Priority", mandatoryFieldIndicator: self.mandatoryField(), isRequired: self.showMandatoryField, options: self.priorityOptions, errorMessage: nil, isEnabled: self.isEnabled, allowsMultipleSelection: true, allowsEmptySelection: true, value: self.$prioritySelectionValue, buttonSize: .flexibleByMaxChip)
.mandatoryFieldIndicatorStyle { conf in
conf.mandatoryFieldIndicator
.foregroundStyle(self.mandatoryFieldIndicatorColor())
}

FilterFormView(title: "Number", mandatoryFieldIndicator: self.mandatoryField(), isRequired: self.showMandatoryField, options: self.numberOptions, errorMessage: nil, isEnabled: self.isEnabled, allowsMultipleSelection: true, allowsEmptySelection: true, value: self.$numberSelectionValue, buttonSize: .flexibleByMaxChip)
.mandatoryFieldIndicatorStyle { conf in
conf.mandatoryFieldIndicator
.foregroundStyle(self.mandatoryFieldIndicatorColor())
}

FilterFormView(title: "SingleSelection, Non-EmptySelection, flexible, same size", mandatoryFieldIndicator: self.mandatoryField(), isRequired: self.showMandatoryField, options: self.valueOptions, errorMessage: nil, isEnabled: self.isEnabled, allowsMultipleSelection: true, allowsEmptySelection: true, value: self.$trySixSelectionValue, buttonSize: .flexibleByMaxChip)
.mandatoryFieldIndicatorStyle { conf in
conf.mandatoryFieldIndicator
.foregroundStyle(self.mandatoryFieldIndicatorColor())
}

FilterFormView(title: "SingleSelection, Non-EmptySelection, flexible", mandatoryFieldIndicator: self.mandatoryField(), isRequired: self.showMandatoryField, options: self.valueOptions, errorMessage: nil, isEnabled: self.isEnabled, allowsMultipleSelection: true, allowsEmptySelection: true, value: self.$trySevenSelectionValue, buttonSize: .flexible)
.mandatoryFieldIndicatorStyle { conf in
conf.mandatoryFieldIndicator
.foregroundStyle(self.mandatoryFieldIndicatorColor())
}

FilterFormView(title: "Sort Filter, MultiSelection, EmptySelection, flexible, no mandatory", mandatoryFieldIndicator: self.mandatoryField(), isRequired: false, options: self.sortValueOptions, errorMessage: nil, isEnabled: self.isEnabled, allowsMultipleSelection: true, allowsEmptySelection: true, value: self.$sortFilterSelectionValue, buttonSize: .flexible)
.mandatoryFieldIndicatorStyle { conf in
conf.mandatoryFieldIndicator
.foregroundStyle(self.mandatoryFieldIndicatorColor())
}
.filterFormOptionMinTouchHeight(50)
.filterFormOptionCornerRadius(16)
.filterFormOptionTitleSpacing(4)
.filterFormOptionPadding(EdgeInsets(top: 4, leading: 9, bottom: 4, trailing: 9))
.filterFormOptionAttributes([
.enabledUnselected: [
.strokeWidth: 1.0,
.strokeColor: Color.preferredColor(.separator),
.foregroundColor: Color.preferredColor(.tertiaryLabel),
.backgroundColor: Color.preferredColor(.tertiaryFill),
.font: Font.system(.body)
],
.enabledSelected: [
.strokeWidth: 1.0,
.strokeColor: Color.preferredColor(.tintColor),
.foregroundColor: Color.preferredColor(.tintColor),
.backgroundColor: Color.preferredColor(.secondaryGroupedBackground),
.font: Font.system(.body)
]
])

FilterFormView(title: "Sort Filter, MultiSelection, EmptySelection, fixed, no mandatory", mandatoryFieldIndicator: self.mandatoryField(), isRequired: false, options: self.sortValueOptions, errorMessage: nil, isEnabled: self.isEnabled, allowsMultipleSelection: true, allowsEmptySelection: true, value: self.$sortFilterFixedSelectionValue, buttonSize: .fixed)
.mandatoryFieldIndicatorStyle { conf in
conf.mandatoryFieldIndicator
.foregroundStyle(self.mandatoryFieldIndicatorColor())
}
.filterFormOptionMinTouchHeight(50)
.filterFormOptionCornerRadius(16)
.filterFormOptionTitleSpacing(4)
.filterFormOptionPadding(EdgeInsets(top: 4, leading: 9, bottom: 4, trailing: 9))
.filterFormOptionsItemSpacing(16)
.filterFormOptionsLineSpacing(10)
.filterFormOptionAttributes([
.enabledUnselected: [
.strokeWidth: 1.0,
.strokeColor: Color.preferredColor(.separator),
.foregroundColor: Color.preferredColor(.tertiaryLabel),
.backgroundColor: Color.preferredColor(.tertiaryFill),
.font: Font.system(.body)
],
.enabledSelected: [
.strokeWidth: 1.0,
.strokeColor: Color.preferredColor(.tintColor),
.foregroundColor: Color.preferredColor(.tintColor),
.backgroundColor: Color.preferredColor(.secondaryGroupedBackground),
.font: Font.system(.body)
]
])

// Empty title and mandatory
FilterFormView(title: {
EmptyView()
}, mandatoryFieldIndicator: {
EmptyView()
}, isRequired: false, options: self.sortValueOptions, isEnabled: self.isEnabled, allowsMultipleSelection: true, allowsEmptySelection: true, value: self.$sortFilterEmptyTitleSelectionValue, buttonSize: .flexible)
.filterFormOptionMinTouchHeight(50)
.filterFormOptionCornerRadius(16)
.filterFormOptionTitleSpacing(4)
.filterFormOptionPadding(EdgeInsets(top: 4, leading: 9, bottom: 4, trailing: 9))
.filterFormOptionAttributes([
.enabledUnselected: [
.strokeWidth: 1.0,
.strokeColor: Color.preferredColor(.separator),
.foregroundColor: Color.preferredColor(.tertiaryLabel),
.backgroundColor: Color.preferredColor(.tertiaryFill),
.font: Font.system(.body)
],
.enabledSelected: [
.strokeWidth: 1.0,
.strokeColor: Color.preferredColor(.tintColor),
.foregroundColor: Color.preferredColor(.tintColor),
.backgroundColor: Color.preferredColor(.secondaryGroupedBackground),
.font: Font.system(.body)
]
])
}
.listStyle(.plain)
}

func mandatoryFieldIndicatorColor() -> Color {
if !self.isEnabled {
return .preferredColor(.separator)
} else {
return self.customizedMandatoryIndicator ? Color.red : Color.preferredColor(.primaryLabel)
}
}
}

#Preview {
FilterFormViewExamples()
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ struct FormViewExamples: View {
{
Text("RatingControlFormView Example")
}
NavigationLink {
FilterFormViewExamples()
} label: {
Text("FilterFormView Example")
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import SwiftUI

struct TextFieldFormViewExample: View {
var key1: AttributedString {
let aString = AttributedString("Key 1")
let aString = AttributedString("Long Key 1 Long Key 1 Long Key 1 Long Key 1 Long Key 1 Long Key 1 Long Key 1 Long Key 1 Long Key 1 Long Key 1 ")
return aString
}

Expand Down
11 changes: 11 additions & 0 deletions Sources/FioriSwiftUICore/Utils/FilterForm.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import Foundation

/// Size of `FUIFilterFormView` button
public enum FilterButtonSize {
/// Items will be displayed in two columns, each column's width will be 50% of available space.
case fixed
/// Items will be displayed in sequence, each item size will be decided by its own content.
case flexible
/// Items will be displayed in sequence, each item size will be the same as the chip size with largest content.
case flexibleByMaxChip
}
Loading
Loading