From a70317b4e4d3fb4e344c3f2e1dce46359c34e9d1 Mon Sep 17 00:00:00 2001 From: "Gu, Jiajun (external - Project)" Date: Fri, 21 Feb 2025 10:38:45 +0800 Subject: [PATCH 1/3] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20[HCPSDKFIORIUIKI?= =?UTF-8?q?T-2891]FilterFeedbackbar=20FilterForm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../DataTypes/SortFilter+DataType.swift | 23 +++- .../Models/ModelDefinitions.swift | 12 ++ .../Views/OptionListPickerItem+View.swift | 120 +++--------------- .../FilterFeedbackBarItemSubview.swift | 91 ++++++++++--- .../_FilterFeedbackBarItem+View.swift | 2 +- .../OptionListPickerItem+API.generated.swift | 14 +- ...PickerItemModel+Extensions.generated.swift | 14 +- 7 files changed, 149 insertions(+), 127 deletions(-) diff --git a/Sources/FioriSwiftUICore/DataTypes/SortFilter+DataType.swift b/Sources/FioriSwiftUICore/DataTypes/SortFilter+DataType.swift index 9fac66d49..dc9edaecd 100644 --- a/Sources/FioriSwiftUICore/DataTypes/SortFilter+DataType.swift +++ b/Sources/FioriSwiftUICore/DataTypes/SortFilter+DataType.swift @@ -408,6 +408,7 @@ public extension SortFilterItem { struct PickerItem: Identifiable, Equatable { public let id: String public var name: String + public var title: String? public var value: [Int] public var workingValue: [Int] let originalValue: [Int] @@ -461,9 +462,29 @@ public extension SortFilterItem { case disable } - public init(id: String = UUID().uuidString, name: String, value: [Int], valueOptions: [String], allowsMultipleSelection: Bool, allowsEmptySelection: Bool, barItemDisplayMode: BarItemDisplayMode = .name, isSearchBarHidden: Bool = false, icon: String? = nil, itemLayout: OptionListPickerItemLayoutType = .fixed, displayMode: DisplayMode = .automatic, listEntriesSectionMode: ListEntriesSectionMode = .default, allowsDisplaySelectionCount: Bool = true, resetButtonConfiguration: FilterFeedbackBarResetButtonConfiguration = FilterFeedbackBarResetButtonConfiguration()) { + /// Create PickerItem for filter feedback. + /// When `displayMode` is `.filterFormCell`, the styles of options can be customized by some styles of FilterFormView, such as: + /// filterFormOptionAttributes, filterFormOptionMinHeight, filterFormOptionMinTouchHeight, filterFormOptionCornerRadius, filterFormOptionPadding, filterFormOptionTitleSpacing, filterFormOptionsItemSpacing, filterFormOptionsLineSpacing. + /// - Parameters: + /// - id: The unique identifier for PickerItem. + /// - name: Item name. + /// - title: Title label of the options. + /// - value: Item selected value. + /// - valueOptions: Item options. + /// - allowsMultipleSelection: A boolean value to indicate to allow multiple selections or not. + /// - allowsEmptySelection: A boolean value to indicate to allow empty selections or not. + /// - barItemDisplayMode: Name display mode for the bar. + /// - isSearchBarHidden: A boolean value to indicate to search bar hidden or not. + /// - icon: Icon at the left of the item. + /// - itemLayout: Options layout type when `displayMode` is `.filterFormCell`. + /// - displayMode: Options display mode. + /// - listEntriesSectionMode: List entries section mode when `displayMode` is `.list`. + /// - allowsDisplaySelectionCount: A boolean value to indicate to allow display selection count or not. + /// - resetButtonConfiguration: A configuration to customize the reset button. + public init(id: String = UUID().uuidString, name: String, title: String? = nil, value: [Int], valueOptions: [String], allowsMultipleSelection: Bool, allowsEmptySelection: Bool, barItemDisplayMode: BarItemDisplayMode = .name, isSearchBarHidden: Bool = false, icon: String? = nil, itemLayout: OptionListPickerItemLayoutType = .fixed, displayMode: DisplayMode = .automatic, listEntriesSectionMode: ListEntriesSectionMode = .default, allowsDisplaySelectionCount: Bool = true, resetButtonConfiguration: FilterFeedbackBarResetButtonConfiguration = FilterFeedbackBarResetButtonConfiguration()) { self.id = id self.name = name + self.title = title self.value = value self.workingValue = value self.originalValue = value diff --git a/Sources/FioriSwiftUICore/Models/ModelDefinitions.swift b/Sources/FioriSwiftUICore/Models/ModelDefinitions.swift index f61848fcf..87f51b178 100644 --- a/Sources/FioriSwiftUICore/Models/ModelDefinitions.swift +++ b/Sources/FioriSwiftUICore/Models/ModelDefinitions.swift @@ -579,10 +579,22 @@ public protocol FilterFeedbackBarButtonModel {} // sourcery: virtualPropUpdateSearchListPickerHeight = "var updateSearchListPickerHeight: ((CGFloat) -> ())? = nil" // sourcery: virtualPropBarItemFrame = "var barItemFrame: CGRect = .zero" public protocol OptionListPickerItemModel: OptionListPickerComponent { + // sourcery: default.value = nil + // sourcery: no_view + var title: String? { get set } + // sourcery: default.value = .fixed // sourcery: no_view var itemLayout: OptionListPickerItemLayoutType { get set } + // sourcery: default.value = true + // sourcery: no_view + var allowsMultipleSelection: Bool { get set } + + // sourcery: default.value = false + // sourcery: no_view + var allowsEmptySelection: Bool { get set } + // sourcery: default.value = nil // sourcery: no_view var onTap: ((_ index: Int) -> Void)? { get } diff --git a/Sources/FioriSwiftUICore/Views/OptionListPickerItem+View.swift b/Sources/FioriSwiftUICore/Views/OptionListPickerItem+View.swift index d53b6d817..196b7eea6 100644 --- a/Sources/FioriSwiftUICore/Views/OptionListPickerItem+View.swift +++ b/Sources/FioriSwiftUICore/Views/OptionListPickerItem+View.swift @@ -28,12 +28,15 @@ public extension OptionListPickerItem { /// - value: Indexes for selected values. /// - valueOptions: The data for constructing the list picker. /// - hint: Hint message. + /// - title: Title label of the options. /// - itemLayout: Option item layout type. + /// - allowsMultipleSelection: A boolean value to indicate to allow multiple selections or not. + /// - allowsEmptySelection: A boolean value to indicate to allow empty selections or not. /// - barItemFrame: The frame of the item in FilterFeedbackBar, which toggle to show this view. /// - onTap: The closure when tap on item. /// - updateSearchListPickerHeight: The closure to update the parent view. - init(value: Binding<[Int]>, valueOptions: [String] = [], hint: String? = nil, itemLayout: OptionListPickerItemLayoutType = .fixed, barItemFrame: CGRect = .zero, onTap: ((_ index: Int) -> Void)? = nil, updateSearchListPickerHeight: ((CGFloat) -> Void)? = nil) { - self.init(value: value, valueOptions: valueOptions, hint: hint, itemLayout: itemLayout, onTap: onTap) + init(value: Binding<[Int]>, valueOptions: [String] = [], title: String? = nil, hint: String? = nil, itemLayout: OptionListPickerItemLayoutType = .fixed, allowsMultipleSelection: Bool = true, allowsEmptySelection: Bool = false, barItemFrame: CGRect = .zero, onTap: ((_ index: Int) -> Void)? = nil, updateSearchListPickerHeight: ((CGFloat) -> Void)? = nil) { + self.init(value: value, valueOptions: valueOptions, hint: hint, title: title, itemLayout: itemLayout, allowsMultipleSelection: allowsMultipleSelection, allowsEmptySelection: allowsEmptySelection, onTap: onTap) self.barItemFrame = barItemFrame self.updateSearchListPickerHeight = updateSearchListPickerHeight @@ -42,65 +45,20 @@ public extension OptionListPickerItem { extension OptionListPickerItem: View { public var body: some View { - if _itemLayout == .flexible { - self.generateFlexibleContent() - } else { - self.generateFixedContent() - } - } - - private func generateFixedContent() -> some View { - ScrollView(.vertical) { - Grid(horizontalSpacing: 16) { - ForEach(0 ..< Int(ceil(Double(_valueOptions.count) / 2.0)), id: \.self) { rowIndex in - GridRow { - FilterFeedbackBarButton( - icon: _value.wrappedValue.contains(rowIndex * 2) ? Image(systemName: "checkmark") : nil, - title: AttributedString(_valueOptions[rowIndex * 2]), - isSelected: _value.wrappedValue.contains(rowIndex * 2) - ) - .filterFeedbackBarStyle() - .onTapGesture { - _onTap?(rowIndex * 2) - } - if rowIndex * 2 + 1 < _valueOptions.count { - FilterFeedbackBarButton( - icon: _value.wrappedValue.contains(rowIndex * 2 + 1) ? Image(systemName: "checkmark") : nil, - title: AttributedString(_valueOptions[rowIndex * 2 + 1]), - isSelected: _value.wrappedValue.contains(rowIndex * 2 + 1) - ) - .onTapGesture { - _onTap?(rowIndex * 2 + 1) - } - } - } - } - } - .background( - GeometryReader { geometry in - Color.clear - .onAppear { - self.updateSearchListPickerHeight?(self.calculateHeight(scrollViewContentHeight: geometry.size.height)) - } - } - ) - } - } - - private func generateFlexibleContent() -> some View { ScrollView(.vertical) { - OptionListPickerCustomLayout { - ForEach(0 ..< _valueOptions.count, id: \.self) { optionIndex in - FilterFeedbackBarButton( - icon: _value.wrappedValue.contains(optionIndex) ? Image(systemName: "checkmark") : nil, - title: AttributedString(_valueOptions[optionIndex]), - isSelected: _value.wrappedValue.contains(optionIndex) - ) - .onTapGesture { - _onTap?(optionIndex) - } + FilterFormView(title: { + if let title = _title, !title.isEmpty { + Text(title) + .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) + .foregroundStyle(Color.preferredColor(.primaryLabel)) + } else { + EmptyView() } + }, mandatoryFieldIndicator: { + EmptyView() + }, isRequired: false, options: _valueOptions.map { AttributedString($0) }, isEnabled: true, allowsMultipleSelection: _allowsMultipleSelection, allowsEmptySelection: _allowsEmptySelection, value: _value, buttonSize: _itemLayout == .flexible ? .flexible : .fixed, isSingleLine: false) { _ in } + .filterFormOptionsLineSpacing(12) .background( GeometryReader { geometry in Color.clear @@ -174,49 +132,3 @@ extension OptionListPickerItem: View { Spacer() } } - -struct OptionListPickerCustomLayout: Layout { - func sizeThatFits(proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) -> CGSize { - guard let containerWidth = proposal.width else { - return .zero - } - var containerHeight = 0.0 - var currentRowX = 0.0 - let padding = UIDevice.current.userInterfaceIdiom != .phone ? 13.0 : 16.0 - for index in 0 ..< subviews.count { - let subview = subviews[index] - let subviewSize = subview.sizeThatFits(.unspecified) - let subviewWidth = min(subviewSize.width, containerWidth - CGFloat(padding * 2)) - if index == 0 { - containerHeight += subviewSize.height - } - if currentRowX + subviewWidth + padding > containerWidth - CGFloat(padding * 2) { - containerHeight += subviewSize.height - containerHeight += 6 - currentRowX = 0.0 - } - currentRowX += subviewWidth + 6.0 - } - return CGSize(width: containerWidth, height: containerHeight) - } - - func placeSubviews(in bounds: CGRect, proposal: ProposedViewSize, subviews: Subviews, cache: inout ()) { - guard let containerWidth = proposal.width else { return } - var currentY: CGFloat = bounds.minY - var currentRowX = 0.0 - let padding = UIDevice.current.userInterfaceIdiom != .phone ? 13.0 : 16.0 - for subview in subviews { - let subviewSize = subview.sizeThatFits(.unspecified) - let subviewWidth = min(subviewSize.width, containerWidth - CGFloat(padding * 2)) - if currentRowX + subviewWidth + padding > containerWidth - CGFloat(padding * 2) { - currentY += subviewSize.height - currentY += 6 - currentRowX = 0.0 - subview.place(at: CGPoint(x: currentRowX, y: currentY), proposal: ProposedViewSize(width: subviewWidth, height: subviewSize.height)) - } else { - subview.place(at: CGPoint(x: currentRowX, y: currentY), proposal: ProposedViewSize(width: subviewWidth, height: subviewSize.height)) - } - currentRowX += subviewWidth + 6.0 - } - } -} diff --git a/Sources/FioriSwiftUICore/Views/SortFilter/FilterFeedbackBarItemSubview.swift b/Sources/FioriSwiftUICore/Views/SortFilter/FilterFeedbackBarItemSubview.swift index 4ef03f32a..beab59660 100644 --- a/Sources/FioriSwiftUICore/Views/SortFilter/FilterFeedbackBarItemSubview.swift +++ b/Sources/FioriSwiftUICore/Views/SortFilter/FilterFeedbackBarItemSubview.swift @@ -298,22 +298,41 @@ struct PickerMenuItem: View { }) .buttonStyle(ApplyButtonStyle()) } components: { - OptionListPickerItem(value: self.$item.workingValue, valueOptions: self.item.valueOptions, hint: nil, itemLayout: self.item.itemLayout, barItemFrame: self.barItemFrame) { index in - self.item.onTap(option: self.item.valueOptions[index]) - } updateSearchListPickerHeight: { height in - let isNotIphone = UIDevice.current.userInterfaceIdiom != .phone - var calculateHeight = height - calculateHeight += isNotIphone ? 13 : 16 - calculateHeight += isNotIphone ? 50 : 56 - if !isNotIphone { - calculateHeight += UIEdgeInsets.getSafeAreaInsets().bottom + ScrollView(.vertical) { + FilterFormView(title: { + if let title = self.item.title, !title.isEmpty { + Text(title) + .font(.fiori(forTextStyle: .subheadline, weight: .semibold)) + .foregroundStyle(Color.preferredColor(.primaryLabel)) + } else { + EmptyView() + } + }, mandatoryFieldIndicator: { + EmptyView() + }, isRequired: false, options: self.item.valueOptions.map { AttributedString($0) }, isEnabled: true, allowsMultipleSelection: self.item.allowsMultipleSelection, allowsEmptySelection: self.item.allowsEmptySelection, value: self.$item.workingValue, buttonSize: self.item.itemLayout == .flexible ? .flexible : .fixed, isSingleLine: false) { _ in } - #if !os(visionOS) - calculateHeight += UIDevice.current.userInterfaceIdiom != .phone ? 55 : 0 - #else - calculateHeight += 95 - #endif - self.detentHeight = calculateHeight + .filterFormOptionsLineSpacing(12) + .background( + GeometryReader { geometry in + Color.clear + .onAppear { + self.detentHeight = self.testHeight(scrollViewContentHeight: geometry.size.height) +// let isNotIphone = UIDevice.current.userInterfaceIdiom != .phone +// var calculateHeight = self.calculateScrollViewMaxHeight(scrollViewContentHeight: geometry.size.height) +// calculateHeight += isNotIphone ? 13 : 16 +// calculateHeight += isNotIphone ? 50 : 56 +// if !isNotIphone { +// calculateHeight += UIEdgeInsets.getSafeAreaInsets().bottom +// } +// #if !os(visionOS) +// calculateHeight += UIDevice.current.userInterfaceIdiom != .phone ? 55 : 0 +// #else +// calculateHeight += 95 +// #endif +// self.detentHeight = calculateHeight + } + } + ) } .padding([.leading, .trailing], 16) } @@ -345,7 +364,7 @@ struct PickerMenuItem: View { ForEach(self.item.valueOptions.indices, id: \.self) { idx in if self.item.isOptionSelected(index: idx) { Button { - self.item.onTap(option: self.item.valueOptions[idx]) + self.item.optionOnTap(idx) self.item.apply() self.onUpdate() } label: { @@ -547,6 +566,46 @@ struct PickerMenuItem: View { return self.item.workingValue.isEmpty } } + + private func testHeight(scrollViewContentHeight: CGFloat) -> CGFloat { + let screenHeight = Screen.bounds.size.height + let safeAreaInset = UIEdgeInsets.getSafeAreaInsets() + var calculateDetentHeight = 0.0 + if UIDevice.current.userInterfaceIdiom != .phone { + if self.barItemFrame.arrowDirection() == .top { + calculateDetentHeight = screenHeight - self.barItemFrame.maxY - safeAreaInset.bottom - 60 + } else if self.barItemFrame.arrowDirection() == .bottom { + calculateDetentHeight = screenHeight - (screenHeight - self.barItemFrame.minY) + safeAreaInset.top + } + } else { + calculateDetentHeight = screenHeight - safeAreaInset.top - 30 + } + return calculateDetentHeight + } + + private func calculateScrollViewMaxHeight(scrollViewContentHeight: CGFloat) -> CGFloat { + let screenHeight = Screen.bounds.size.height + let safeAreaInset = UIEdgeInsets.getSafeAreaInsets() + var maxScrollViewHeight = screenHeight - self.additionalHeight() + if UIDevice.current.userInterfaceIdiom != .phone { + if self.barItemFrame.arrowDirection() == .top { + maxScrollViewHeight -= (self.barItemFrame.maxY + 80) + } else if self.barItemFrame.arrowDirection() == .bottom { + maxScrollViewHeight -= (screenHeight - self.barItemFrame.minY + 80) + safeAreaInset.bottom + 13 + } + } else { + maxScrollViewHeight -= (safeAreaInset.top + 30) + } + return min(scrollViewContentHeight, maxScrollViewHeight) + } + + private func additionalHeight() -> CGFloat { + let isNotIphone = UIDevice.current.userInterfaceIdiom != .phone + var height = 0.0 + height += UIEdgeInsets.getSafeAreaInsets().bottom + (isNotIphone ? 13 : 16) + height += isNotIphone ? 50 : 56 + return height + } } private extension View { diff --git a/Sources/FioriSwiftUICore/Views/SortFilter/_FilterFeedbackBarItem+View.swift b/Sources/FioriSwiftUICore/Views/SortFilter/_FilterFeedbackBarItem+View.swift index 7d3644d3d..1c732f345 100644 --- a/Sources/FioriSwiftUICore/Views/SortFilter/_FilterFeedbackBarItem+View.swift +++ b/Sources/FioriSwiftUICore/Views/SortFilter/_FilterFeedbackBarItem+View.swift @@ -356,7 +356,7 @@ struct _PickerMenuItem: View { }) .buttonStyle(ApplyButtonStyle()) } components: { - OptionListPickerItem(value: self.$item.workingValue, valueOptions: self.item.valueOptions, hint: nil, itemLayout: self.item.itemLayout, barItemFrame: self.barItemFrame) { index in + OptionListPickerItem(value: self.$item.workingValue, valueOptions: self.item.valueOptions, title: self.item.title, itemLayout: self.item.itemLayout, allowsMultipleSelection: self.item.allowsMultipleSelection, allowsEmptySelection: self.item.allowsEmptySelection, barItemFrame: self.barItemFrame) { index in self.item.onTap(option: self.item.valueOptions[index]) } updateSearchListPickerHeight: { height in let isNotIphone = UIDevice.current.userInterfaceIdiom != .phone diff --git a/Sources/FioriSwiftUICore/_generated/ViewModels/API/OptionListPickerItem+API.generated.swift b/Sources/FioriSwiftUICore/_generated/ViewModels/API/OptionListPickerItem+API.generated.swift index 2b9d7b204..b1a067693 100644 --- a/Sources/FioriSwiftUICore/_generated/ViewModels/API/OptionListPickerItem+API.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/ViewModels/API/OptionListPickerItem+API.generated.swift @@ -8,20 +8,26 @@ public struct OptionListPickerItem { var _value: Binding<[Int]> var _valueOptions: [String] var _hint: String? = nil + var _title: String? = nil var _itemLayout: OptionListPickerItemLayoutType + var _allowsMultipleSelection: Bool + var _allowsEmptySelection: Bool var _onTap: ((_ index: Int) -> Void)? = nil - @State var _height: CGFloat = 0 - var barItemFrame: CGRect = .zero var updateSearchListPickerHeight: ((CGFloat) -> ())? = nil + var barItemFrame: CGRect = .zero + @State var _height: CGFloat = 0 public init(model: OptionListPickerItemModel) { - self.init(value: Binding<[Int]>(get: { model.value }, set: { model.value = $0 }), valueOptions: model.valueOptions, hint: model.hint, itemLayout: model.itemLayout, onTap: model.onTap) + self.init(value: Binding<[Int]>(get: { model.value }, set: { model.value = $0 }), valueOptions: model.valueOptions, hint: model.hint, title: model.title, itemLayout: model.itemLayout, allowsMultipleSelection: model.allowsMultipleSelection, allowsEmptySelection: model.allowsEmptySelection, onTap: model.onTap) } - public init(value: Binding<[Int]>, valueOptions: [String] = [], hint: String? = nil, itemLayout: OptionListPickerItemLayoutType = .fixed, onTap: ((_ index: Int) -> Void)? = nil) { + public init(value: Binding<[Int]>, valueOptions: [String] = [], hint: String? = nil, title: String? = nil, itemLayout: OptionListPickerItemLayoutType = .fixed, allowsMultipleSelection: Bool = true, allowsEmptySelection: Bool = false, onTap: ((_ index: Int) -> Void)? = nil) { self._value = value self._valueOptions = valueOptions self._hint = hint + self._title = title self._itemLayout = itemLayout + self._allowsMultipleSelection = allowsMultipleSelection + self._allowsEmptySelection = allowsEmptySelection self._onTap = onTap } } diff --git a/Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/OptionListPickerItemModel+Extensions.generated.swift b/Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/OptionListPickerItemModel+Extensions.generated.swift index 0ccb053d8..ae7dea8c0 100644 --- a/Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/OptionListPickerItemModel+Extensions.generated.swift +++ b/Sources/FioriSwiftUICore/_generated/ViewModels/Model+Extensions/OptionListPickerItemModel+Extensions.generated.swift @@ -3,10 +3,22 @@ import SwiftUI public extension OptionListPickerItemModel { - var itemLayout: OptionListPickerItemLayoutType { + var title: String? { + return nil + } + + var itemLayout: OptionListPickerItemLayoutType { return .fixed } + var allowsMultipleSelection: Bool { + return true + } + + var allowsEmptySelection: Bool { + return false + } + var onTap: ((_ index: Int) -> Void)? { return nil } From 0fa2931c0b979f76fae0dd8424089b1de91c084e Mon Sep 17 00:00:00 2001 From: "Gu, Jiajun (external - Project)" Date: Fri, 21 Feb 2025 17:19:53 +0800 Subject: [PATCH 2/3] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20[HCPSDKFIORIUIKI?= =?UTF-8?q?T-2891]FilterFeedbackbar=20FilterForm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Views/OptionListPickerItem+View.swift | 3 +- .../FilterFeedbackBarItemSubview.swift | 65 ++++++------------- .../_FilterFeedbackBarItem+View.swift | 1 - 3 files changed, 21 insertions(+), 48 deletions(-) diff --git a/Sources/FioriSwiftUICore/Views/OptionListPickerItem+View.swift b/Sources/FioriSwiftUICore/Views/OptionListPickerItem+View.swift index 196b7eea6..90f7439b0 100644 --- a/Sources/FioriSwiftUICore/Views/OptionListPickerItem+View.swift +++ b/Sources/FioriSwiftUICore/Views/OptionListPickerItem+View.swift @@ -58,7 +58,8 @@ extension OptionListPickerItem: View { EmptyView() }, isRequired: false, options: _valueOptions.map { AttributedString($0) }, isEnabled: true, allowsMultipleSelection: _allowsMultipleSelection, allowsEmptySelection: _allowsEmptySelection, value: _value, buttonSize: _itemLayout == .flexible ? .flexible : .fixed, isSingleLine: false) { _ in } - .filterFormOptionsLineSpacing(12) + .padding([.leading, .trailing], 16) + .filterFormOptionsLineSpacing(10) .background( GeometryReader { geometry in Color.clear diff --git a/Sources/FioriSwiftUICore/Views/SortFilter/FilterFeedbackBarItemSubview.swift b/Sources/FioriSwiftUICore/Views/SortFilter/FilterFeedbackBarItemSubview.swift index 2be229473..e60068b37 100644 --- a/Sources/FioriSwiftUICore/Views/SortFilter/FilterFeedbackBarItemSubview.swift +++ b/Sources/FioriSwiftUICore/Views/SortFilter/FilterFeedbackBarItemSubview.swift @@ -311,30 +311,23 @@ struct PickerMenuItem: View { EmptyView() }, isRequired: false, options: self.item.valueOptions.map { AttributedString($0) }, isEnabled: true, allowsMultipleSelection: self.item.allowsMultipleSelection, allowsEmptySelection: self.item.allowsEmptySelection, value: self.$item.workingValue, buttonSize: self.item.itemLayout == .flexible ? .flexible : .fixed, isSingleLine: false) { _ in } - .filterFormOptionsLineSpacing(12) + .filterFormOptionsLineSpacing(10) .background( GeometryReader { geometry in Color.clear .onAppear { - self.detentHeight = self.testHeight(scrollViewContentHeight: geometry.size.height) -// let isNotIphone = UIDevice.current.userInterfaceIdiom != .phone -// var calculateHeight = self.calculateScrollViewMaxHeight(scrollViewContentHeight: geometry.size.height) -// calculateHeight += isNotIphone ? 13 : 16 -// calculateHeight += isNotIphone ? 50 : 56 -// if !isNotIphone { -// calculateHeight += UIEdgeInsets.getSafeAreaInsets().bottom -// } -// #if !os(visionOS) -// calculateHeight += UIDevice.current.userInterfaceIdiom != .phone ? 55 : 0 -// #else -// calculateHeight += 95 -// #endif -// self.detentHeight = calculateHeight + self.detentHeight = self.calcluateFilterFormViewPopoverHeight(scrollViewContentHeight: geometry.size.height) + } + .setOnChange(of: geometry.frame(in: .global), action1: { _ in + self.detentHeight = self.calcluateFilterFormViewPopoverHeight(scrollViewContentHeight: geometry.size.height) + }) { _, _ in + self.detentHeight = self.calcluateFilterFormViewPopoverHeight(scrollViewContentHeight: geometry.size.height) } } ) + .padding([.leading, .trailing], 16) + .padding(.bottom, 10) } - .padding([.leading, .trailing], 16) } .frame(height: self.detentHeight) .ifApply(UIDevice.current.userInterfaceIdiom != .phone, content: { v in @@ -567,44 +560,24 @@ struct PickerMenuItem: View { } } - private func testHeight(scrollViewContentHeight: CGFloat) -> CGFloat { - let screenHeight = Screen.bounds.size.height - let safeAreaInset = UIEdgeInsets.getSafeAreaInsets() - var calculateDetentHeight = 0.0 - if UIDevice.current.userInterfaceIdiom != .phone { - if self.barItemFrame.arrowDirection() == .top { - calculateDetentHeight = screenHeight - self.barItemFrame.maxY - safeAreaInset.bottom - 60 - } else if self.barItemFrame.arrowDirection() == .bottom { - calculateDetentHeight = screenHeight - (screenHeight - self.barItemFrame.minY) + safeAreaInset.top - } - } else { - calculateDetentHeight = screenHeight - safeAreaInset.top - 30 - } - return calculateDetentHeight - } - - private func calculateScrollViewMaxHeight(scrollViewContentHeight: CGFloat) -> CGFloat { + private func calcluateFilterFormViewPopoverHeight(scrollViewContentHeight: CGFloat) -> CGFloat { let screenHeight = Screen.bounds.size.height let safeAreaInset = UIEdgeInsets.getSafeAreaInsets() - var maxScrollViewHeight = screenHeight - self.additionalHeight() + var maxPopoverViewHeight = 0.0 + var calaulatePopoverViewHeight = scrollViewContentHeight if UIDevice.current.userInterfaceIdiom != .phone { if self.barItemFrame.arrowDirection() == .top { - maxScrollViewHeight -= (self.barItemFrame.maxY + 80) + maxPopoverViewHeight = screenHeight - self.barItemFrame.maxY - safeAreaInset.bottom - 30 } else if self.barItemFrame.arrowDirection() == .bottom { - maxScrollViewHeight -= (screenHeight - self.barItemFrame.minY + 80) + safeAreaInset.bottom + 13 + maxPopoverViewHeight = screenHeight - (screenHeight - self.barItemFrame.minY) + safeAreaInset.top } + calaulatePopoverViewHeight += 50 + 70 } else { - maxScrollViewHeight -= (safeAreaInset.top + 30) + maxPopoverViewHeight = screenHeight - safeAreaInset.top - 30 + calaulatePopoverViewHeight += 56 + 20 + safeAreaInset.bottom } - return min(scrollViewContentHeight, maxScrollViewHeight) - } - - private func additionalHeight() -> CGFloat { - let isNotIphone = UIDevice.current.userInterfaceIdiom != .phone - var height = 0.0 - height += UIEdgeInsets.getSafeAreaInsets().bottom + (isNotIphone ? 13 : 16) - height += isNotIphone ? 50 : 56 - return height + + return min(maxPopoverViewHeight, calaulatePopoverViewHeight) } } diff --git a/Sources/FioriSwiftUICore/Views/SortFilter/_FilterFeedbackBarItem+View.swift b/Sources/FioriSwiftUICore/Views/SortFilter/_FilterFeedbackBarItem+View.swift index b97c7f38b..865cde204 100644 --- a/Sources/FioriSwiftUICore/Views/SortFilter/_FilterFeedbackBarItem+View.swift +++ b/Sources/FioriSwiftUICore/Views/SortFilter/_FilterFeedbackBarItem+View.swift @@ -373,7 +373,6 @@ struct _PickerMenuItem: View { #endif self.detentHeight = calculateHeight } - .padding([.leading, .trailing], 16) } .frame(height: self.detentHeight) .ifApply(UIDevice.current.userInterfaceIdiom != .phone, content: { v in From 7d8f9884efb5dfd35757b931e0824ea1d8a9fbbc Mon Sep 17 00:00:00 2001 From: "Gu, Jiajun (external - Project)" <> Date: Tue, 25 Feb 2025 08:55:47 +0800 Subject: [PATCH 3/3] =?UTF-8?q?refactor:=20=F0=9F=92=A1=20[HCPSDKFIORIUIKI?= =?UTF-8?q?T-2891]FilterFeedbackbar=20FilterForm?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Sources/FioriSwiftUICore/DataTypes/SortFilter+DataType.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Sources/FioriSwiftUICore/DataTypes/SortFilter+DataType.swift b/Sources/FioriSwiftUICore/DataTypes/SortFilter+DataType.swift index dc9edaecd..f8b6ee989 100644 --- a/Sources/FioriSwiftUICore/DataTypes/SortFilter+DataType.swift +++ b/Sources/FioriSwiftUICore/DataTypes/SortFilter+DataType.swift @@ -475,7 +475,7 @@ public extension SortFilterItem { /// - allowsEmptySelection: A boolean value to indicate to allow empty selections or not. /// - barItemDisplayMode: Name display mode for the bar. /// - isSearchBarHidden: A boolean value to indicate to search bar hidden or not. - /// - icon: Icon at the left of the item. + /// - icon: Icon at the leading side of the item. /// - itemLayout: Options layout type when `displayMode` is `.filterFormCell`. /// - displayMode: Options display mode. /// - listEntriesSectionMode: List entries section mode when `displayMode` is `.list`.