FuelMan/Gas Man/FuelLogListView.swift

157 lines
6.3 KiB
Swift

import SwiftUI
import CoreData
struct FuelLogListView: View {
@Environment(\.managedObjectContext) private var viewContext
// All fuel logs (sorted by date descending)
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \FuelLog.date, ascending: false)],
animation: .default)
private var fuelLogs: FetchedResults<FuelLog>
// All vehicles (sorted by make)
@FetchRequest(
sortDescriptors: [NSSortDescriptor(keyPath: \Vehicle.make, ascending: true)],
animation: .default)
private var vehicles: FetchedResults<Vehicle>
@State private var showingAddFuelLog = false
@State private var selectedVehicleID: UUID? = nil
@State private var showAddVehicleSheet = false
// For tracking the previous odometer reading
@State private var previousOdometer: Double? = nil
@State private var showOdometerAlert = false
@State private var isUpdatingCalculation = false
// Computed property for formatted previous odometer value
private var previousOdometerString: String {
previousOdometer.map { String(format: "%.0f", $0) } ?? "N/A"
}
// Filter fuel logs by the selected vehicle.
private var filteredFuelLogs: [FuelLog] {
if let vehicleID = selectedVehicleID {
return fuelLogs.filter { log in
if let logVehicleID = log.vehicle?.id {
return logVehicleID == vehicleID
}
return false
}
} else {
return Array(fuelLogs)
}
}
var body: some View {
NavigationView {
if vehicles.isEmpty {
VStack(spacing: 20) {
Text("No vehicles found.")
.font(.headline)
Text("Please add a vehicle before logging fuel records.")
.multilineTextAlignment(.center)
.padding(.horizontal)
Button("Add Vehicle") {
showAddVehicleSheet = true
}
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(8)
}
.navigationTitle("Fuel Logs")
.sheet(isPresented: $showAddVehicleSheet) {
AddVehicleView().environment(\.managedObjectContext, viewContext)
}
} else {
List {
Section {
Picker("Vehicle", selection: $selectedVehicleID) {
ForEach(vehicles, id: \.id) { vehicle in
Text("\(vehicle.year) \(vehicle.make ?? "") \(vehicle.model ?? "")")
.tag(vehicle.id)
}
}
.pickerStyle(MenuPickerStyle())
}
ForEach(filteredFuelLogs.indices, id: \.self) { index in
let log = filteredFuelLogs[index]
let distance: Double? = {
guard index < filteredFuelLogs.count - 1 else { return nil }
let previousLog = filteredFuelLogs[index + 1]
let milesDriven = log.odometer - previousLog.odometer
return milesDriven > 0 ? milesDriven : nil
}()
let mpg: Double? = {
// Only calculate MPG if fullTank is true.
guard log.fullTank else { return nil }
guard index < filteredFuelLogs.count - 1 else { return nil }
let previousLog = filteredFuelLogs[index + 1]
let milesDriven = log.odometer - previousLog.odometer
guard log.fuelVolume > 0, milesDriven > 0 else { return nil }
return milesDriven / log.fuelVolume
}()
NavigationLink(destination: FuelLogDetailView(fuelLog: log)) {
FuelLogSummaryView(log: log, mpg: mpg, distanceSincePrevious: distance)
}
}
.onDelete(perform: deleteFuelLogs)
}
.listStyle(InsetGroupedListStyle())
.navigationTitle("Fuel Logs")
.toolbar {
ToolbarItem(placement: .navigationBarTrailing) {
Button {
showingAddFuelLog = true
} label: {
Label("Add Fuel Log", systemImage: "plus")
}
}
ToolbarItem(placement: .navigationBarLeading) {
EditButton()
}
}
.sheet(isPresented: $showingAddFuelLog) {
AddFuelLogView().environment(\.managedObjectContext, viewContext)
}
.onAppear {
print("Total fuel logs: \(fuelLogs.count)")
setDefaultVehicle()
}
}
}
.alert(isPresented: $showOdometerAlert) {
Alert(title: Text("Odometer Reading Error"),
message: Text("Odometer reading must be greater than the previous record (\(previousOdometerString))."),
dismissButton: .default(Text("OK")))
}
}
private func setDefaultVehicle() {
if selectedVehicleID == nil {
if let lastFuelLog = fuelLogs.first, let vehicle = lastFuelLog.vehicle {
selectedVehicleID = vehicle.id
} else {
selectedVehicleID = vehicles.first?.id
}
}
}
private func deleteFuelLogs(offsets: IndexSet) {
withAnimation {
let logsToDelete = offsets.map { filteredFuelLogs[$0] }
logsToDelete.forEach { viewContext.delete($0) }
do {
try viewContext.save()
} catch {
let nsError = error as NSError
fatalError("Unresolved error \(nsError), \(nsError.userInfo)")
}
}
}
}