import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'dart:math' as math; import '../../database/database.dart'; import '../garage/garage_providers.dart'; import 'ride_detail_screen.dart'; class HistoryScreen extends ConsumerStatefulWidget { const HistoryScreen({super.key}); @override ConsumerState createState() => _HistoryScreenState(); } class _HistoryScreenState extends ConsumerState { int? _selectedMotorcycleId; // null = All Motorcycles, -1 = Current, else specific ID @override Widget build(BuildContext context) { final database = ref.watch(databaseProvider); final garageBikesAsync = ref.watch(garageMotorcyclesStreamProvider); final defaultBike = ref.watch(defaultMotorcycleProvider); return Scaffold( appBar: AppBar(title: const Text('Ride History')), body: Column( children: [ _buildFilterBar(garageBikesAsync.value ?? [], defaultBike), Expanded( child: StreamBuilder>( stream: database.select(database.rides).watch(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } if (snapshot.hasError) { return Center(child: Text('Error: ${snapshot.error}')); } var rides = snapshot.data ?? []; // Filter logic if (_selectedMotorcycleId == -1 && defaultBike != null) { rides = rides .where((r) => r.motorcycleId == defaultBike.id) .toList(); } else if (_selectedMotorcycleId != null && _selectedMotorcycleId! > 0) { rides = rides .where((r) => r.motorcycleId == _selectedMotorcycleId) .toList(); } // Sort by start time descending rides.sort((a, b) => b.startTime.compareTo(a.startTime)); if (rides.isEmpty) { return const Center( child: Text( 'No recorded rides matching filter.', style: TextStyle(fontSize: 18, color: Colors.grey), ), ); } return ListView.builder( padding: const EdgeInsets.all(8), itemCount: rides.length, itemBuilder: (context, index) { final ride = rides[index]; final bikeName = (ride.motorcycleYear != null && ride.motorcycleMake != null && ride.motorcycleModel != null) ? '${ride.motorcycleYear} ${ride.motorcycleMake} ${ride.motorcycleModel}' : null; return Card( elevation: 4, margin: const EdgeInsets.symmetric( vertical: 8, horizontal: 4, ), child: InkWell( key: ValueKey('history_ride_card_${ride.id}'), onTap: () { Navigator.of(context).push( MaterialPageRoute( builder: (_) => RideDetailScreen(ride: ride), ), ); }, child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: Row( children: [ Text( 'Ride ${ride.id}', style: const TextStyle( fontWeight: FontWeight.bold, fontSize: 18, ), ), if (bikeName != null) ...[ const SizedBox(width: 8), Flexible( child: Container( padding: const EdgeInsets.symmetric( horizontal: 6, vertical: 2, ), decoration: BoxDecoration( color: Colors.cyanAccent .withValues(alpha: 0.15), borderRadius: BorderRadius.circular(4), border: Border.all( color: Colors.cyanAccent .withValues(alpha: 0.5), ), ), child: Text( bikeName, maxLines: 1, overflow: TextOverflow.ellipsis, style: const TextStyle( fontSize: 11, fontWeight: FontWeight.bold, color: Colors.cyanAccent, ), ), ), ), ], ], ), ), const SizedBox(width: 8), Text( ride.startTime.toLocal().toString().split( '.', )[0], style: const TextStyle( color: Colors.grey, fontSize: 11, ), ), ], ), const Divider(), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ _buildStatCol( 'TRIP', '${ride.distanceMiles.toStringAsFixed(1)} mi', ), _buildStatCol( 'TIME', '${(ride.movingTime / 60).toStringAsFixed(0)} min', ), _buildStatCol( 'TOP SPD', '${ride.topSpeedMph.toStringAsFixed(0)} mph', ), ], ), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ _buildStatCol( 'MAX LEAN', '${math.max(ride.maxLeanLeft, ride.maxLeanRight).toStringAsFixed(0)}°', ), _buildStatCol( 'HARD BRK', '${ride.maxBrakingG.toStringAsFixed(2)}G', ), _buildStatCol( 'ELEV GAIN', '${ride.elevationGain.toStringAsFixed(0)}m', ), ], ), ], ), ), ), ); }, ); }, ), ), ], ), ); } Widget _buildFilterBar( List bikes, GarageMotorcycle? defaultBike, ) { if (bikes.isEmpty) return const SizedBox(); return Padding( padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 8.0), child: Row( children: [ const Icon(Icons.filter_alt, color: Colors.cyanAccent, size: 20), const SizedBox(width: 8), Expanded( child: Container( padding: const EdgeInsets.symmetric(horizontal: 12), decoration: BoxDecoration( color: Colors.white10, borderRadius: BorderRadius.circular(8), ), child: DropdownButtonHideUnderline( child: DropdownButton( value: _selectedMotorcycleId, isExpanded: true, dropdownColor: const Color(0xFF1E1E1E), hint: const Text('Filter by Motorcycle'), items: [ const DropdownMenuItem( value: null, child: Text('All Motorcycles'), ), if (defaultBike != null) DropdownMenuItem( value: -1, child: Text('Current (${defaultBike.modelName})'), ), ...bikes.map( (b) => DropdownMenuItem( value: b.id, child: Text('${b.year} ${b.makeName} ${b.modelName}'), ), ), ], onChanged: (val) { setState(() { _selectedMotorcycleId = val; }); }, ), ), ), ), ], ), ); } Widget _buildStatCol(String label, String val) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(label, style: const TextStyle(fontSize: 10, color: Colors.grey)), Text( val, style: const TextStyle(fontSize: 16, fontWeight: FontWeight.bold), ), ], ); } }