Skip to content

Commit

Permalink
feat: 🎸 [JIRA:IOSSDKBUG-413] FilterFeedbackBar in visionOS
Browse files Browse the repository at this point in the history
  • Loading branch information
hengyi-zhang committed Oct 31, 2024
2 parents dcbf398 + 359d846 commit 7a9a1b7
Show file tree
Hide file tree
Showing 14 changed files with 175 additions and 60 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import SwiftUI

struct StepperViewExample: View {
@State var normalStepValue = "3"
@State var doubleStepValue = "6.0"
@State var multipleDigits = "6.895"
@State var longTitleStepValue = "3"
@State var customStyleStepValue = "3"
@State var noFocusValue = "79"
Expand Down Expand Up @@ -37,13 +39,34 @@ struct StepperViewExample: View {
)
.disabled(self.isDisabled)

StepperView(
title: { Text("Value") },
text: self.$doubleStepValue,
step: 0.5,
stepRange: 0.5 ... 80.5,
isDecimalSupported: true,
description: { Text("Double Value") }
)
.disabled(self.isDisabled)

StepperView(
title: { Text("Value") },
text: self.$multipleDigits,
step: 0.005,
stepRange: 0.005 ... 80.895,
isDecimalSupported: true,
description: { Text("Multi-digit Double Value") }
)
.disabled(self.isDisabled)

StepperView(
title: { Text("Value") },
text: self.$negativeValue,
stepRange: 10 ... 100,
description: { Text(self.isInputValueValid ? "Hint Text" : "Validation failed.") }
).onChange(of: self.negativeValue, perform: { value in
if Int(value) ?? 1 > 80 {
let cValue = Double(value) ?? 10
if cValue > 80 || cValue < 20 {
self.isInputValueValid = false
} else {
self.isInputValueValid = true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@ struct SortFilterExample: View {
[
.switch(item: .init(name: "Favorite", value: true, icon: "heart.fill"), showsOnFilterFeedbackBar: true),
.switch(item: .init(name: "Tagged", value: nil, icon: "tag"), showsOnFilterFeedbackBar: false),
.picker(item: .init(name: "JIRA Status", value: [0], valueOptions: ["Received", "Started", "Hold", "Transfer", "Completed", "Pending Review Pending Pending Pending Pending Pending", "Accepted Medium", "Pending Medium", "Completed Medium"], allowsMultipleSelection: true, allowsEmptySelection: true, showsValueForSingleSelected: false, icon: "clock", itemLayout: .fixed, displayMode: .automatic), showsOnFilterFeedbackBar: true)
.picker(item: .init(name: "List Few JIRA Status", value: [0], valueOptions: ["Received", "Started", "Hold", "Transfer", "Completed", "Pending Review Pending Pending Pending Pending Pending", "Accepted Medium", "Pending Medium", "Completed Medium"], allowsMultipleSelection: true, allowsEmptySelection: true, showsValueForSingleSelected: false, icon: "clock", itemLayout: .fixed, displayMode: .list), showsOnFilterFeedbackBar: true),
.picker(item: .init(name: "List Many JIRA Status", value: [0], valueOptions: ["Received", "Started", "Hold", "Transfer", "Completed", "Pending Review Pending Pending Pending Pending Pending", "Accepted Medium", "Pending Medium", "Completed Medium", "Checked", "Unchecked", "Partially Checked", "Checked and Unchecked", "Checked and Partially Checked", "Unchecked and Partially Checked", "Partially Checked and Unchecked", "Checked and Unchecked and Partially Checked", "Unchecked and Partially Checked and Partially Checked", "Partially Checked and Unchecked and Partially Checked", "Checked Finally", "Unchecked Finally", "Partially Checked Finally", "Checked and Unchecked Finally", "Checked and Partially Checked Finally", "Unchecked and Partially Checked Finally", "Partially Checked and Unchecked Finally", "Checked Finally and Partially Checked Finally", "Unchecked Finally and Partially Checked Finally", "Partially Checked Finally and Partially Checked Finally", "Review", "Reviewed", "To be Reviewed", "Pending for Review", "Booked", "To be Booked", "Will Book", "Booking Canceled"], allowsMultipleSelection: true, allowsEmptySelection: true, showsValueForSingleSelected: false, icon: "clock", itemLayout: .fixed, displayMode: .list), showsOnFilterFeedbackBar: true),
.picker(item: .init(name: "FormCell Flexible Filter Selection", value: [0], valueOptions: ["Received", "Started", "Hold", "Transfer", "Completed", "Pending Review Pending Pending Pending Pending Pending", "Accepted Medium", "Pending", "Completed Medium"], allowsMultipleSelection: true, allowsEmptySelection: true, showsValueForSingleSelected: false, icon: "clock", itemLayout: .flexible, displayMode: .filterFormCell), showsOnFilterFeedbackBar: true),
.picker(item: .init(name: "FormCell Fixed Few Filter Selection", value: [0], valueOptions: ["Received", "Started", "Hold", "Transfer", "Completed", "Pending Review Pending Pending Pending Pending Pending"], allowsMultipleSelection: true, allowsEmptySelection: true, showsValueForSingleSelected: false, icon: "clock", itemLayout: .fixed, displayMode: .filterFormCell), showsOnFilterFeedbackBar: true),
.picker(item: .init(name: "FormCell Fixed Many Filter Selection", value: [0], valueOptions: ["Received", "Started", "Hold", "Transfer", "Completed", "Pending Review Pending Pending Pending Pending Pending", "Accepted Medium", "Pending Medium", "Completed Medium", "Checked", "Unchecked", "Partially Checked", "Checked and Unchecked", "Checked and Partially Checked", "Unchecked and Partially Checked", "Partially Checked and Unchecked", "Checked and Unchecked and Partially Checked", "Unchecked and Partially Checked and Partially Checked", "Partially Checked and Unchecked and Partially Checked", "Checked Finally", "Unchecked Finally", "Partially Checked Finally", "Checked and Unchecked Finally", "Checked and Partially Checked Finally", "Unchecked and Partially Checked Finally", "Partially Checked and Unchecked Finally", "Checked Finally and Partially Checked Finally", "Unchecked Finally and Partially Checked Finally", "Partially Checked Finally and Partially Checked Finally", "Review", "Reviewed", "To be Reviewed", "Pending for Review", "Booked", "To be Booked", "Will Book", "Booking Canceled"], allowsMultipleSelection: true, allowsEmptySelection: true, showsValueForSingleSelected: false, icon: "clock", itemLayout: .fixed, displayMode: .filterFormCell), showsOnFilterFeedbackBar: true)
],
[
.picker(item: .init(name: "Priority", value: [0], valueOptions: ["High", "Medium", "Low"], allowsMultipleSelection: true, allowsEmptySelection: true, showsValueForSingleSelected: false, icon: "filemenu.and.cursorarrow"), showsOnFilterFeedbackBar: true),
Expand Down
17 changes: 15 additions & 2 deletions Sources/FioriSwiftUICore/Views/OptionListPickerItem+View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ extension OptionListPickerItem: View {
let popverHeight = Screen.bounds.size.height - StatusBar.height
let totalSpacing: CGFloat = (UIDevice.current.userInterfaceIdiom == .pad ? 8 : 16) * 2
let totalPadding: CGFloat = (UIDevice.current.userInterfaceIdiom == .pad ? 13 : 16) * 2
let maxScrollViewHeight = popverHeight - totalSpacing - totalPadding - 120
let safeAreaInset = self.getSafeAreaInsets()
let maxScrollViewHeight = popverHeight - totalSpacing - totalPadding - safeAreaInset.top - safeAreaInset.bottom - (UIDevice.current.userInterfaceIdiom == .pad ? 210 : 30)
self._height = min(geometry.size.height, maxScrollViewHeight)
}
}
Expand Down Expand Up @@ -94,14 +95,26 @@ extension OptionListPickerItem: View {
let popverHeight = Screen.bounds.size.height - StatusBar.height
let totalSpacing: CGFloat = (UIDevice.current.userInterfaceIdiom == .pad ? 8 : 16) * 2
let totalPadding: CGFloat = (UIDevice.current.userInterfaceIdiom == .pad ? 13 : 16) * 2
let maxScrollViewHeight = popverHeight - totalSpacing - totalPadding - 120
let safeAreaInset = self.getSafeAreaInsets()
let maxScrollViewHeight = popverHeight - totalSpacing - totalPadding - safeAreaInset.top - safeAreaInset.bottom - (UIDevice.current.userInterfaceIdiom == .pad ? 210 : 30)
self._height = min(geometry.size.height, maxScrollViewHeight)
}
}
)
}
.frame(height: _height)
}

private func getSafeAreaInsets() -> UIEdgeInsets {
guard let keyWindow = UIApplication.shared.connectedScenes
.first(where: { $0.activationState == .foregroundActive })
.flatMap({ $0 as? UIWindowScene })?.windows
.first(where: \.isKeyWindow)
else {
return .zero
}
return keyWindow.safeAreaInsets
}
}

/*
Expand Down
20 changes: 17 additions & 3 deletions Sources/FioriSwiftUICore/Views/SearchListPickerItem+View.swift
Original file line number Diff line number Diff line change
Expand Up @@ -59,13 +59,16 @@ extension SearchListPickerItem: View {
}
}
.modifier(FioriIntrospectModifier<UIScrollView> { scrollView in
if !_searchText.isEmpty {
return
}
DispatchQueue.main.async {
let popverHeight = Screen.bounds.size.height - StatusBar.height
let totalSpacing: CGFloat = (UIDevice.current.userInterfaceIdiom == .pad ? 8 : 16) * 2
let totalPadding: CGFloat = (UIDevice.current.userInterfaceIdiom == .pad ? 13 : 16) * 2
let maxScrollViewHeight = popverHeight - totalSpacing - totalPadding - 52 - 56 - 120

self._height = UIDevice.current.userInterfaceIdiom != .phone ? min(scrollView.contentSize.height, 396) : min(min(scrollView.contentSize.height, maxScrollViewHeight), 396)
let safeAreaInset = self.getSafeAreaInsets()
let maxScrollViewHeight = popverHeight - totalSpacing - totalPadding - 52 - 56 - safeAreaInset.top - safeAreaInset.bottom - (UIDevice.current.userInterfaceIdiom == .pad ? 230 : 30)
self._height = min(scrollView.contentSize.height, maxScrollViewHeight)
var isSelectAllViewShow = false
if allowsMultipleSelection {
if _value.count != _valueOptions.count || allowsEmptySelection {
Expand Down Expand Up @@ -111,6 +114,17 @@ extension SearchListPickerItem: View {
private func findIndex(of item: String) -> Int? {
_valueOptions.firstIndex(where: { $0 == item })
}

private func getSafeAreaInsets() -> UIEdgeInsets {
guard let keyWindow = UIApplication.shared.connectedScenes
.first(where: { $0.activationState == .foregroundActive })
.flatMap({ $0 as? UIWindowScene })?.windows
.first(where: \.isKeyWindow)
else {
return .zero
}
return keyWindow.safeAreaInsets
}
}

#Preview {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ public struct DefaultFilterFeedbackBarStyle: FilterFeedbackBarStyle {
RoundedRectangle(cornerRadius: self.cornerRadius)
.fill(configuration.isSelected ? self.fillColorSelected : self.fillColorUnselected)
RoundedRectangle(cornerRadius: self.cornerRadius)
.stroke(configuration.isSelected ? self.strokeColorSelected : self.strokeColorUnselected, lineWidth: self.borderWidth)
.strokeBorder(configuration.isSelected ? self.strokeColorSelected : self.strokeColorUnselected, lineWidth: self.borderWidth)
}
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ struct SliderMenuItem: View {
.onTapGesture {
self.isSheetVisible.toggle()
}
.popover(isPresented: self.$isSheetVisible, attachmentAnchor: .point(.bottom)) {
.popover(isPresented: self.$isSheetVisible) {
CancellableResettableDialogForm {
SortFilterItemTitle(title: self.item.name)
} cancelAction: {
Expand Down Expand Up @@ -153,7 +153,7 @@ struct PickerMenuItem: View {
.onTapGesture {
self.isSheetVisible.toggle()
}
.popover(isPresented: self.$isSheetVisible, attachmentAnchor: .point(.bottom)) {
.popover(isPresented: self.$isSheetVisible) {
CancellableResettableDialogForm {
SortFilterItemTitle(title: self.item.name)
} cancelAction: {
Expand Down Expand Up @@ -224,7 +224,7 @@ struct PickerMenuItem: View {
.onTapGesture {
self.isSheetVisible.toggle()
}
.popover(isPresented: self.$isSheetVisible, attachmentAnchor: .point(.bottom)) {
.popover(isPresented: self.$isSheetVisible) {
CancellableResettableDialogNavigationForm {
SortFilterItemTitle(title: self.item.name)
} cancelAction: {
Expand Down Expand Up @@ -252,7 +252,7 @@ struct PickerMenuItem: View {
} selectAll: { isAll in
self.item.selectAll(isAll)
} updateSearchListPickerHeight: { height in
self.detentHeight = height
self.detentHeight = max(height, 88)
}
.frame(maxHeight: UIDevice.current.userInterfaceIdiom != .phone ? (self.detentHeight) : nil)
.padding(0)
Expand Down Expand Up @@ -311,7 +311,7 @@ struct DateTimeMenuItem: View {
.onTapGesture {
self.isSheetVisible.toggle()
}
.popover(isPresented: self.$isSheetVisible, attachmentAnchor: .point(.bottom)) {
.popover(isPresented: self.$isSheetVisible) {
CancellableResettableDialogForm {
SortFilterItemTitle(title: self.item.name)
} cancelAction: {
Expand Down Expand Up @@ -448,7 +448,7 @@ struct FullCFGMenuItem: View {
.onTapGesture {
self.isSheetVisible.toggle()
}
.popover(isPresented: self.$isSheetVisible, attachmentAnchor: .point(.bottom)) {
.popover(isPresented: self.$isSheetVisible) {
SortFilterView(
title: {
if let title = fullCFGButton.name {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,14 @@ protocol _JouleWelcomeScreen: _MediaImageComponent, _GreetingTextComponent, _Tit
protocol _StepperFieldComponent: _DecrementActionComponent, _TextInputFieldComponent, _IncrementActionComponent {
/// The step value
// sourcery: defaultValue = 1
var step: Int { get }
var step: Double { get }

/// a range of values
var stepRange: ClosedRange<Int> { get }
var stepRange: ClosedRange<Double> { get }

/// Indicates whether the stepper field supports decimal values. Default is false.
// sourcery: defaultValue = false
var isDecimalSupported: Bool { get }
}

// sourcery: CompositeComponent
Expand Down
Loading

0 comments on commit 7a9a1b7

Please sign in to comment.