Distance filter below fuel type under Distance heading; list paginated 10 rows with Show more

This commit is contained in:
FuelBoard Contributor
2026-08-11 19:38:08 +01:00
parent cf9765be7b
commit d62ac1b265
+43 -16
View File
@@ -1,7 +1,7 @@
import SwiftUI import SwiftUI
import WidgetKit import WidgetKit
/// Stations tab the main list with fuel picker, sort, station count limit. /// Stations tab the main list with fuel picker, distance filter, sort, pagination.
struct StationsView: View { struct StationsView: View {
let stations: [FuelStation] let stations: [FuelStation]
let totalCount: Int let totalCount: Int
@@ -15,6 +15,13 @@ struct StationsView: View {
var onToggleFavourite: (FuelStation) -> Void = { _ in } var onToggleFavourite: (FuelStation) -> Void = { _ in }
var onRefresh: () async -> Void = {} var onRefresh: () async -> Void = {}
/// Pagination: one page = 10 rows, reset whenever the underlying list
/// changes (new fetch, fuel/sort/radius switch). RAG/TOP/deltas still come
/// from the whole radius pool via `cheapestPrice` paging never changes
/// which station is "best".
@State private var pageSize = 10
@State private var visibleCount = 10
var body: some View { var body: some View {
NavigationStack { NavigationStack {
List { List {
@@ -43,6 +50,22 @@ struct StationsView: View {
} }
} }
Section("Distance") {
Picker("Distance", selection: $stationLimit) {
ForEach(FuelStore.stationRadiusOptions, id: \.self) { miles in
Text("\(miles) miles").tag(miles)
}
}
.pickerStyle(.segmented)
.onChange(of: stationLimit) { _, newValue in
FuelStore.saveStationLimit(newValue)
}
.padding(.vertical, 2)
Text("\(totalCount) stations within \(stationLimit) miles")
.font(.caption2)
.foregroundStyle(.secondary)
}
Section("Stations") { Section("Stations") {
Picker("Sort by", selection: $sortMode) { Picker("Sort by", selection: $sortMode) {
ForEach(SortMode.allCases) { mode in ForEach(SortMode.allCases) { mode in
@@ -64,7 +87,7 @@ struct StationsView: View {
Text("No \(selectedFuel.displayName) stations found.") Text("No \(selectedFuel.displayName) stations found.")
.foregroundStyle(.secondary) .foregroundStyle(.secondary)
} else { } else {
ForEach(Array(stations.enumerated()), id: \.element.id) { index, station in ForEach(Array(stations.prefix(visibleCount).enumerated()), id: \.element.id) { index, station in
StationRow( StationRow(
station: station, station: station,
fuel: selectedFuel, fuel: selectedFuel,
@@ -75,23 +98,23 @@ struct StationsView: View {
onToggleFavourite: { onToggleFavourite(station) } onToggleFavourite: { onToggleFavourite(station) }
) )
} }
}
if !stations.isEmpty { if visibleCount < stations.count {
Divider() Button {
Picker("Within", selection: $stationLimit) { visibleCount += pageSize
ForEach(FuelStore.stationRadiusOptions, id: \.self) { miles in } label: {
Text("\(miles) miles").tag(miles) HStack {
Spacer()
Text("Show \(min(pageSize, stations.count - visibleCount)) more (\(stations.count - visibleCount) remaining)")
Spacer()
}
} }
} else {
Text("All \(stations.count) stations shown")
.font(.caption2)
.foregroundStyle(.secondary)
.frame(maxWidth: .infinity)
} }
.pickerStyle(.segmented)
.onChange(of: stationLimit) { _, newValue in
FuelStore.saveStationLimit(newValue)
}
.padding(.vertical, 2)
Text("\(totalCount) stations within \(stationLimit) miles")
.font(.caption2)
.foregroundStyle(.secondary)
} }
} }
@@ -134,6 +157,10 @@ struct StationsView: View {
// Manual override for the twice-a-day cache policy. // Manual override for the twice-a-day cache policy.
await onRefresh() await onRefresh()
} }
.onChange(of: stations) { _, _ in
// New fetch or filter switch back to the first page.
visibleCount = pageSize
}
.navigationTitle("FuelBoard") .navigationTitle("FuelBoard")
} }
} }