Remove Location status section; add 10/25/50/75/100 station limit picker; refresh location every foreground
This commit is contained in:
+29
-23
@@ -8,6 +8,7 @@ struct ContentView: View {
|
|||||||
@State private var stations: [FuelStation] = []
|
@State private var stations: [FuelStation] = []
|
||||||
@State private var selectedFuel: FuelType = FuelStore.loadSelectedFuel()
|
@State private var selectedFuel: FuelType = FuelStore.loadSelectedFuel()
|
||||||
@State private var sortMode: SortMode = FuelStore.loadSortMode()
|
@State private var sortMode: SortMode = FuelStore.loadSortMode()
|
||||||
|
@State private var stationLimit: Int = FuelStore.loadStationLimit()
|
||||||
@State private var location: Coordinate? = {
|
@State private var location: Coordinate? = {
|
||||||
if let loc = FuelStore.loadLocation() { return Coordinate(lat: loc.lat, lng: loc.lng) }
|
if let loc = FuelStore.loadLocation() { return Coordinate(lat: loc.lat, lng: loc.lng) }
|
||||||
return nil
|
return nil
|
||||||
@@ -20,6 +21,10 @@ struct ContentView: View {
|
|||||||
stations.compactMap { $0.prices[selectedFuel] }.min()
|
stations.compactMap { $0.prices[selectedFuel] }.min()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private var displayedStations: [FuelStation] {
|
||||||
|
Array(sortedStations.prefix(stationLimit))
|
||||||
|
}
|
||||||
|
|
||||||
private var sortedStations: [FuelStation] {
|
private var sortedStations: [FuelStation] {
|
||||||
let available = stations.filter { $0.prices[selectedFuel] != nil }
|
let available = stations.filter { $0.prices[selectedFuel] != nil }
|
||||||
switch sortMode {
|
switch sortMode {
|
||||||
@@ -84,11 +89,11 @@ struct ContentView: View {
|
|||||||
ProgressView()
|
ProgressView()
|
||||||
Text("Fetching prices…")
|
Text("Fetching prices…")
|
||||||
}
|
}
|
||||||
} else if sortedStations.isEmpty {
|
} else if displayedStations.isEmpty {
|
||||||
Text("No \(selectedFuel.displayName) stations found.")
|
Text("No \(selectedFuel.displayName) stations found.")
|
||||||
.foregroundStyle(.secondary)
|
.foregroundStyle(.secondary)
|
||||||
} else {
|
} else {
|
||||||
ForEach(Array(sortedStations.enumerated()), id: \.element.id) { index, station in
|
ForEach(Array(displayedStations.enumerated()), id: \.element.id) { index, station in
|
||||||
StationRow(
|
StationRow(
|
||||||
station: station,
|
station: station,
|
||||||
fuel: selectedFuel,
|
fuel: selectedFuel,
|
||||||
@@ -98,6 +103,23 @@ struct ContentView: View {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !displayedStations.isEmpty {
|
||||||
|
Divider()
|
||||||
|
Picker("Show", selection: $stationLimit) {
|
||||||
|
ForEach([10, 25, 50, 75, 100], id: \.self) { count in
|
||||||
|
Text("\(count)").tag(count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.pickerStyle(.segmented)
|
||||||
|
.onChange(of: stationLimit) { _, newValue in
|
||||||
|
FuelStore.saveStationLimit(newValue)
|
||||||
|
}
|
||||||
|
.padding(.vertical, 2)
|
||||||
|
Text("Showing \(displayedStations.count) of \(sortedStations.count) stations")
|
||||||
|
.font(.caption2)
|
||||||
|
.foregroundStyle(.secondary)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section("Key") {
|
Section("Key") {
|
||||||
@@ -128,22 +150,6 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Section("Location") {
|
|
||||||
if let location {
|
|
||||||
Text("Using location \(String(format: "%.4f, %.4f", location.lat, location.lng))")
|
|
||||||
.font(.caption)
|
|
||||||
.foregroundStyle(.secondary)
|
|
||||||
} else {
|
|
||||||
Text("No location yet — allow location access to sort by distance.")
|
|
||||||
.font(.caption)
|
|
||||||
.foregroundStyle(.secondary)
|
|
||||||
}
|
|
||||||
Button("Update my location") {
|
|
||||||
locationManager.requestUpdate()
|
|
||||||
}
|
|
||||||
.font(.footnote)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !statusMessage.isEmpty {
|
if !statusMessage.isEmpty {
|
||||||
Section("Status") {
|
Section("Status") {
|
||||||
Text(statusMessage)
|
Text(statusMessage)
|
||||||
@@ -165,15 +171,15 @@ struct ContentView: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onAppear {
|
.onAppear {
|
||||||
// Auto-request location on first launch so the widget gets a
|
// Request a fresh fix on every launch so "Closest" stays
|
||||||
// fresh fix without the user hunting for the button.
|
// accurate and the widget gets fresh coords.
|
||||||
if FuelStore.loadLocation() == nil {
|
locationManager.requestUpdate()
|
||||||
locationManager.requestUpdate()
|
|
||||||
}
|
|
||||||
Task { await refresh() }
|
Task { await refresh() }
|
||||||
}
|
}
|
||||||
.onChange(of: scenePhase) { _, newPhase in
|
.onChange(of: scenePhase) { _, newPhase in
|
||||||
if newPhase == .active {
|
if newPhase == .active {
|
||||||
|
// Re-request location on foreground too.
|
||||||
|
locationManager.requestUpdate()
|
||||||
Task { await refresh() }
|
Task { await refresh() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,6 +103,7 @@ struct FuelStore {
|
|||||||
static let locationKey = "fuelboard.lastLocation" // "lat,lng,timestamp"
|
static let locationKey = "fuelboard.lastLocation" // "lat,lng,timestamp"
|
||||||
static let fuelKey = "fuelboard.selectedFuel" // FuelType raw value
|
static let fuelKey = "fuelboard.selectedFuel" // FuelType raw value
|
||||||
static let sortModeKey = "fuelboard.sortMode" // SortMode raw value
|
static let sortModeKey = "fuelboard.sortMode" // SortMode raw value
|
||||||
|
static let stationLimitKey = "fuelboard.stationLimit" // Int (10/25/50/75/100)
|
||||||
|
|
||||||
// MARK: Stations
|
// MARK: Stations
|
||||||
|
|
||||||
@@ -167,6 +168,19 @@ struct FuelStore {
|
|||||||
saveString(mode.rawValue, service: sortModeKey)
|
saveString(mode.rawValue, service: sortModeKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// MARK: Station count limit
|
||||||
|
|
||||||
|
static func loadStationLimit() -> Int {
|
||||||
|
if let raw = loadString(service: stationLimitKey), let value = Int(raw), [10, 25, 50, 75, 100].contains(value) {
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
return 25
|
||||||
|
}
|
||||||
|
|
||||||
|
static func saveStationLimit(_ limit: Int) {
|
||||||
|
saveString(String(limit), service: stationLimitKey)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Low-level keychain helpers
|
// MARK: Low-level keychain helpers
|
||||||
|
|
||||||
private static func keychainData(service: String) -> Data? {
|
private static func keychainData(service: String) -> Data? {
|
||||||
|
|||||||
Reference in New Issue
Block a user