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

feat: 🎸 jira 2286 sort & filter for SwiftUI project #606

Merged
merged 28 commits into from
Nov 7, 2023
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
c37aeea
feat: 🎸 jira 2286 sort & filter for SwiftUI project
CharlesXu0488 Oct 19, 2023
84cf550
feat: 🎸 jira 2286 sort & filter for SwiftUI project
CharlesXu0488 Oct 19, 2023
03c47ac
feat: 🎸 jira 2286 sort & filter for SwiftUI project
CharlesXu0488 Oct 19, 2023
de5da24
refactoring
CharlesXu0488 Oct 25, 2023
6410aca
Merge branch 'main' into HCPSDKFIORIUIKIT-2286
CharlesXu0488 Oct 25, 2023
8b5090e
merge changes from upstream
CharlesXu0488 Oct 25, 2023
f04f846
merge changes from upstream
CharlesXu0488 Oct 25, 2023
1785af7
refactor
CharlesXu0488 Oct 26, 2023
f243943
Support disabled reset button and refactor
CharlesXu0488 Nov 1, 2023
249753a
renaming
CharlesXu0488 Nov 1, 2023
2535965
improvement for designer review
CharlesXu0488 Nov 2, 2023
6d5847d
Merge branch 'main' into HCPSDKFIORIUIKIT-2286
dyongxu Nov 3, 2023
f972c89
improvement for designer review 2
CharlesXu0488 Nov 3, 2023
91bf3b8
refactor & review
CharlesXu0488 Nov 6, 2023
e1c53a4
refactor & review
CharlesXu0488 Nov 6, 2023
d91e089
refactor & review
CharlesXu0488 Nov 6, 2023
d9299a1
refactor & review
CharlesXu0488 Nov 6, 2023
fd06d01
refactor & review
CharlesXu0488 Nov 6, 2023
df22b57
refactor & review
CharlesXu0488 Nov 6, 2023
2bf467b
refactor & review
CharlesXu0488 Nov 6, 2023
0bdb1d1
refactor & review
CharlesXu0488 Nov 6, 2023
4877f63
refactor & review
CharlesXu0488 Nov 6, 2023
1ff5554
refactor & review
CharlesXu0488 Nov 6, 2023
32ec328
refactor & review
CharlesXu0488 Nov 6, 2023
839db8f
refactor & review
CharlesXu0488 Nov 6, 2023
48feea9
Merge branch 'main' into HCPSDKFIORIUIKIT-2286
CharlesXu0488 Nov 6, 2023
4c9caf6
feat: refactor & review
CharlesXu0488 Nov 6, 2023
83316d9
Merge branch 'HCPSDKFIORIUIKIT-2286' of github.com:CharlesXu0488/clou…
CharlesXu0488 Nov 7, 2023
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
24 changes: 20 additions & 4 deletions Apps/Examples/Examples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@
B8D4376F25F980340024EE7D /* ObjectCell_Spec_Jan2018.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D4376E25F980340024EE7D /* ObjectCell_Spec_Jan2018.swift */; };
B8D4377125F983730024EE7D /* ObjectCell_Rules_Alignment.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D4377025F983730024EE7D /* ObjectCell_Rules_Alignment.swift */; };
B8D437732609479E0024EE7D /* SingleActionFollowButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = B8D437722609479E0024EE7D /* SingleActionFollowButton.swift */; };
C1A0FDB32AD893FA0001738E /* SortFilterView+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1A0FDB22AD893FA0001738E /* SortFilterView+Extensions.swift */; };
C1C764882A818BEC00BCB0F7 /* SortFilterExample.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1C764872A818BEC00BCB0F7 /* SortFilterExample.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -240,6 +242,8 @@
B8D4376E25F980340024EE7D /* ObjectCell_Spec_Jan2018.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectCell_Spec_Jan2018.swift; sourceTree = "<group>"; };
B8D4377025F983730024EE7D /* ObjectCell_Rules_Alignment.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ObjectCell_Rules_Alignment.swift; sourceTree = "<group>"; };
B8D437722609479E0024EE7D /* SingleActionFollowButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SingleActionFollowButton.swift; sourceTree = "<group>"; };
C1A0FDB22AD893FA0001738E /* SortFilterView+Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SortFilterView+Extensions.swift"; sourceTree = "<group>"; };
C1C764872A818BEC00BCB0F7 /* SortFilterExample.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SortFilterExample.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -423,6 +427,7 @@
8A5579C824C1293C0098003A /* FioriSwiftUICore */ = {
isa = PBXGroup;
children = (
C1C764862A818BD600BCB0F7 /* SortFilter */,
B100639129C0623300AF0CA2 /* StepProgressIndicator */,
108E43D3292DAB3E006532F3 /* EmptyStateView */,
B1D41B1E291A2D2E004E64A5 /* Picker */,
Expand Down Expand Up @@ -575,6 +580,15 @@
path = ObjectItem;
sourceTree = "<group>";
};
C1C764862A818BD600BCB0F7 /* SortFilter */ = {
isa = PBXGroup;
children = (
C1C764872A818BEC00BCB0F7 /* SortFilterExample.swift */,
C1A0FDB22AD893FA0001738E /* SortFilterView+Extensions.swift */,
);
path = SortFilter;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
Expand Down Expand Up @@ -728,6 +742,7 @@
8A557A2424C12F380098003A /* ChartDetailView.swift in Sources */,
8A5579D024C1293C0098003A /* SettingsLine.swift in Sources */,
1FC30412270540FB004BEE00 /* 72-Fonts.swift in Sources */,
C1A0FDB32AD893FA0001738E /* SortFilterView+Extensions.swift in Sources */,
B84D24ED2652F343007F2373 /* HeaderChartExample.swift in Sources */,
B100639329C0624D00AF0CA2 /* StepProgressIndicatorExample.swift in Sources */,
B846F94626815CC90085044B /* ContactItemExample.swift in Sources */,
Expand Down Expand Up @@ -777,6 +792,7 @@
8A5579D524C1293C0098003A /* SettingsSeries.swift in Sources */,
8A557A2224C12C9B0098003A /* CoreContentView.swift in Sources */,
8A5579D224C1293C0098003A /* Color+Extensions.swift in Sources */,
C1C764882A818BEC00BCB0F7 /* SortFilterExample.swift in Sources */,
B84D24EF2652F343007F2373 /* ObjectHeaderTestApp.swift in Sources */,
B84D24EC2652F343007F2373 /* ObjectHeaderSpecCompact.swift in Sources */,
8A5579CD24C1293C0098003A /* SettingsLabel.swift in Sources */,
Expand Down Expand Up @@ -920,7 +936,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
Expand Down Expand Up @@ -975,7 +991,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
Expand All @@ -995,7 +1011,7 @@
DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = Examples/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand All @@ -1017,7 +1033,7 @@
DEVELOPMENT_TEAM = "";
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = Examples/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ struct CoreContentView: View {
destination: EmptyStateViewExample()) {
Text("EmptyStateViewExample")
}

NavigationLink(destination: SortFilterExample()) {
Text("SortFilterExample")
}
}
}.navigationBarTitle("FioriSwiftUICore")
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import FioriSwiftUICore
import SwiftUI

