MotorSignal-App/lib/features/garage/garage_screen.dart

241 lines
10 KiB
Dart

import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../database/database.dart';
import '../../models/motorcycle_models.dart';
import '../../core/theme/evolution_theme_config.dart';
import 'garage_providers.dart';
class GarageScreen extends ConsumerWidget {
const GarageScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final bikesAsync = ref.watch(garageMotorcyclesStreamProvider);
final themeMode = ref.watch(dashboardThemeModeProvider);
return Scaffold(
backgroundColor: themeMode == DashboardThemeMode.evolution ? Colors.black : null,
appBar: AppBar(
backgroundColor: themeMode == DashboardThemeMode.evolution ? Colors.transparent : null,
elevation: 0,
title: Text(
'My Garage',
style: TextStyle(
fontFamily: themeMode == DashboardThemeMode.evolution ? 'Sora' : null,
fontWeight: FontWeight.bold,
),
),
actions: [
IconButton(
icon: const Icon(Icons.add_circle_outline, color: Color(0xFF00E5FF)),
tooltip: 'Add Motorcycle',
onPressed: () => context.push('/garage/add'),
),
],
),
body: bikesAsync.when(
loading: () => const Center(child: CircularProgressIndicator()),
error: (err, stack) => Center(child: Text('Error loading garage: $err')),
data: (bikes) {
if (bikes.isEmpty) {
return _buildEmptyState(context);
}
return ListView.builder(
padding: const EdgeInsets.all(16.0),
itemCount: bikes.length,
itemBuilder: (context, index) {
final bike = bikes[index];
return _buildMotorcycleCard(context, ref, bike, themeMode);
},
);
},
),
floatingActionButton: bikesAsync.value != null && bikesAsync.value!.isNotEmpty
? FloatingActionButton.extended(
backgroundColor: Colors.cyanAccent,
foregroundColor: Colors.black,
icon: const Icon(Icons.two_wheeler),
label: const Text('ADD MOTORCYCLE', style: TextStyle(fontWeight: FontWeight.bold)),
onPressed: () => context.push('/garage/add'),
)
: null,
);
}
Widget _buildEmptyState(BuildContext context) {
return Center(
child: Padding(
padding: const EdgeInsets.all(32.0),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.two_wheeler, size: 80, color: Colors.white24),
const SizedBox(height: 24),
const Text(
'YOUR GARAGE IS EMPTY',
style: TextStyle(fontSize: 20, fontWeight: FontWeight.bold, letterSpacing: 1.5),
),
const SizedBox(height: 12),
const Text(
'Add your motorcycle to personalize your ride history and performance data.',
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white70, height: 1.4),
),
const SizedBox(height: 32),
ElevatedButton.icon(
style: ElevatedButton.styleFrom(
backgroundColor: Colors.cyanAccent,
foregroundColor: Colors.black,
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 14),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
),
icon: const Icon(Icons.add),
label: const Text('ADD MOTORCYCLE', style: TextStyle(fontWeight: FontWeight.bold, letterSpacing: 1.2)),
onPressed: () => context.push('/garage/add'),
),
],
),
),
);
}
Widget _buildMotorcycleCard(BuildContext context, WidgetRef ref, GarageMotorcycle bike, DashboardThemeMode themeMode) {
MotorcycleSpecification? spec;
if (bike.specificationJson != null) {
try {
spec = MotorcycleSpecification.fromJson(json.decode(bike.specificationJson!));
} catch (_) {}
}
final displayName = bike.nickname != null && bike.nickname!.isNotEmpty
? '${bike.nickname} (${bike.year} ${bike.makeName} ${bike.modelName})'
: '${bike.year} ${bike.makeName} ${bike.modelName}';
final isEvolution = themeMode == DashboardThemeMode.evolution;
return Container(
margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration(
color: isEvolution ? const Color(0xFF0D0D0D) : null,
borderRadius: BorderRadius.circular(isEvolution ? 14 : 12),
border: Border.all(
color: bike.isDefault
? const Color(0xFF00E5FF)
: (isEvolution ? const Color(0xFF1F1F1F) : Colors.white12),
width: bike.isDefault ? 1.8 : 1.0,
),
),
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(isEvolution ? 14 : 12),
onTap: () => context.push('/garage/${bike.id}'),
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Container(
padding: const EdgeInsets.all(12),
decoration: BoxDecoration(
color: isEvolution ? const Color(0xFF141414) : Colors.white10,
borderRadius: BorderRadius.circular(10),
border: isEvolution ? Border.all(color: const Color(0xFF222222)) : null,
),
child: const Icon(Icons.two_wheeler, size: 36, color: Color(0xFF00E5FF)),
),
const SizedBox(width: 16),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
displayName,
style: TextStyle(
fontFamily: isEvolution ? 'Sora' : null,
fontSize: 17,
fontWeight: FontWeight.w800,
color: Colors.white,
),
),
),
if (bike.isDefault)
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2),
decoration: BoxDecoration(
color: const Color(0xFF00E5FF).withValues(alpha: 0.15),
borderRadius: BorderRadius.circular(4),
border: Border.all(color: const Color(0xFF00E5FF)),
),
child: const Text(
'CURRENT',
style: TextStyle(
fontFamily: 'Inter',
fontSize: 10,
fontWeight: FontWeight.w900,
color: Color(0xFF00E5FF),
letterSpacing: 0.5,
),
),
),
],
),
const SizedBox(height: 6),
Text(
spec != null
? '${spec.displacementCc?.toStringAsFixed(0) ?? "—"} cc • ${spec.horsepower?.toStringAsFixed(0) ?? "—"} hp'
: '${bike.year} • ${bike.makeName}',
style: TextStyle(
fontFamily: isEvolution ? 'JetBrains Mono' : null,
color: isEvolution ? const Color(0xFF00E5FF) : Colors.white70,
fontSize: 13,
fontWeight: isEvolution ? FontWeight.w700 : FontWeight.normal,
),
),
],
),
),
],
),
const SizedBox(height: 16),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
TextButton.icon(
icon: const Icon(Icons.directions_bike, size: 18),
label: const Text('View Specs & Stats'),
onPressed: () => context.push('/garage/${bike.id}'),
),
if (!bike.isDefault)
OutlinedButton(
style: OutlinedButton.styleFrom(
foregroundColor: Colors.white,
side: const BorderSide(color: Colors.white30),
),
onPressed: () {
ref.read(garageControllerProvider).setDefaultMotorcycle(bike.id);
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Set ${bike.makeName} ${bike.modelName} as current motorcycle.')),
);
},
child: const Text('Set as Current'),
),
],
),
],
),
),
),
),
);
}
}