Skip to content

Commit 4c4b9fd

Browse files
committed
refactor: move filters to native Form sheet — remove inline list section
1 parent 5821789 commit 4c4b9fd

File tree

1 file changed

+88
-73
lines changed

1 file changed

+88
-73
lines changed

TableProMobile/TableProMobile/Views/DataBrowserView.swift

Lines changed: 88 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ struct DataBrowserView: View {
3232
@State private var goToPageInput = ""
3333
@State private var filters: [TableFilter] = []
3434
@State private var filterLogicMode: FilterLogicMode = .and
35-
@State private var showFilterBar = false
35+
@State private var showFilterSheet = false
3636

3737
private var isView: Bool {
3838
table.type == .view || table.type == .materializedView
@@ -65,6 +65,15 @@ struct DataBrowserView: View {
6565
.toolbar { paginationToolbar }
6666
.task { await loadData(isInitial: true) }
6767
.sheet(isPresented: $showInsertSheet) { insertSheet }
68+
.sheet(isPresented: $showFilterSheet) {
69+
FilterSheetView(
70+
filters: $filters,
71+
logicMode: $filterLogicMode,
72+
columns: columns,
73+
onApply: { applyFilters() },
74+
onClear: { clearFilters() }
75+
)
76+
}
6877
.confirmationDialog("Delete Row", isPresented: $showDeleteConfirmation, titleVisibility: .visible) {
6978
Button("Delete", role: .destructive) {
7079
if let pkValues = deleteTarget {
@@ -119,50 +128,12 @@ struct DataBrowserView: View {
119128
}
120129
}
121130

131+
private var activeFilterCount: Int {
132+
filters.filter { $0.isEnabled && $0.isValid }.count
133+
}
134+
122135
private var rowList: some View {
123136
List {
124-
if showFilterBar {
125-
Section {
126-
if filters.count > 1 {
127-
Picker("Logic", selection: $filterLogicMode) {
128-
Text("AND").tag(FilterLogicMode.and)
129-
Text("OR").tag(FilterLogicMode.or)
130-
}
131-
.pickerStyle(.segmented)
132-
}
133-
134-
ForEach($filters) { $filter in
135-
FilterRowView(
136-
filter: $filter,
137-
columns: columns,
138-
onDelete: { filters.removeAll { $0.id == filter.id } }
139-
)
140-
}
141-
142-
HStack {
143-
Button {
144-
filters.append(TableFilter(columnName: columns.first?.name ?? ""))
145-
} label: {
146-
Label("Add Filter", systemImage: "plus.circle")
147-
}
148-
Spacer()
149-
Button("Apply") {
150-
applyFilters()
151-
}
152-
.buttonStyle(.borderedProminent)
153-
.disabled(!hasActiveFilters)
154-
}
155-
156-
if hasActiveFilters {
157-
Button("Clear Filters", role: .destructive) {
158-
clearFilters()
159-
}
160-
}
161-
} header: {
162-
Text("Filters")
163-
}
164-
}
165-
166137
ForEach(Array(rows.enumerated()), id: \.offset) { index, row in
167138
NavigationLink {
168139
RowDetailView(
@@ -207,11 +178,12 @@ struct DataBrowserView: View {
207178
@ToolbarContentBuilder
208179
private var topToolbar: some ToolbarContent {
209180
ToolbarItem(placement: .topBarTrailing) {
210-
Button { withAnimation { showFilterBar.toggle() } } label: {
181+
Button { showFilterSheet = true } label: {
211182
Image(systemName: hasActiveFilters
212183
? "line.3.horizontal.decrease.circle.fill"
213184
: "line.3.horizontal.decrease.circle")
214185
}
186+
.badge(activeFilterCount)
215187
}
216188
ToolbarItem(placement: .topBarTrailing) {
217189
NavigationLink {
@@ -438,47 +410,90 @@ struct DataBrowserView: View {
438410
}
439411
}
440412

441-
// MARK: - Filter Row
413+
// MARK: - Filter Sheet
442414

443-
private struct FilterRowView: View {
444-
@Binding var filter: TableFilter
415+
private struct FilterSheetView: View {
416+
@Environment(\.dismiss) private var dismiss
417+
@Binding var filters: [TableFilter]
418+
@Binding var logicMode: FilterLogicMode
445419
let columns: [ColumnInfo]
446-
let onDelete: () -> Void
420+
let onApply: () -> Void
421+
let onClear: () -> Void
447422

448423
var body: some View {
449-
VStack(spacing: 8) {
450-
HStack {
451-
Picker("Column", selection: $filter.columnName) {
452-
ForEach(columns, id: \.name) { col in
453-
Text(col.name).tag(col.name)
424+
NavigationStack {
425+
Form {
426+
if filters.count > 1 {
427+
Section {
428+
Picker("Logic", selection: $logicMode) {
429+
Text("AND").tag(FilterLogicMode.and)
430+
Text("OR").tag(FilterLogicMode.or)
431+
}
432+
.pickerStyle(.segmented)
454433
}
455434
}
456-
.pickerStyle(.menu)
457435

458-
Button(role: .destructive) { onDelete() } label: {
459-
Image(systemName: "minus.circle.fill")
460-
.foregroundStyle(.red)
436+
ForEach($filters) { $filter in
437+
Section {
438+
Picker("Column", selection: $filter.columnName) {
439+
ForEach(columns, id: \.name) { col in
440+
Text(col.name).tag(col.name)
441+
}
442+
}
443+
444+
Picker("Operator", selection: $filter.filterOperator) {
445+
ForEach(FilterOperator.allCases, id: \.self) { op in
446+
Text(op.displayName).tag(op)
447+
}
448+
}
449+
450+
if filter.filterOperator.needsValue {
451+
TextField("Value", text: $filter.value)
452+
.textInputAutocapitalization(.never)
453+
.autocorrectionDisabled()
454+
}
455+
456+
if filter.filterOperator == .between {
457+
TextField("Second value", text: $filter.secondValue)
458+
.textInputAutocapitalization(.never)
459+
.autocorrectionDisabled()
460+
}
461+
}
462+
}
463+
.onDelete { indexSet in
464+
filters.remove(atOffsets: indexSet)
461465
}
462-
.buttonStyle(.plain)
463-
}
464466

465-
Picker("Operator", selection: $filter.filterOperator) {
466-
ForEach(FilterOperator.allCases, id: \.self) { op in
467-
Text(op.displayName).tag(op)
467+
Section {
468+
Button {
469+
filters.append(TableFilter(columnName: columns.first?.name ?? ""))
470+
} label: {
471+
Label("Add Filter", systemImage: "plus.circle")
472+
}
468473
}
469-
}
470-
.pickerStyle(.menu)
471474

472-
if filter.filterOperator.needsValue {
473-
TextField("Value", text: $filter.value)
474-
.textInputAutocapitalization(.never)
475-
.autocorrectionDisabled()
475+
if !filters.isEmpty {
476+
Section {
477+
Button("Clear All Filters", role: .destructive) {
478+
onClear()
479+
dismiss()
480+
}
481+
}
482+
}
476483
}
477-
478-
if filter.filterOperator == .between {
479-
TextField("Second value", text: $filter.secondValue)
480-
.textInputAutocapitalization(.never)
481-
.autocorrectionDisabled()
484+
.navigationTitle("Filters")
485+
.navigationBarTitleDisplayMode(.inline)
486+
.toolbar {
487+
ToolbarItem(placement: .cancellationAction) {
488+
Button("Cancel") { dismiss() }
489+
}
490+
ToolbarItem(placement: .confirmationAction) {
491+
Button("Apply") {
492+
onApply()
493+
dismiss()
494+
}
495+
.disabled(!filters.contains { $0.isEnabled && $0.isValid })
496+
}
482497
}
483498
}
484499
}

0 commit comments

Comments
 (0)