import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:intl/intl.dart'; import 'package:go_router/go_router.dart'; import '../../database/database.dart'; import '../../core/responsive/responsive_layout.dart'; import '../../core/theme/theme_extensions.dart'; import '../../services/export_service.dart'; import '../../services/entitlements/entitlement_providers.dart'; import '../../services/entitlements/feature_access_service.dart'; import '../../services/github/github_sync_service.dart'; import '../entitlements/widgets/pro_lock_badge.dart'; import '../replay/replay_screen.dart'; import '../map/map_screen.dart'; class RideDetailScreen extends ConsumerStatefulWidget { final Ride ride; const RideDetailScreen({super.key, required this.ride}); @override ConsumerState createState() => _RideDetailScreenState(); } class _RideDetailScreenState extends ConsumerState { List _events = []; bool _isLoadingEvents = true; @override void initState() { super.initState(); _loadEvents(); } Future _loadEvents() async { final db = ref.read(databaseProvider); final events = await (db.select( db.rideEvents, )..where((e) => e.rideId.equals(widget.ride.id))).get(); if (mounted) { setState(() { _events = events; _isLoadingEvents = false; }); } } @override Widget build(BuildContext context) { final ride = widget.ride; final colors = context.motorColors; final theme = Theme.of(context); final bikeName = (ride.motorcycleYear != null && ride.motorcycleMake != null && ride.motorcycleModel != null) ? '${ride.motorcycleYear} ${ride.motorcycleMake} ${ride.motorcycleModel}' .toUpperCase() : null; final durationSec = ride.endTime != null ? ride.endTime!.difference(ride.startTime).inSeconds : (ride.movingTime + ride.stoppedTime); final durationMin = (durationSec / 60).toStringAsFixed(0); final movingMin = (ride.movingTime / 60).toStringAsFixed(0); final syncService = ref.watch(githubSyncServiceProvider); final isUploaded = syncService.isRideUploaded(ride.id); final commitSha = syncService.getRideCommitSha(ride.id); return Scaffold( appBar: AppBar( title: FittedBox( fit: BoxFit.scaleDown, child: Text( 'Ride #${ride.id} Telemetry', style: const TextStyle(fontWeight: FontWeight.bold), ), ), actions: [ IconButton( icon: Icon(Icons.share, color: colors.cyberCyan), tooltip: 'Export CSV', onPressed: () async { final isPro = ref .read(featureAccessProvider) .canAccess(MotorSignalFeature.csvExport); if (!isPro) { showProUpgradeSheet( context, ref, feature: MotorSignalFeature.csvExport, ); return; } final exporter = ref.read(exportServiceProvider); await exporter.exportRide(ride.id, asGpx: false); }, ), IconButton( icon: Icon(Icons.delete_outline, color: colors.raceRed), tooltip: 'Delete Ride', onPressed: () => _confirmDelete(context, ride), ), ], ), body: ResponsiveLayout( builder: (context, responsive) { final isWide = responsive.isExpanded || (responsive.isMedium && responsive.isLandscape); if (isWide) { return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildGitHubSyncBanner(context, ref, syncService, isUploaded, commitSha, colors), const SizedBox(height: 16), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( flex: 5, child: Column( children: [ _buildHeroHeaderRow(context, ride, bikeName, colors), const SizedBox(height: 16), _buildSessionOverview(ride, durationMin, movingMin, colors, theme), const SizedBox(height: 16), _buildActionButtons(context, ride, colors, isNarrow: responsive.width < 800), ], ), ), const SizedBox(width: 16), Expanded( flex: 5, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildHandlingSection( ride, colors, isLandscape: responsive.isExpanded && responsive.width >= 900, ), const SizedBox(height: 16), _buildForensicEventsSection(context, colors, theme), ], ), ), ], ), ], ), ); } return SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildGitHubSyncBanner(context, ref, syncService, isUploaded, commitSha, colors), const SizedBox(height: 14), _buildHeroHeaderRow(context, ride, bikeName, colors), const SizedBox(height: 16), _buildSessionOverview(ride, durationMin, movingMin, colors, theme), const SizedBox(height: 16), _buildHandlingSection(ride, colors, isLandscape: false), const SizedBox(height: 16), _buildForensicEventsSection(context, colors, theme), const SizedBox(height: 20), _buildActionButtons(context, ride, colors, isNarrow: responsive.width < 450), const SizedBox(height: 24), ], ), ); }, ), ); } Widget _buildGitHubSyncBanner( BuildContext context, WidgetRef ref, GitHubSyncService syncService, bool isUploaded, String? commitSha, MotorSignalThemeColors colors, ) { final isSyncing = syncService.state == GitHubUploadState.uploading; return Container( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 8), decoration: BoxDecoration( color: colors.surfaceContainer, borderRadius: BorderRadius.circular(12), border: Border.all( color: isUploaded ? colors.launchGreen.withValues(alpha: 0.6) : colors.cyberCyan.withValues(alpha: 0.4), width: 1.2, ), ), child: Row( children: [ Icon( isUploaded ? Icons.cloud_done : (isSyncing ? Icons.cloud_sync : Icons.cloud_upload_outlined), color: isUploaded ? colors.launchGreen : colors.cyberCyan, size: 20, ), const SizedBox(width: 8), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisSize: MainAxisSize.min, children: [ Text( isUploaded ? 'GITHUB LOGS SYNCHRONIZED' : (isSyncing ? 'UPLOADING TO GITHUB...' : 'GITHUB LOG SYNC'), maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'Sora', fontSize: 10.5, fontWeight: FontWeight.w800, color: isUploaded ? colors.launchGreen : Theme.of(context).colorScheme.onSurface, ), ), Text( isUploaded ? 'Commit: ${commitSha != null && commitSha.length >= 7 ? commitSha.substring(0, 7) : "synced"}' : 'Repository: bponders12-cell/ride_logs', maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'JetBrains Mono', fontSize: 9, color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.6), ), ), ], ), ), if (!isUploaded) ...[ const SizedBox(width: 6), TextButton( onPressed: isSyncing ? null : () async { final result = await syncService.uploadRide( widget.ride.id, isManual: true, ); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text(result.message), backgroundColor: result.success ? colors.launchGreen : colors.raceRed, ), ); } }, style: TextButton.styleFrom( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 4, ), minimumSize: Size.zero, tapTargetSize: MaterialTapTargetSize.shrinkWrap, backgroundColor: colors.cyberCyan.withValues(alpha: 0.15), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), child: Text( isSyncing ? 'SYNCING...' : 'UPLOAD', style: TextStyle( fontFamily: 'JetBrains Mono', fontSize: 9.5, fontWeight: FontWeight.w800, color: colors.cyberCyan, ), ), ), ], ], ), ); } Widget _buildHeroHeaderRow( BuildContext context, Ride ride, String? bikeName, MotorSignalThemeColors colors, ) { return Row( children: [ Expanded( child: Container( constraints: const BoxConstraints(minHeight: 120), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 10), decoration: BoxDecoration( color: colors.surfaceContainer, borderRadius: BorderRadius.circular(14), border: Border.all(color: colors.outlineVariant, width: 1.2), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.two_wheeler, color: colors.cyberCyan, size: 32, ), const SizedBox(height: 4), Text( bikeName ?? 'MOTORCYCLE', textAlign: TextAlign.center, maxLines: 2, overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'Sora', fontSize: 10.5, fontWeight: FontWeight.w800, color: Theme.of(context).colorScheme.onSurface, ), ), if (ride.motorcycleId != null) ...[ const SizedBox(height: 4), InkWell( onTap: () => context.push('/garage/${ride.motorcycleId}'), child: Text( 'VIEW SPECS >', style: TextStyle( fontFamily: 'JetBrains Mono', fontSize: 8.5, fontWeight: FontWeight.bold, color: colors.cyberCyan, ), ), ), ], ], ), ), ), const SizedBox(width: 10), Expanded( child: Material( color: Colors.transparent, child: InkWell( onTap: () { Navigator.of(context).push( MaterialPageRoute( builder: (_) => MapScreen(rideId: ride.id), ), ); }, borderRadius: BorderRadius.circular(14), child: Container( constraints: const BoxConstraints(minHeight: 120), padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 10), decoration: BoxDecoration( color: colors.surfaceContainer, borderRadius: BorderRadius.circular(14), border: Border.all( color: colors.cyberCyan.withValues(alpha: 0.5), width: 1.2, ), ), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.map_rounded, color: colors.cyberCyan, size: 32, ), const SizedBox(height: 4), FittedBox( fit: BoxFit.scaleDown, child: Text( 'ROUTE PREVIEW', style: TextStyle( fontFamily: 'JetBrains Mono', fontSize: 10.5, fontWeight: FontWeight.w900, color: colors.cyberCyan, letterSpacing: 0.08, ), ), ), const SizedBox(height: 4), Container( padding: const EdgeInsets.symmetric( horizontal: 6, vertical: 2, ), decoration: BoxDecoration( color: colors.cyberCyan.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(6), ), child: FittedBox( fit: BoxFit.scaleDown, child: Text( 'VIEW MAP >', style: TextStyle( fontFamily: 'JetBrains Mono', fontSize: 8, fontWeight: FontWeight.w800, color: colors.cyberCyan, ), ), ), ), ], ), ), ), ), ), ], ); } Widget _buildSessionOverview( Ride ride, String durationMin, String movingMin, MotorSignalThemeColors colors, ThemeData theme, ) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildSectionHeader('SESSION OVERVIEW', colors), const SizedBox(height: 8), Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: colors.surfaceContainer, borderRadius: BorderRadius.circular(14), border: Border.all(color: colors.outlineVariant, width: 1.2), ), child: Column( children: [ _buildMetricRow( 'DISTANCE:', '${ride.distanceMiles.toStringAsFixed(2)} mi', 'DURATION:', '$durationMin min', theme, colors, ), Divider(color: colors.outlineVariant, height: 18), _buildMetricRow( 'MOVING TIME:', '$movingMin min', 'AVG SPEED:', '${ride.averageSpeed.toStringAsFixed(1)} mph', theme, colors, ), Divider(color: colors.outlineVariant, height: 18), _buildMetricRow( 'TOP SPEED:', '${ride.topSpeedMph.toStringAsFixed(1)} mph', 'DATE:', DateFormat('MM/dd/yyyy').format(ride.startTime.toLocal()), theme, colors, ), Divider(color: colors.outlineVariant, height: 18), _buildMetricRow( 'ELEV GAIN:', '${ride.elevationGain.toStringAsFixed(0)} m', 'ELEV LOSS:', '${ride.elevationLoss.toStringAsFixed(0)} m', theme, colors, ), ], ), ), ], ); } Widget _buildHandlingSection( Ride ride, MotorSignalThemeColors colors, { required bool isLandscape, }) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ _buildSectionHeader('HANDLING & DYNAMICS', colors), const SizedBox(height: 8), _buildResponsiveHandlingCards(ride, colors, isLandscape), ], ); } Widget _buildResponsiveHandlingCards( Ride ride, MotorSignalThemeColors colors, bool isLandscape, ) { final cards = [ _buildHandlingKpiCard( 'MAX LEAN (LEFT)', '${ride.maxLeanLeft.toStringAsFixed(1)}°', Icons.turn_left, colors.leanAngleLeft, colors, ), _buildHandlingKpiCard( 'MAX LEAN (RIGHT)', '${ride.maxLeanRight.toStringAsFixed(1)}°', Icons.turn_right, colors.leanAngleRight, colors, ), _buildHandlingKpiCard( 'MAX ACCELERATION', '${ride.maxAccelG.toStringAsFixed(2)} G', Icons.speed, colors.gForcePositive, colors, ), _buildHandlingKpiCard( 'MAX BRAKING', '${ride.maxBrakingG.toStringAsFixed(2)} G', Icons.pan_tool_alt, colors.gForceNegative, colors, ), ]; if (isLandscape) { return Row( children: cards .map( (c) => Expanded( child: Padding( padding: const EdgeInsets.symmetric(horizontal: 4), child: c, ), ), ) .toList(), ); } return Column( children: [ Row( children: [ Expanded(child: cards[0]), const SizedBox(width: 8), Expanded(child: cards[1]), ], ), const SizedBox(height: 8), Row( children: [ Expanded(child: cards[2]), const SizedBox(width: 8), Expanded(child: cards[3]), ], ), ], ); } Widget _buildHandlingKpiCard( String label, String value, IconData icon, Color accentColor, MotorSignalThemeColors colors, ) { return Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 12), decoration: BoxDecoration( color: colors.surfaceContainer, borderRadius: BorderRadius.circular(12), border: Border.all(color: colors.outlineVariant, width: 1.2), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Text( label, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'Inter', fontSize: 9.5, fontWeight: FontWeight.w700, color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.6), ), ), ), Icon(icon, color: accentColor, size: 16), ], ), const SizedBox(height: 6), FittedBox( fit: BoxFit.scaleDown, alignment: Alignment.centerLeft, child: Text( value, style: TextStyle( fontFamily: 'JetBrains Mono', fontSize: 18, fontWeight: FontWeight.w900, color: Theme.of(context).colorScheme.onSurface, ), ), ), ], ), ); } Widget _buildForensicEventsSection( BuildContext context, MotorSignalThemeColors colors, ThemeData theme, ) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: _buildSectionHeader('FORENSIC EVENTS (${_events.length})', colors), ), if (_events.isNotEmpty) Text( 'TAP TO INSPECT', style: TextStyle( fontFamily: 'JetBrains Mono', fontSize: 9, fontWeight: FontWeight.w700, color: colors.cyberCyan, ), ), ], ), const SizedBox(height: 8), Container( padding: const EdgeInsets.all(10), decoration: BoxDecoration( color: colors.surfaceContainer, borderRadius: BorderRadius.circular(14), border: Border.all(color: colors.outlineVariant, width: 1.2), ), child: _isLoadingEvents ? const Padding( padding: EdgeInsets.all(16), child: Center(child: CircularProgressIndicator()), ) : _events.isEmpty ? Padding( padding: const EdgeInsets.symmetric(vertical: 16), child: Center( child: Text( 'No threshold handling events registered during this session.', style: TextStyle( fontFamily: 'Inter', fontSize: 12, color: theme.colorScheme.onSurface.withValues(alpha: 0.6), ), ), ), ) : Column( children: _events .take(15) .map( (event) => _buildInteractiveEventTile(context, event, colors), ) .toList(), ), ), ], ); } Widget _buildInteractiveEventTile( BuildContext context, RideEvent event, MotorSignalThemeColors colors, ) { Color badgeColor = colors.warningAmber; IconData eventIcon = Icons.warning_amber_rounded; if (event.eventType.toLowerCase().contains('accel')) { badgeColor = colors.launchGreen; eventIcon = Icons.arrow_upward; } else if (event.eventType.toLowerCase().contains('brak')) { badgeColor = colors.raceRed; eventIcon = Icons.arrow_downward; } else if (event.eventType.toLowerCase().contains('corner') || event.eventType.toLowerCase().contains('lean')) { badgeColor = colors.cyberCyan; eventIcon = Icons.cached; } String formattedValue = '${event.value.toStringAsFixed(1)}°'; if (event.eventType.toLowerCase().contains('accel') || event.eventType.toLowerCase().contains('brak')) { formattedValue = '${event.value.toStringAsFixed(2)} G'; } final timeStr = DateFormat('HH:mm:ss.SSS').format(event.timestamp.toLocal()); return Material( color: Colors.transparent, child: InkWell( onTap: () => _showEventDetailsDialog( context, event, formattedValue, timeStr, badgeColor, ), borderRadius: BorderRadius.circular(8), child: Padding( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 6), child: Row( children: [ Icon(eventIcon, color: badgeColor, size: 16), const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( event.eventType.toUpperCase(), maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'JetBrains Mono', fontSize: 11, fontWeight: FontWeight.w800, color: Theme.of(context).colorScheme.onSurface, ), ), Text( timeStr, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'JetBrains Mono', fontSize: 9, color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.5), ), ), ], ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2), decoration: BoxDecoration( color: badgeColor.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(4), ), child: Text( formattedValue, style: TextStyle( fontFamily: 'JetBrains Mono', fontSize: 11, fontWeight: FontWeight.w700, color: badgeColor, ), ), ), const SizedBox(width: 6), Icon( Icons.chevron_right, color: Theme.of(context).colorScheme.onSurface.withValues(alpha: 0.3), size: 16, ), ], ), ), ), ); } void _showEventDetailsDialog( BuildContext context, RideEvent event, String formattedValue, String timeStr, Color badgeColor, ) { showDialog( context: context, builder: (c) => AlertDialog( title: Row( children: [ Icon(Icons.info_outline, color: badgeColor), const SizedBox(width: 8), Text(event.eventType.toUpperCase()), ], ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text('Timestamp: $timeStr'), const SizedBox(height: 8), Text('Recorded Value: $formattedValue'), const SizedBox(height: 8), Text('Ride ID: ${event.rideId}'), ], ), actions: [ TextButton( onPressed: () => Navigator.pop(c), child: const Text('CLOSE'), ), ], ), ); } Widget _buildActionButtons( BuildContext context, Ride ride, MotorSignalThemeColors colors, { required bool isNarrow, }) { Widget buildReplayButton() => OutlinedButton( onPressed: () { Navigator.of(context).push( MaterialPageRoute( builder: (_) => ReplayScreen(rideId: ride.id), ), ); }, style: OutlinedButton.styleFrom( foregroundColor: colors.cyberCyan, side: BorderSide(color: colors.cyberCyan, width: 1.5), padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), child: const FittedBox( fit: BoxFit.scaleDown, child: Text( 'REPLAY RIDE', style: TextStyle( fontFamily: 'Sora', fontWeight: FontWeight.w800, fontSize: 12, ), ), ), ); Widget buildGpxButton() => OutlinedButton( onPressed: () async { final exporter = ref.read(exportServiceProvider); await exporter.exportRide(ride.id, asGpx: true); }, style: OutlinedButton.styleFrom( foregroundColor: Theme.of(context).colorScheme.onSurface, side: BorderSide(color: colors.outlineVariant, width: 1.2), padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), child: const FittedBox( fit: BoxFit.scaleDown, child: Text( 'EXPORT GPX', style: TextStyle( fontFamily: 'Sora', fontWeight: FontWeight.w700, fontSize: 12, ), ), ), ); Widget buildCsvButton() => Builder( builder: (context) { final isProCsv = ref .watch(featureAccessProvider) .canAccess(MotorSignalFeature.csvExport); return OutlinedButton( onPressed: () async { if (!isProCsv) { showProUpgradeSheet( context, ref, feature: MotorSignalFeature.csvExport, ); return; } final exporter = ref.read(exportServiceProvider); await exporter.exportRide(ride.id, asGpx: false); }, style: OutlinedButton.styleFrom( foregroundColor: Theme.of(context).colorScheme.onSurface, side: BorderSide(color: colors.outlineVariant, width: 1.2), padding: const EdgeInsets.symmetric(vertical: 14), shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(10)), ), child: FittedBox( fit: BoxFit.scaleDown, child: Row( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.min, children: [ const Text( 'EXPORT CSV', style: TextStyle( fontFamily: 'Sora', fontWeight: FontWeight.w700, fontSize: 12, ), ), if (!isProCsv) ...[ const SizedBox(width: 6), const ProBadge( fontSize: 8, padding: EdgeInsets.symmetric(horizontal: 4, vertical: 1), ), ], ], ), ), ); }, ); if (isNarrow) { return Column( children: [ Row( children: [ Expanded(child: buildReplayButton()), const SizedBox(width: 8), Expanded(child: buildGpxButton()), ], ), const SizedBox(height: 8), SizedBox( width: double.infinity, child: buildCsvButton(), ), ], ); } return Row( children: [ Expanded(child: buildReplayButton()), const SizedBox(width: 8), Expanded(child: buildGpxButton()), const SizedBox(width: 8), Expanded(child: buildCsvButton()), ], ); } Widget _buildSectionHeader(String title, MotorSignalThemeColors colors) { return Text( title, style: TextStyle( fontFamily: 'Sora', fontSize: 12, fontWeight: FontWeight.w800, color: colors.cyberCyan, letterSpacing: 0.1, ), ); } Widget _buildMetricRow( String label1, String val1, String label2, String val2, ThemeData theme, MotorSignalThemeColors colors, ) { Widget buildItem(String label, String val) { return Row( children: [ Flexible( flex: 6, child: Text( label, maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'Inter', fontSize: 9.5, fontWeight: FontWeight.w700, color: theme.colorScheme.onSurface.withValues(alpha: 0.5), ), ), ), const SizedBox(width: 4), Expanded( flex: 5, child: FittedBox( fit: BoxFit.scaleDown, alignment: Alignment.centerLeft, child: Text( val, style: TextStyle( fontFamily: 'JetBrains Mono', fontSize: 11, fontWeight: FontWeight.w800, color: theme.colorScheme.onSurface, ), ), ), ), ], ); } return Row( children: [ Expanded(child: buildItem(label1, val1)), const SizedBox(width: 8), Expanded(child: buildItem(label2, val2)), ], ); } Future _confirmDelete(BuildContext context, Ride r) async { final colors = context.motorColors; final confirm = await showDialog( context: context, builder: (c) => AlertDialog( title: const Text('Delete Ride?'), content: const Text('This cannot be undone. Historical telemetry for this ride will be removed.'), actions: [ TextButton( onPressed: () => Navigator.pop(c, false), child: const Text('CANCEL'), ), TextButton( onPressed: () => Navigator.pop(c, true), child: Text( 'DELETE', style: TextStyle(color: colors.raceRed, fontWeight: FontWeight.bold), ), ), ], ), ); if (confirm == true && mounted) { final db = ref.read(databaseProvider); await (db.delete( db.telemetrySamples, )..where((t) => t.rideId.equals(r.id))).go(); await (db.delete( db.rideEvents, )..where((e) => e.rideId.equals(r.id))).go(); await (db.delete( db.rides, )..where((ride) => ride.id.equals(r.id))).go(); if (mounted && context.mounted) { Navigator.of(context).pop(); } } } }