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/responsive/responsive_layout.dart'; import '../../core/theme/theme_extensions.dart'; import 'garage_providers.dart'; import 'widgets/motorcycle_photo.dart'; import '../../services/entitlements/entitlement_providers.dart'; import '../../services/entitlements/feature_access_service.dart'; import '../entitlements/widgets/pro_lock_badge.dart'; class GarageScreen extends ConsumerWidget { const GarageScreen({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final bikesAsync = ref.watch(garageMotorcyclesStreamProvider); final colors = context.motorColors; return Scaffold( appBar: AppBar( title: const Text( 'My Garage', style: TextStyle(fontWeight: FontWeight.bold), ), ), 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, colors); return ResponsiveLayout( builder: (context, responsive) { final isMultiColumn = responsive.isExpanded || (responsive.isMedium && responsive.isLandscape); if (isMultiColumn) { return GridView.builder( padding: const EdgeInsets.all(16.0), gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( maxCrossAxisExtent: 550, mainAxisExtent: 420, crossAxisSpacing: 16, mainAxisSpacing: 16, ), itemCount: bikes.length, itemBuilder: (context, index) { return _buildMotorcycleCard(context, ref, bikes[index], colors, isGrid: true); }, ); } return ListView.builder( padding: const EdgeInsets.all(16.0), itemCount: bikes.length, itemBuilder: (context, index) { return _buildMotorcycleCard(context, ref, bikes[index], colors, isGrid: false); }, ); }, ); }, ), floatingActionButton: bikesAsync.value != null && bikesAsync.value!.isNotEmpty ? FloatingActionButton.extended( key: const ValueKey('garage_add_motorcycle_fab'), backgroundColor: colors.cyberCyan, foregroundColor: Colors.black, icon: const Icon(Icons.two_wheeler), label: const Text( 'Add Motorcycle', style: TextStyle(fontWeight: FontWeight.w600, letterSpacing: 0.2), ), onPressed: () => _onAddMotorcycle(context, ref, bikesAsync.value), ) : null, ); } void _onAddMotorcycle( BuildContext context, WidgetRef ref, List? bikes, ) { if (bikes != null && bikes.isNotEmpty) { final canAddMore = ref .read(featureAccessProvider) .canAccess(MotorSignalFeature.useMultipleMotorcycles); if (!canAddMore) { showProUpgradeSheet( context, ref, feature: MotorSignalFeature.useMultipleMotorcycles, ); return; } } context.push('/garage/add'); } Widget _buildEmptyState(BuildContext context, MotorSignalThemeColors colors) { final theme = Theme.of(context); return Center( child: Padding( padding: const EdgeInsets.all(32.0), child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( Icons.two_wheeler, size: 80, color: theme.colorScheme.onSurface.withValues(alpha: 0.25), ), const SizedBox(height: 24), Text( 'Your Garage is Empty', style: TextStyle( fontFamily: 'Sora', fontSize: 18, fontWeight: FontWeight.w700, letterSpacing: 0.2, color: theme.colorScheme.onSurface, ), ), const SizedBox(height: 12), Text( 'Add your motorcycle to personalize your ride history and performance data.', textAlign: TextAlign.center, style: TextStyle( color: theme.colorScheme.onSurface.withValues(alpha: 0.7), height: 1.4, ), ), const SizedBox(height: 32), ElevatedButton.icon( key: const ValueKey('garage_add_motorcycle_empty_button'), style: ElevatedButton.styleFrom( backgroundColor: colors.cyberCyan, foregroundColor: Colors.black, padding: const EdgeInsets.symmetric( horizontal: 24, vertical: 14, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), icon: const Icon(Icons.add), label: const Text( 'Add Motorcycle', style: TextStyle( fontWeight: FontWeight.w600, letterSpacing: 0.3, ), ), onPressed: () => context.push('/garage/add'), ), ], ), ), ); } Widget _buildMotorcycleCard( BuildContext context, WidgetRef ref, GarageMotorcycle bike, MotorSignalThemeColors colors, { bool isGrid = false, }) { 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 theme = Theme.of(context); return Container( margin: EdgeInsets.only(bottom: isGrid ? 0 : 16), decoration: BoxDecoration( color: colors.surfaceContainer, borderRadius: BorderRadius.circular(14), border: Border.all( color: bike.isDefault ? colors.cyberCyan.withValues(alpha: 0.6) : colors.outlineVariant, width: bike.isDefault ? 1.0 : 0.8, ), ), child: Material( color: Colors.transparent, child: InkWell( borderRadius: BorderRadius.circular(14), onTap: () => context.push('/garage/${bike.id}'), child: Padding( padding: const EdgeInsets.all(12.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ MotorcyclePhoto( year: bike.year, make: bike.makeName, model: bike.modelName, height: 150, borderRadius: BorderRadius.circular(10), ), const SizedBox(height: 12), Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( displayName, style: TextStyle( fontFamily: 'Sora', fontSize: 16, fontWeight: FontWeight.w700, color: theme.colorScheme.onSurface, ), ), ), if (bike.isDefault) Container( padding: const EdgeInsets.symmetric( horizontal: 8, vertical: 3, ), decoration: BoxDecoration( color: colors.cyberCyan.withValues(alpha: 0.12), borderRadius: BorderRadius.circular(6), border: Border.all( color: colors.cyberCyan.withValues(alpha: 0.4), width: 0.8, ), ), child: Text( 'Current', style: TextStyle( fontFamily: 'Inter', fontSize: 10, fontWeight: FontWeight.w600, color: colors.cyberCyan, letterSpacing: 0.3, ), ), ), ], ), const SizedBox(height: 4), Text( spec != null ? '${spec.displacementCc?.toStringAsFixed(0) ?? "—"} cc • ${spec.horsepower?.toStringAsFixed(0) ?? "—"} hp' : '${bike.year} • ${bike.makeName}', style: TextStyle( fontFamily: 'JetBrains Mono', color: colors.cyberCyan, fontSize: 12.5, fontWeight: FontWeight.w600, ), ), ], ), ), ], ), const SizedBox(height: 12), Wrap( alignment: WrapAlignment.spaceBetween, crossAxisAlignment: WrapCrossAlignment.center, spacing: 8, runSpacing: 4, children: [ TextButton.icon( icon: Icon(Icons.directions_bike, size: 18, color: colors.cyberCyan), label: Text( 'View Specs & Stats', style: TextStyle(color: colors.cyberCyan, fontWeight: FontWeight.bold), ), onPressed: () => context.push('/garage/${bike.id}'), ), if (!bike.isDefault) OutlinedButton( style: OutlinedButton.styleFrom( foregroundColor: theme.colorScheme.onSurface, side: BorderSide(color: colors.outlineVariant), ), 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'), ), ], ), ], ), ), ), ), ); } }