| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153 |
- import 'package:flutter/material.dart';
- import '../../../core/theme/app_colors.dart';
- import '../../../core/widgets/surface_card.dart';
- /// Compact live car data shown only while the ELM327 adapter is delivering
- /// fresh speed/throttle values.
- class ObdCard extends StatelessWidget {
- const ObdCard({
- super.key,
- required this.speedKmh,
- required this.throttlePercent,
- required this.economyL100,
- this.compact = false,
- });
- final double? speedKmh;
- final double? throttlePercent;
- final double? economyL100;
- final bool compact;
- @override
- Widget build(BuildContext context) {
- final colors = context.colors;
- final theme = Theme.of(context);
- final throttle = (throttlePercent ?? 0).clamp(0.0, 100.0);
- return SurfaceCard(
- padding: EdgeInsets.fromLTRB(
- compact ? 16 : 20,
- compact ? 13 : 16,
- compact ? 16 : 20,
- compact ? 13 : 16,
- ),
- radius: 24,
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Row(
- children: [
- Container(
- width: 7,
- height: 7,
- decoration: BoxDecoration(
- color: colors.accent,
- shape: BoxShape.circle,
- ),
- ),
- const SizedBox(width: 8),
- Text(
- 'OBD-II',
- style: theme.textTheme.labelMedium?.copyWith(
- color: colors.inkMuted,
- letterSpacing: 0.8,
- ),
- ),
- const Spacer(),
- Text(
- 'LIVE',
- style: theme.textTheme.labelSmall?.copyWith(
- color: colors.accent,
- fontWeight: FontWeight.w700,
- letterSpacing: 0.8,
- ),
- ),
- ],
- ),
- SizedBox(height: compact ? 6 : 8),
- Row(
- crossAxisAlignment: CrossAxisAlignment.end,
- children: [
- Text(
- speedKmh == null ? '—' : speedKmh!.round().toString(),
- style: theme.textTheme.displaySmall?.copyWith(
- fontSize: compact ? 38 : 46,
- height: 0.95,
- fontFeatures: const [FontFeature.tabularFigures()],
- ),
- ),
- const SizedBox(width: 7),
- Padding(
- padding: const EdgeInsets.only(bottom: 5),
- child: Text(
- 'km/h',
- style: theme.textTheme.bodySmall?.copyWith(
- color: colors.inkMuted,
- ),
- ),
- ),
- ],
- ),
- SizedBox(height: compact ? 7 : 9),
- Row(
- children: [
- Text(
- 'Throttle',
- style: theme.textTheme.bodySmall?.copyWith(
- color: colors.inkMuted,
- ),
- ),
- const Spacer(),
- Text(
- '${throttle.round()}%',
- style: theme.textTheme.labelMedium?.copyWith(
- color: colors.ink,
- fontFeatures: const [FontFeature.tabularFigures()],
- ),
- ),
- ],
- ),
- const SizedBox(height: 5),
- ClipRRect(
- borderRadius: BorderRadius.circular(999),
- child: TweenAnimationBuilder<double>(
- tween: Tween(begin: 0, end: throttle / 100),
- duration: const Duration(milliseconds: 180),
- curve: Curves.easeOut,
- builder: (context, value, _) {
- return LinearProgressIndicator(
- value: value,
- minHeight: compact ? 5 : 6,
- backgroundColor: colors.border,
- valueColor: AlwaysStoppedAnimation(colors.accent),
- );
- },
- ),
- ),
- SizedBox(height: compact ? 7 : 9),
- Row(
- children: [
- Text(
- 'Rolling economy',
- style: theme.textTheme.bodySmall?.copyWith(
- color: colors.inkMuted,
- ),
- ),
- const Spacer(),
- Text(
- economyL100 == null
- ? '—'
- : '${economyL100!.toStringAsFixed(1)} L/100 km',
- style: theme.textTheme.labelMedium?.copyWith(
- color: colors.ink,
- fontFeatures: const [FontFeature.tabularFigures()],
- ),
- ),
- ],
- ),
- ],
- ),
- );
- }
- }
|