MotorSignal-App/lib/features/dashboard/widgets/performance_summary.dart

121 lines
4.5 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../../core/theme/app_colors.dart';
import '../../../core/theme/app_typography.dart';
import '../../performance/models/performance_launch_models.dart';
import '../../performance/performance_providers.dart';
import '../../performance/performance_timer_service.dart';
/// Performance run summary chip / card (0-60 and 0-100 timing).
///
/// Observes authoritative [performanceLaunchProvider] and falls back to
/// [performanceTimerProvider] to display active timing or last completed benchmark.
class PerformanceSummary extends ConsumerWidget {
final bool compact;
const PerformanceSummary({
super.key,
this.compact = false,
});
@override
Widget build(BuildContext context, WidgetRef ref) {
final attempt = ref.watch(performanceLaunchProvider);
final perfData = ref.watch(performanceTimerProvider);
final isDark = Theme.of(context).brightness == Brightness.dark;
// 1. Live timing check: authoritative launch state machine first, then timer service
if (attempt.state == PerformanceLaunchState.launched) {
final elapsed = attempt.currentElapsedSeconds ?? 0.0;
final targetStr = attempt.target == PerformanceLaunchTarget.sixty ? '0-60' : '0-100';
return _buildTimingChip(context, targetStr, elapsed);
}
if (perfData.state == PerformanceState.timing) {
final elapsed = perfData.currentElapsedSeconds ?? 0.0;
final targetStr = perfData.target == PerformanceTarget.sixty ? '0-60' : '0-100';
return _buildTimingChip(context, targetStr, elapsed);
}
// 2. Completed result check: authoritative launch result first, then timer result
if (attempt.lastResult != null) {
final result = attempt.lastResult!;
final targetStr = result.target == PerformanceLaunchTarget.sixty ? '0-60' : '0-100';
return _buildResultChip(context, targetStr, result.accelerationTimeSec, isDark);
}
if (perfData.lastResult != null) {
final lastResult = perfData.lastResult!;
final targetStr = lastResult.target == PerformanceTarget.sixty ? '0-60' : '0-100';
return _buildResultChip(context, targetStr, lastResult.timeSeconds, isDark);
}
return const SizedBox.shrink();
}
Widget _buildTimingChip(BuildContext context, String targetStr, double elapsed) {
return GestureDetector(
onTap: () => context.push('/launch'),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
decoration: BoxDecoration(
color: AppColors.telemetryGreen.withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(6),
border: Border.all(color: AppColors.telemetryGreen, width: 1.0),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.timer, color: AppColors.telemetryGreen, size: 14),
const SizedBox(width: 5),
Text(
'$targetStr: ${elapsed.toStringAsFixed(2)}s',
style: const TextStyle(
fontFamily: AppTypography.fontTelemetry,
fontSize: 11,
fontWeight: FontWeight.w800,
color: AppColors.telemetryGreen,
),
),
],
),
),
);
}
Widget _buildResultChip(BuildContext context, String targetStr, double timeSeconds, bool isDark) {
return GestureDetector(
onTap: () => context.push('/launch'),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
decoration: BoxDecoration(
color: isDark ? AppColors.darkSurfaceContainer : AppColors.lightSurfaceContainer,
borderRadius: BorderRadius.circular(6),
border: Border.all(
color: isDark ? AppColors.darkOutline : AppColors.lightOutline,
width: 0.8,
),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
const Icon(Icons.emoji_events_outlined, size: 13, color: AppColors.warningAmber),
const SizedBox(width: 4),
Text(
'$targetStr: ${timeSeconds.toStringAsFixed(2)}s',
style: TextStyle(
fontFamily: AppTypography.fontTelemetry,
fontSize: 10,
fontWeight: FontWeight.w700,
color: isDark ? Colors.white70 : AppColors.lightOnSurface,
),
),
],
),
),
);
}
}