struct SortFilterExample: View {
@State private var items: [[SortFilterItem]] = [
[
.switch(item: .init(name: "Favorite", value: true, icon: "heart.fill"), isShownOnMenu: true),
CharlesXu0488 marked this conversation as resolved.
Show resolved Hide resolved
.switch(item: .init(name: "Tagged", value: nil, icon: "tag"), isShownOnMenu: false),
.picker(item: .init(value: [0], valueOptions: ["Received", "Started", "Hold", "Transfer", "Completed", "Pending Review", "Accepted", "Rejected"], name: "JIRA Status", allowsMultipleSelection: true, allowsEmptySelection: true, icon: "clock"), isShownOnMenu: true)
CharlesXu0488 marked this conversation as resolved.
Show resolved Hide resolved
],
[
.picker(item: .init(value: [0], valueOptions: ["High", "Medium", "Low"], name: "Priority", allowsMultipleSelection: true, allowsEmptySelection: true, icon: "filemenu.and.cursorarrow"), isShownOnMenu: true),
.filterfeedback(item: .init(value: [0], valueOptions: ["Ascending", "Descending"], name: "Sort Order", allowsMultipleSelection: false, allowsEmptySelection: false, icon: "checkmark"))
],
[
.slider(item: .init(value: 10, minimumValue: 0, maximumValue: 100, name: "User Stories", formatter: "%2d Stories", icon: "number"), isShownOnMenu: true),
.slider(item: .init(value: nil, minimumValue: 0, maximumValue: 100, name: "Number of Tasks"), isShownOnMenu: true),
.datetime(item: .init(value: Date(), name: "Start Date", formatter: "yyyy-MM-dd HH:mm",icon: "calendar"), isShownOnMenu: true)
],
[
.datetime(item: .init(value: nil, name: "Completion Date"), isShownOnMenu: true)
]
]

@State private var isShowingFullCFG: Bool = false
@State private var isCustomStyle: Bool = false
@State private var sortFilterList: [String] = []
@State private var sortFilterButtonLabel: String = "Sort & Filter"

var body: some View {
VStack {
if isCustomStyle {
SortFilterMenu(items: $items, onUpdate: performSortAndFilter)
CharlesXu0488 marked this conversation as resolved.
Show resolved Hide resolved
.sortFilterMenuItemStyle(font: .subheadline, foregroundColorSelected: .red, strokeColorSelected: .red, cornerRadius: 25)
.optionChipStyle(font: .footnote, foregroundColorUnselected: .green, strokeColorSelected: .black)
// .trailingFullConfigurationMenuItem(icon: "command")
// .leadingFullConfigurationMenuItem(icon: "command")
// .leadingFullConfigurationMenuItem(name: "All")
} else {
SortFilterMenu(items: $items, onUpdate: performSortAndFilter)
}

List {
ForEach(sortFilterList, id: \.self) { line in
Text(line)
}
}
.listStyle(PlainListStyle())

HStack {
Toggle("Custom Style", isOn: $isCustomStyle)
.fixedSize()
.toggleStyle(FioriToggleStyle())

Button("Print") {
for line in sortFilterList {
print(line)
}
}
}
}
.navigationTitle("Sort & Filter")
.toolbar {
Button(sortFilterButtonLabel) {
isShowingFullCFG.toggle()
}
.popover(isPresented: $isShowingFullCFG, arrowEdge: .leading) {
if isCustomStyle {
SortFilterFullCFG(
CharlesXu0488 marked this conversation as resolved.
Show resolved Hide resolved
title: "Configuration",
items: $items,
onUpdate: performSortAndFilter
)
.optionChipStyle(font: .footnote, foregroundColorUnselected: .green, strokeColorSelected: .black)
CharlesXu0488 marked this conversation as resolved.
Show resolved Hide resolved
} else {
SortFilterFullCFG(
title: "Configuration",
items: $items,
onUpdate: performSortAndFilter
)
}
}
}
.onAppear {
performSortAndFilter()
}
}

func numberOfItems() -> Int {
// randomly padding result to mimic impact of filterring
for i in 0 ... Int.random(in: 0 ... 5) {
self.sortFilterList.append("padding element \(i + 1)")
}
return self.sortFilterList.count
}

func performSortAndFilter() {
self.sortFilterList = self.items.joined().map { value(of: $0) }
self.sortFilterButtonLabel = "CFG (\(self.numberOfItems()))"
}
}

#if DEBUG
@available(iOS 16.0, *)
struct SortFilterExample_Previews: PreviewProvider {
static var previews: some View {
SortFilterExample()
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import FioriSwiftUICore
import SwiftUI

extension View {
func value(of item: SortFilterItem) -> String {
switch item {
case .picker(let v, _):
return self.json(item: v)
case .filterfeedback(let v):
return self.json(item: v)
case .slider(let v, _):
return self.json(item: v)
case .datetime(let v, _):
return self.json(item: v)
case .switch(let v, _):
return self.json(item: v)
}
}

func json(item: PickerItem) -> String {
"{name: \(item.name), value: \(item.value)}"
}

func json(item: SliderItem) -> String {
"{name: \(item.name), value: \(String(describing: item.value))}"
}

func json(item: DateTimeItem) -> String {
"{name: \(item.name), value: \(String(describing: item.value))}"
}

func json(item: SwitchItem) -> String {
"{name: \(item.name), value: \(String(describing: item.value))}"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "icon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import PackageDescription
let package = Package(
name: "FioriSwiftUI",
defaultLocalization: "en",
platforms: [.iOS(.v15), .watchOS(.v7)],
platforms: [.iOS(.v16), .watchOS(.v7)],
products: [
.library(
name: "FioriSwiftUI",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import Foundation
import SwiftUI

struct CancellableResettableDialogForm<Title: View, CancelAction: View, ResetAction: View, ApplyAction: View, Components: View>: View {
let title: Title

let components: Components

var cancelAction: CancelAction
var resetAction: ResetAction
var applyAction: ApplyAction

public init(@ViewBuilder title: () -> Title,
@ViewBuilder cancelAction: () -> CancelAction,
@ViewBuilder resetAction: () -> ResetAction,
@ViewBuilder applyAction: () -> ApplyAction,
@ViewBuilder components: () -> Components)
{
self.title = title()
self.cancelAction = cancelAction()
self.resetAction = resetAction()
self.applyAction = applyAction()
self.components = components()
}

var body: some View {
VStack(spacing: UIDevice.current.userInterfaceIdiom == .pad ? 8 : 16) {
HStack {
cancelAction
Spacer()
title
Spacer()
resetAction
}
components
applyAction
}
.frame(width: UIDevice.current.userInterfaceIdiom == .pad ? 375: UIScreen.main.bounds.size.width - 32)
.padding([.leading, .trailing], 16)
.padding([.top, .bottom], UIDevice.current.userInterfaceIdiom == .pad ? 13 : 16)
}
}

struct ApplyButtonStyle: PrimitiveButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.frame(minWidth: UIDevice.current.userInterfaceIdiom == .pad ? 375 : 200, maxWidth: .infinity)
.padding(8)
.font(.body)
.fontWeight(.bold)
.foregroundStyle(Color.preferredColor(.base2))
.background(RoundedRectangle(cornerRadius: 8).fill(Color.preferredColor(.tintColor)))
.onTapGesture {
configuration.trigger()
}
.padding([.top, .bottom], UIDevice.current.userInterfaceIdiom == .pad ? 16 : 8)
}
}

struct CancelResetButtonStyle: PrimitiveButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.font(.body)
.fontWeight(.bold)
.foregroundStyle(Color.preferredColor(.tintColor))
.onTapGesture {
configuration.trigger()
}
}
}

#Preview {
VStack {
Spacer()
CancellableResettableDialogForm {
Text("Date of Completion")
} cancelAction: {
Action(actionText: "Cancel", didSelectAction: nil)
} resetAction: {
Action(actionText: "Reset", didSelectAction: nil)
} applyAction: {
Action(actionText: "Apply", didSelectAction: nil)
.buttonStyle(ApplyButtonStyle())
} components: {
DatePicker(
"date",
selection: Binding<Date>(get: { Date() }, set: { print($0) }),
displayedComponents: [.date]
)
.datePickerStyle(.graphical)
}
}
}
Loading
Loading