import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:go_router/go_router.dart'; import '../../../services/map/map_provider_interface.dart'; import '../../../services/map/map_providers.dart'; import '../../../services/alerts/road_alert_models.dart'; import '../../../services/alerts/road_alert_providers.dart'; import '../../../services/alerts/road_alert_service.dart'; import '../../../services/osm_oauth_service.dart'; import '../../../services/github/github_auth_service.dart'; import '../../../services/sensor_fusion_service.dart'; import '../../../services/field_test/field_test_logger.dart'; import '../../../database/database.dart'; import '../../rides/ride_state_machine.dart'; import '../../../services/auth/auth_providers.dart'; import '../../../core/theme/evolution_theme_config.dart'; import '../../../core/theme/theme_mode_provider.dart'; import '../../../core/app_info.dart'; import 'current_plan_card.dart'; class EvolutionSettingsView extends ConsumerStatefulWidget { const EvolutionSettingsView({super.key}); @override ConsumerState createState() => _EvolutionSettingsViewState(); } class _EvolutionSettingsViewState extends ConsumerState { late TextEditingController _tomtomKeyController; late TextEditingController _communityKeyController; late TextEditingController _communityEndpointController; bool _isTestingTomTom = false; bool _isTestingCommunity = false; late TextEditingController _githubTokenController; bool _isTestingGitHub = false; bool _obscureGitHubToken = true; @override void initState() { super.initState(); _tomtomKeyController = TextEditingController( text: ref.read(tomtomApiKeyProvider), ); _communityKeyController = TextEditingController( text: ref.read(communityApiKeyProvider), ); _communityEndpointController = TextEditingController( text: ref.read(communityEndpointUrlProvider), ); _githubTokenController = TextEditingController( text: ref.read(githubAuthServiceProvider).getToken() ?? '', ); } @override void dispose() { _tomtomKeyController.dispose(); _communityKeyController.dispose(); _communityEndpointController.dispose(); _githubTokenController.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final mapType = ref.watch(mapProviderTypeNotifierProvider); final themeMode = ref.watch(dashboardThemeModeProvider); final roadAlertsEnabled = ref.watch(roadAlertsEnabledProvider); final audioAlertsEnabled = ref.watch(audioAlertsEnabledProvider); final alertRadiusMeters = ref.watch(alertRadiusMetersProvider); final enabledCategories = ref.watch(enabledCategoriesProvider); final osmAuth = ref.watch(osmOAuthServiceProvider); final radiusMiles = (alertRadiusMeters / 1609.34).toStringAsFixed(1); final isLandscape = MediaQuery.of(context).orientation == Orientation.landscape; return Scaffold( backgroundColor: Colors.black, appBar: AppBar( toolbarHeight: isLandscape ? 36 : 52, backgroundColor: Colors.transparent, elevation: 0, centerTitle: true, title: Text( 'SETTINGS & SYSTEM CONFIG', style: TextStyle( fontFamily: 'Sora', fontSize: isLandscape ? 13 : 16, fontWeight: FontWeight.w900, color: Colors.white, letterSpacing: 0.12, ), ), ), body: LayoutBuilder( builder: (context, constraints) { final isLandscape = constraints.maxWidth > constraints.maxHeight; final appThemeMode = ref.watch(appThemeModeProvider); final appearanceToggleBar = Container( margin: EdgeInsets.only(bottom: isLandscape ? 6 : 12), padding: EdgeInsets.symmetric( horizontal: 12, vertical: isLandscape ? 6 : 12, ), decoration: BoxDecoration( color: const Color(0xFF0D0D0D), borderRadius: BorderRadius.circular(14), border: Border.all(color: const Color(0xFF1F1F1F), width: 1.2), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Expanded( child: Row( children: [ Icon( Icons.brightness_medium_outlined, color: Color(0xFF00E5FF), size: 18, ), SizedBox(width: 8), Flexible( child: Text( 'APPEARANCE:', overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'Inter', fontSize: 11, fontWeight: FontWeight.w800, color: Colors.white70, ), ), ), ], ), ), const SizedBox(width: 8), SegmentedButton( showSelectedIcon: false, style: const ButtonStyle( visualDensity: VisualDensity.compact, tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), segments: const [ ButtonSegment( value: ThemeMode.system, label: Text('System', style: TextStyle(fontSize: 11)), ), ButtonSegment( value: ThemeMode.light, label: Text('Light', style: TextStyle(fontSize: 11)), ), ButtonSegment( value: ThemeMode.dark, label: Text('Dark', style: TextStyle(fontSize: 11)), ), ], selected: {appThemeMode}, onSelectionChanged: (Set selection) { ref .read(appThemeModeProvider.notifier) .setThemeMode(selection.first); }, ), ], ), ); final themeToggleBar = Container( margin: EdgeInsets.only(bottom: isLandscape ? 6 : 12), padding: EdgeInsets.symmetric( horizontal: 12, vertical: isLandscape ? 6 : 12, ), decoration: BoxDecoration( color: const Color(0xFF0D0D0D), borderRadius: BorderRadius.circular(14), border: Border.all(color: const Color(0xFF1F1F1F), width: 1.2), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Expanded( child: Row( children: [ Icon( Icons.dashboard_customize_outlined, color: Color(0xFF00E5FF), size: 18, ), SizedBox(width: 8), Flexible( child: Text( 'COCKPIT LAYOUT:', overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'Inter', fontSize: 11, fontWeight: FontWeight.w800, color: Colors.white70, ), ), ), ], ), ), const SizedBox(width: 8), SegmentedButton( showSelectedIcon: false, style: const ButtonStyle( visualDensity: VisualDensity.compact, tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), segments: const [ ButtonSegment( value: DashboardThemeMode.classic, label: Text('Classic', style: TextStyle(fontSize: 11)), ), ButtonSegment( value: DashboardThemeMode.evolution, label: Text('Evolution', style: TextStyle(fontSize: 11)), ), ], selected: {themeMode}, onSelectionChanged: (Set selection) { ref .read(dashboardThemeModeProvider.notifier) .setThemeMode(selection.first); }, ), ], ), ); final currentPlanCard = const CurrentPlanCard(isEvolution: true); final accountCard = _buildAccountCard(context, ref); final osmAccountCard = _buildOsmAccountCard(context, ref, osmAuth); final mapEngineCard = _buildMapEngineCard(context, ref, mapType); final alertConfigCard = _buildAlertConfigCard( context, ref, roadAlertsEnabled, audioAlertsEnabled, enabledCategories, alertRadiusMeters, radiusMiles, ); final sensorsCard = _buildSensorsCalibrationCard(context, ref); final tomtomCard = _buildTomTomCard(context, ref); final communityCard = _buildCommunityCard(context, ref); final githubCard = _buildGitHubCard(context, ref); final dataCard = _buildDataManagementCard(context, ref); final engineeringCard = _buildEngineeringDiagnosticsCard( context, ref, ); final versionFooter = _buildVersionFooter(context); if (isLandscape) { return SingleChildScrollView( padding: const EdgeInsets.all(16), child: Column( children: [ appearanceToggleBar, themeToggleBar, Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Expanded( child: Column( children: [ currentPlanCard, const SizedBox(height: 16), accountCard, const SizedBox(height: 16), sensorsCard, const SizedBox(height: 16), mapEngineCard, const SizedBox(height: 16), osmAccountCard, const SizedBox(height: 16), tomtomCard, const SizedBox(height: 16), githubCard, ], ), ), const SizedBox(width: 16), Expanded( child: Column( children: [ alertConfigCard, const SizedBox(height: 16), communityCard, const SizedBox(height: 16), engineeringCard, const SizedBox(height: 16), dataCard, ], ), ), ], ), const SizedBox(height: 24), versionFooter, ], ), ); } return SingleChildScrollView( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ appearanceToggleBar, themeToggleBar, currentPlanCard, const SizedBox(height: 16), accountCard, const SizedBox(height: 16), sensorsCard, const SizedBox(height: 16), engineeringCard, const SizedBox(height: 16), dataCard, const SizedBox(height: 16), osmAccountCard, const SizedBox(height: 16), mapEngineCard, const SizedBox(height: 16), alertConfigCard, const SizedBox(height: 16), communityCard, const SizedBox(height: 16), tomtomCard, const SizedBox(height: 24), versionFooter, const SizedBox(height: 24), ], ), ); }, ), ); } Widget _buildAccountCard(BuildContext context, WidgetRef ref) { final authState = ref.watch(authNotifierProvider); final isAuthed = authState.isAuthenticated; final user = authState.user; return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0D0D0D), borderRadius: BorderRadius.circular(16), border: Border.all( color: isAuthed ? const Color(0xFF00E5FF).withValues(alpha: 0.6) : const Color(0xFF1F1F1F), width: 1.2, ), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Expanded( child: Row( children: [ Icon( Icons.account_circle, color: Color(0xFF00E5FF), size: 18, ), SizedBox(width: 8), Flexible( child: Text( 'MOTORCLOUD ACCOUNT', overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'Sora', fontSize: 12, fontWeight: FontWeight.w800, color: Color(0xFF00E5FF), letterSpacing: 0.1, ), ), ), ], ), ), const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( color: isAuthed ? const Color(0xFF00E5FF).withValues(alpha: 0.15) : Colors.white10, borderRadius: BorderRadius.circular(8), ), child: Text( isAuthed ? 'CONNECTED' : 'OFFLINE MODE', style: TextStyle( fontFamily: 'Inter', fontSize: 9, fontWeight: FontWeight.w800, color: isAuthed ? const Color(0xFF00E5FF) : Colors.white38, ), ), ), ], ), const SizedBox(height: 10), if (isAuthed && user != null) ...[ Row( children: [ CircleAvatar( radius: 18, backgroundColor: Colors.white12, backgroundImage: user.photoUrl != null ? NetworkImage(user.photoUrl!) : null, child: user.photoUrl == null ? const Icon( Icons.person, color: Color(0xFF00E5FF), size: 20, ) : null, ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( user.displayLabel, style: const TextStyle( fontFamily: 'Inter', fontSize: 13, fontWeight: FontWeight.w700, color: Colors.white, ), ), Text( user.email ?? 'Cloud Identity Active', style: const TextStyle( fontFamily: 'Inter', fontSize: 11, color: Colors.white54, ), ), ], ), ), ], ), const SizedBox(height: 12), OutlinedButton.icon( style: OutlinedButton.styleFrom( foregroundColor: const Color(0xFF00E5FF), side: const BorderSide(color: Color(0xFF00E5FF), width: 0.8), minimumSize: const Size(double.infinity, 38), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), icon: const Icon(Icons.manage_accounts, size: 16), label: const Text( 'Manage Account & Cloud Sync', style: TextStyle(fontSize: 11, fontWeight: FontWeight.bold), ), onPressed: () => context.go('/settings/account'), ), ] else ...[ const Text( 'Sign in for optional multi-device account sync and cloud backup. All telemetry and ride logging work completely offline.', style: TextStyle( fontFamily: 'Inter', fontSize: 10, color: Colors.white60, height: 1.3, ), ), const SizedBox(height: 12), ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF00E5FF), foregroundColor: Colors.black, minimumSize: const Size(double.infinity, 38), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), icon: const Icon(Icons.login, size: 16), label: const Text( 'Sign In / Create Account', style: TextStyle( fontFamily: 'Inter', fontSize: 11, fontWeight: FontWeight.w800, ), ), onPressed: () => context.go('/settings/account'), ), ], ], ), ); } Widget _buildOsmAccountCard( BuildContext context, WidgetRef ref, OsmAuthState osmAuth, ) { final isAuthed = osmAuth.isAuthenticated; final user = osmAuth.user; return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0D0D0D), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFF1F1F1F), width: 1.2), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Expanded( child: Row( children: [ Icon(Icons.public, color: Color(0xFF00E5FF), size: 18), SizedBox(width: 8), Flexible( child: Text( 'OPENSTREETMAP ACCOUNT', overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'Sora', fontSize: 12, fontWeight: FontWeight.w800, color: Color(0xFF00E5FF), letterSpacing: 0.1, ), ), ), ], ), ), const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( color: isAuthed ? const Color(0xFF00E5FF).withValues(alpha: 0.15) : Colors.white10, borderRadius: BorderRadius.circular(8), ), child: Text( isAuthed ? 'CONNECTED' : 'DISCONNECTED', style: TextStyle( fontFamily: 'Inter', fontSize: 9, fontWeight: FontWeight.w800, color: isAuthed ? const Color(0xFF00E5FF) : Colors.white38, ), ), ), ], ), const SizedBox(height: 12), if (isAuthed && user != null) ...[ Row( children: [ CircleAvatar( radius: 20, backgroundColor: Colors.white12, backgroundImage: user.avatarUrl != null ? NetworkImage(user.avatarUrl!) : null, child: user.avatarUrl == null ? const Icon( Icons.person, color: Color(0xFF00E5FF), size: 22, ) : null, ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( user.displayName, style: const TextStyle( fontFamily: 'Inter', fontSize: 14, fontWeight: FontWeight.w700, color: Colors.white, ), ), Text( 'Changesets: ${user.changesetCount} • Sync Enabled', style: const TextStyle( fontFamily: 'Inter', fontSize: 11, color: Colors.white54, ), ), ], ), ), ], ), const SizedBox(height: 12), OutlinedButton.icon( style: OutlinedButton.styleFrom( foregroundColor: Colors.redAccent, side: const BorderSide(color: Colors.redAccent, width: 0.8), minimumSize: const Size(double.infinity, 38), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), icon: const Icon(Icons.link_off, size: 16), label: const Text( 'Disconnect OpenStreetMap', style: TextStyle(fontSize: 12, fontWeight: FontWeight.bold), ), onPressed: () => ref.read(osmOAuthServiceProvider.notifier).logout(), ), ] else ...[ const Text( 'Link your OpenStreetMap account via OAuth 2.0 PKCE to upload GPS traces and sync ride telemetry.', style: TextStyle( fontFamily: 'Inter', fontSize: 11, color: Colors.white60, height: 1.4, ), ), const SizedBox(height: 12), ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF00E5FF), foregroundColor: Colors.black, minimumSize: const Size(double.infinity, 40), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(10), ), ), icon: const Icon(Icons.login, size: 18), label: const Text( 'Connect OpenStreetMap Account', style: TextStyle( fontFamily: 'Inter', fontSize: 12, fontWeight: FontWeight.w800, ), ), onPressed: osmAuth.isLoading ? null : () => ref .read(osmOAuthServiceProvider.notifier) .startLoginFlow(), ), ], if (osmAuth.errorMessage != null) ...[ const SizedBox(height: 8), Text( osmAuth.errorMessage!, style: const TextStyle(color: Colors.redAccent, fontSize: 10), ), ], ], ), ); } Widget _buildMapEngineCard( BuildContext context, WidgetRef ref, AppMapType mapType, ) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0D0D0D), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFF1F1F1F), width: 1.2), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'MAP ENGINE & RENDERING', style: TextStyle( fontFamily: 'Sora', fontSize: 12, fontWeight: FontWeight.w800, color: Color(0xFF00E5FF), letterSpacing: 0.1, ), ), const SizedBox(height: 12), const Text( 'Active Map Engine', style: TextStyle( fontFamily: 'Inter', fontSize: 11, fontWeight: FontWeight.w700, color: Colors.white70, ), ), const SizedBox(height: 8), _buildEngineOption( title: 'OpenStreetMap', selected: mapType == AppMapType.openStreetMap, onTap: () => ref .read(mapProviderTypeNotifierProvider.notifier) .setMapProviderType(AppMapType.openStreetMap), ), const SizedBox(height: 6), _buildEngineOption( title: 'Google Maps', selected: mapType == AppMapType.googleMaps, onTap: () => ref .read(mapProviderTypeNotifierProvider.notifier) .setMapProviderType(AppMapType.googleMaps), ), const SizedBox(height: 16), const Text( 'Rendering Preferences', style: TextStyle( fontFamily: 'Inter', fontSize: 11, fontWeight: FontWeight.w700, color: Colors.white70, ), ), const SizedBox(height: 8), _buildSwitchRow(Icons.apartment, '3D Buildings', true, (_) {}), _buildSwitchRow(Icons.terrain, 'Terrain Topo Data', true, (_) {}), _buildSwitchRow(Icons.traffic, 'Live Traffic Overlay', true, (_) {}), _buildSwitchRow( Icons.play_circle_outline, 'Replay Preview', false, (_) {}, ), ], ), ); } Widget _buildAlertConfigCard( BuildContext context, WidgetRef ref, bool roadAlertsEnabled, bool audioAlertsEnabled, Set enabledCategories, double alertRadiusMeters, String radiusMiles, ) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0D0D0D), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFF1F1F1F), width: 1.2), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'ROAD ALERT CONFIGURATION', style: TextStyle( fontFamily: 'Sora', fontSize: 12, fontWeight: FontWeight.w800, color: Color(0xFF00E5FF), letterSpacing: 0.1, ), ), const SizedBox(height: 12), const Text( 'Alert Categories', style: TextStyle( fontFamily: 'Inter', fontSize: 11, fontWeight: FontWeight.w700, color: Colors.white70, ), ), const SizedBox(height: 8), _buildSwitchRow( Icons.local_police_outlined, 'Police Presence', enabledCategories.contains(RoadAlertCategory.police), (v) => ref .read(enabledCategoriesProvider.notifier) .toggleCategory(RoadAlertCategory.police, v), ), _buildSwitchRow( Icons.camera_alt_outlined, 'Speed Cameras', enabledCategories.contains(RoadAlertCategory.speedCamera), (v) => ref .read(enabledCategoriesProvider.notifier) .toggleCategory(RoadAlertCategory.speedCamera, v), ), _buildSwitchRow( Icons.warning_amber_rounded, 'Road Hazards', enabledCategories.contains(RoadAlertCategory.hazard), (v) => ref .read(enabledCategoriesProvider.notifier) .toggleCategory(RoadAlertCategory.hazard, v), ), _buildSwitchRow( Icons.car_crash_outlined, 'Traffic Incidents', enabledCategories.contains(RoadAlertCategory.traffic), (v) => ref .read(enabledCategoriesProvider.notifier) .toggleCategory(RoadAlertCategory.traffic, v), ), const SizedBox(height: 16), const Text( 'Radius Configuration', style: TextStyle( fontFamily: 'Inter', fontSize: 11, fontWeight: FontWeight.w700, color: Colors.white70, ), ), const SizedBox(height: 8), Center( child: Text( '$radiusMiles MILE', style: const TextStyle( fontFamily: 'JetBrains Mono', fontSize: 22, fontWeight: FontWeight.w900, color: Colors.white, ), ), ), const SizedBox(height: 8), Row( children: [ IconButton( icon: const Icon( Icons.remove_circle_outline, color: Color(0xFF00E5FF), ), onPressed: alertRadiusMeters > 500 ? () => ref .read(alertRadiusMetersProvider.notifier) .setRadius(alertRadiusMeters - 500.0) : null, ), Expanded( child: LinearProgressIndicator( value: (alertRadiusMeters / 5000.0).clamp(0.1, 1.0), backgroundColor: const Color(0xFF1F1F1F), valueColor: const AlwaysStoppedAnimation( Color(0xFF00E5FF), ), minHeight: 8, borderRadius: BorderRadius.circular(4), ), ), IconButton( icon: const Icon( Icons.add_circle_outline, color: Color(0xFF00E5FF), ), onPressed: alertRadiusMeters < 5000 ? () => ref .read(alertRadiusMetersProvider.notifier) .setRadius(alertRadiusMeters + 500.0) : null, ), ], ), const Center( child: Text( 'Distance to detect upcoming incidents', style: TextStyle( fontFamily: 'Inter', fontSize: 9, color: Colors.white38, ), ), ), const SizedBox(height: 12), SizedBox( width: double.infinity, child: OutlinedButton.icon( icon: const Icon(Icons.volume_up, size: 16), label: const Text('TRIGGER TEST ALERT (TTS + HUD)'), style: OutlinedButton.styleFrom( foregroundColor: const Color(0xFF00E5FF), side: const BorderSide(color: Color(0xFF00E5FF), width: 1), padding: const EdgeInsets.symmetric(vertical: 10), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), onPressed: () => ref.read(roadAlertServiceProvider).triggerTestAlert(), ), ), ], ), ); } Widget _buildEngineOption({ required String title, required bool selected, required VoidCallback onTap, }) { return InkWell( onTap: onTap, borderRadius: BorderRadius.circular(8), child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), decoration: BoxDecoration( color: selected ? const Color(0xFF00252A) : const Color(0xFF141414), borderRadius: BorderRadius.circular(8), border: Border.all( color: selected ? const Color(0xFF00E5FF) : const Color(0xFF222222), width: selected ? 1.4 : 1.0, ), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( title, style: TextStyle( fontFamily: 'Inter', fontSize: 12, fontWeight: FontWeight.w700, color: selected ? Colors.white : Colors.white60, ), ), if (selected) const Icon(Icons.check, color: Color(0xFF00E5FF), size: 16), ], ), ), ); } Widget _buildSwitchRow( IconData icon, String title, bool value, ValueChanged onChanged, ) { return Padding( padding: const EdgeInsets.symmetric(vertical: 2), child: Row( children: [ Icon(icon, color: Colors.white60, size: 16), const SizedBox(width: 8), Expanded( child: Text( title, style: const TextStyle( fontFamily: 'Inter', fontSize: 11, fontWeight: FontWeight.w600, color: Colors.white, ), ), ), Switch( value: value, activeThumbColor: const Color(0xFF00E5FF), onChanged: onChanged, ), ], ), ); } Widget _buildSensorsCalibrationCard(BuildContext context, WidgetRef ref) { final leanAsync = ref.watch(leanAngleStreamProvider); final currentLean = leanAsync.value ?? 0.0; return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0D0D0D), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFF1F1F1F), width: 1.2), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Row( children: [ Icon(Icons.screen_rotation, color: Color(0xFF00E5FF), size: 18), SizedBox(width: 8), Expanded( child: Text( 'SENSORS & MOUNT CALIBRATION', overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'Inter', fontSize: 12, fontWeight: FontWeight.w800, color: Colors.white, letterSpacing: 0.1, ), ), ), ], ), const SizedBox(height: 8), const Text( 'Place motorcycle upright on level ground. Zeroes the roll and pitch offsets for your phone mount angle.', style: TextStyle( fontFamily: 'Inter', fontSize: 10, color: Colors.white60, height: 1.3, ), ), const SizedBox(height: 12), Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), decoration: BoxDecoration( color: const Color(0xFF141414), borderRadius: BorderRadius.circular(8), border: Border.all(color: const Color(0xFF222222)), ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'CURRENT LEAN ANGLE:', style: TextStyle( fontFamily: 'Inter', fontSize: 10, fontWeight: FontWeight.bold, color: Colors.white54, ), ), Text( '${currentLean.toStringAsFixed(1)}°', style: const TextStyle( fontFamily: 'Inter', fontSize: 14, fontWeight: FontWeight.w900, color: Color(0xFF00E5FF), ), ), ], ), ), const SizedBox(height: 12), SizedBox( width: double.infinity, child: ElevatedButton.icon( icon: const Icon(Icons.tune, size: 16), label: const Text('CALIBRATE UPRIGHT ZERO'), style: ElevatedButton.styleFrom( backgroundColor: const Color(0xFF00E5FF), foregroundColor: Colors.black, padding: const EdgeInsets.symmetric(vertical: 12), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), textStyle: const TextStyle( fontFamily: 'Inter', fontSize: 11, fontWeight: FontWeight.w900, letterSpacing: 0.8, ), ), onPressed: () { final session = ref.read(rideStateMachineProvider); if (session.state == RideState.riding) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Cannot calibrate while a ride is actively recording.', ), ), ); return; } ref.read(sensorFusionServiceProvider).calibrateUpright(); ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Sensors Calibrated! Zero mount angle saved.', ), ), ); }, ), ), ], ), ); } Widget _buildDataManagementCard(BuildContext context, WidgetRef ref) { return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0D0D0D), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFF1F1F1F), width: 1.2), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Row( children: [ Icon(Icons.storage_outlined, color: Color(0xFF00E5FF), size: 18), SizedBox(width: 8), Text( 'DATA & STORAGE', style: TextStyle( fontFamily: 'Inter', fontSize: 12, fontWeight: FontWeight.w800, color: Colors.white, letterSpacing: 0.1, ), ), ], ), const SizedBox(height: 12), InkWell( onTap: () => context.go('/settings/diagnostics'), borderRadius: BorderRadius.circular(8), child: Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), decoration: BoxDecoration( color: const Color(0xFF141414), borderRadius: BorderRadius.circular(8), border: Border.all(color: const Color(0xFF222222)), ), child: const Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Row( children: [ Icon( Icons.monitor_heart, color: Color(0xFF00E5FF), size: 16, ), SizedBox(width: 8), Text( 'Sensor Diagnostics & Raw Telemetry', style: TextStyle( fontFamily: 'Inter', fontSize: 11, fontWeight: FontWeight.w700, color: Colors.white, ), ), ], ), Icon(Icons.chevron_right, color: Colors.white54, size: 18), ], ), ), ), const SizedBox(height: 10), SizedBox( width: double.infinity, child: OutlinedButton.icon( icon: const Icon( Icons.delete_forever, color: Colors.redAccent, size: 16, ), label: const Text('CLEAR ALL RIDE HISTORY'), style: OutlinedButton.styleFrom( foregroundColor: Colors.redAccent, side: const BorderSide(color: Colors.redAccent, width: 1), padding: const EdgeInsets.symmetric(vertical: 10), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), textStyle: const TextStyle( fontFamily: 'Inter', fontSize: 11, fontWeight: FontWeight.w800, letterSpacing: 0.5, ), ), onPressed: () async { final session = ref.read(rideStateMachineProvider); if (session.state == RideState.riding) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text( 'Cannot clear history while a ride is actively recording.', ), ), ); return; } final confirmed = await showDialog( context: context, builder: (ctx) => AlertDialog( backgroundColor: const Color(0xFF141414), title: const Text('Clear All Ride History?'), content: const Text( 'This will permanently delete all saved rides, telemetry points, and events. This action cannot be undone.', ), actions: [ TextButton( onPressed: () => Navigator.pop(ctx, false), child: const Text('CANCEL'), ), TextButton( onPressed: () => Navigator.pop(ctx, true), child: const Text( 'CLEAR ALL', style: TextStyle( color: Colors.redAccent, fontWeight: FontWeight.bold, ), ), ), ], ), ); if (confirmed == true && context.mounted) { final db = ref.read(databaseProvider); await db.transaction(() async { await db.delete(db.telemetrySamples).go(); await db.delete(db.rideEvents).go(); await db.delete(db.performanceRuns).go(); await db.delete(db.rides).go(); }); if (context.mounted) { ScaffoldMessenger.of(context).showSnackBar( const SnackBar( content: Text('All ride history cleared.'), ), ); } } }, ), ), ], ), ); } Widget _buildEngineeringDiagnosticsCard(BuildContext context, WidgetRef ref) { final isEnabled = ref.watch(fieldTestModeEnabledProvider); final activeSession = ref.watch(activeFieldTestSessionProvider); return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0D0D0D), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFF1F1F1F), width: 1.2), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Expanded( child: Row( children: [ Icon( Icons.biotech, color: isEnabled ? Colors.greenAccent : const Color(0xFF00E5FF), size: 18, ), const SizedBox(width: 8), const Flexible( child: Text( 'ENGINEERING & DIAGNOSTICS', overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'Inter', fontSize: 12, fontWeight: FontWeight.w800, color: Colors.white, letterSpacing: 0.1, ), ), ), ], ), ), const SizedBox(width: 8), Switch( value: isEnabled, activeThumbColor: Colors.greenAccent, onChanged: (val) { ref .read(fieldTestModeEnabledProvider.notifier) .setEnabled(val); }, ), ], ), const SizedBox(height: 6), const Text( 'High-resolution black-box recorder for sensor fusion, GPS, and Kalman filter diagnostics.', style: TextStyle( fontFamily: 'Inter', fontSize: 10, color: Colors.white60, height: 1.3, ), ), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Text( 'RECORDER STATUS:', style: TextStyle( fontFamily: 'Inter', color: Colors.white54, fontSize: 10, fontWeight: FontWeight.bold, ), ), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: activeSession != null ? Colors.greenAccent.withValues(alpha: 0.15) : (isEnabled ? const Color(0xFF00E5FF).withValues(alpha: 0.15) : Colors.white10), borderRadius: BorderRadius.circular(6), border: Border.all( color: activeSession != null ? Colors.greenAccent : (isEnabled ? const Color(0xFF00E5FF) : Colors.white24), ), ), child: Text( activeSession != null ? 'RECORDING (Ride #$activeSession)' : (isEnabled ? 'ARMED (Auto-starts on Ride)' : 'OFF'), style: TextStyle( fontFamily: 'Inter', fontSize: 10, fontWeight: FontWeight.bold, color: activeSession != null ? Colors.greenAccent : (isEnabled ? const Color(0xFF00E5FF) : Colors.white54), ), ), ), ], ), const SizedBox(height: 12), Row( children: [ Expanded( child: ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: Colors.greenAccent.withValues(alpha: 0.2), foregroundColor: Colors.greenAccent, side: const BorderSide(color: Colors.greenAccent), padding: const EdgeInsets.symmetric(vertical: 10), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), icon: const Icon(Icons.fact_check, size: 16), label: const Text( 'PRE-RIDE CHECK', style: TextStyle( fontFamily: 'Inter', fontSize: 9, fontWeight: FontWeight.w800, ), ), onPressed: () => context.go('/settings/field-test-pre-ride-check'), ), ), const SizedBox(width: 6), Expanded( child: ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: const Color( 0xFF00E5FF, ).withValues(alpha: 0.15), foregroundColor: const Color(0xFF00E5FF), side: const BorderSide(color: Color(0xFF00E5FF)), padding: const EdgeInsets.symmetric(vertical: 10), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), icon: const Icon(Icons.assessment, size: 16), label: const Text( 'REPORTS', style: TextStyle( fontFamily: 'Inter', fontSize: 9, fontWeight: FontWeight.w800, ), ), onPressed: () => context.go('/settings/field-test-report'), ), ), const SizedBox(width: 6), Expanded( child: ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: Colors.white10, foregroundColor: Colors.white, side: const BorderSide(color: Colors.white24), padding: const EdgeInsets.symmetric(vertical: 10), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), icon: const Icon(Icons.stream, size: 16), label: const Text( 'LIVE LOG', style: TextStyle( fontFamily: 'Inter', fontSize: 9, fontWeight: FontWeight.w800, ), ), onPressed: () => context.go('/settings/field-test-live-log'), ), ), ], ), ], ), ); } Widget _buildGitHubCard(BuildContext context, WidgetRef ref) { final authService = ref.watch(githubAuthServiceProvider); final hasToken = authService.getToken() != null && authService.getToken()!.isNotEmpty; return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0D0D0D), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFF1F1F1F), width: 1.2), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Expanded( child: Row( children: [ Icon( Icons.cloud_upload_outlined, color: Color(0xFF00E5FF), size: 18, ), SizedBox(width: 8), Flexible( child: Text( 'GITHUB RIDE LOG SYNC', overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'Inter', fontSize: 12, fontWeight: FontWeight.w800, color: Colors.white, letterSpacing: 0.1, ), ), ), ], ), ), const SizedBox(width: 8), Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3), decoration: BoxDecoration( color: hasToken ? const Color(0xFF00E676).withValues(alpha: 0.15) : Colors.white10, borderRadius: BorderRadius.circular(8), ), child: Text( hasToken ? 'CONFIGURED' : 'NO TOKEN', style: TextStyle( fontFamily: 'Inter', fontSize: 9, fontWeight: FontWeight.w800, color: hasToken ? const Color(0xFF00E676) : Colors.white38, ), ), ), ], ), const SizedBox(height: 8), const Text( 'Target Repository: bponders12-cell/ride_logs (branch: main). Offline-first background uploads with zero telemetry disruption.', style: TextStyle( fontFamily: 'Inter', fontSize: 10, color: Colors.white60, height: 1.3, ), ), const SizedBox(height: 12), TextField( controller: _githubTokenController, obscureText: _obscureGitHubToken, decoration: InputDecoration( labelText: 'GitHub Personal Access Token (PAT)', labelStyle: const TextStyle( fontFamily: 'Inter', fontSize: 11, color: Colors.white60, ), hintText: 'ghp_xxxxxxxxxxxxxxxxxxxx', hintStyle: const TextStyle( fontFamily: 'Inter', fontSize: 11, color: Colors.white30, ), filled: true, fillColor: const Color(0xFF141414), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color(0xFF222222)), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color(0xFF222222)), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color(0xFF00E5FF)), ), isDense: true, suffixIcon: IconButton( icon: Icon( _obscureGitHubToken ? Icons.visibility_off : Icons.visibility, color: Colors.white38, size: 18, ), onPressed: () { setState(() => _obscureGitHubToken = !_obscureGitHubToken); }, ), ), style: const TextStyle( fontFamily: 'JetBrains Mono', fontSize: 12, color: Colors.white, ), onChanged: (val) { authService.saveToken(val); }, ), const SizedBox(height: 12), Row( mainAxisAlignment: MainAxisAlignment.end, children: [ if (hasToken) TextButton( onPressed: () async { await authService.clearToken(); _githubTokenController.clear(); setState(() {}); }, child: const Text( 'CLEAR', style: TextStyle( color: Colors.redAccent, fontFamily: 'Inter', fontSize: 10, ), ), ), const SizedBox(width: 8), ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: const Color( 0xFF00E5FF, ).withValues(alpha: 0.15), foregroundColor: const Color(0xFF00E5FF), side: const BorderSide(color: Color(0xFF00E5FF)), padding: const EdgeInsets.symmetric( horizontal: 14, vertical: 8, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), onPressed: _isTestingGitHub ? null : () async { setState(() => _isTestingGitHub = true); final messenger = ScaffoldMessenger.of(context); final result = await authService.testConnection(); setState(() => _isTestingGitHub = false); messenger.showSnackBar( SnackBar( content: Text(result['message'] as String), backgroundColor: result['success'] == true ? const Color(0xFF00E676) : Colors.redAccent, ), ); }, icon: _isTestingGitHub ? const SizedBox( width: 14, height: 14, child: CircularProgressIndicator( strokeWidth: 2, color: Color(0xFF00E5FF), ), ) : const Icon(Icons.sync, size: 16), label: const Text( 'TEST CONNECTION', style: TextStyle( fontFamily: 'Inter', fontSize: 10, fontWeight: FontWeight.w800, ), ), ), ], ), ], ), ); } Widget _buildTomTomCard(BuildContext context, WidgetRef ref) { final tomtomStatus = ref.watch(tomtomStatusProvider); return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0D0D0D), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFF1F1F1F), width: 1.2), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Expanded( child: Row( children: [ Icon(Icons.traffic, color: Color(0xFF00E5FF), size: 18), SizedBox(width: 8), Flexible( child: Text( 'TOMTOM TRAFFIC PROVIDER', overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'Inter', fontSize: 12, fontWeight: FontWeight.w800, color: Colors.white, letterSpacing: 0.1, ), ), ), ], ), ), const SizedBox(width: 8), _buildStatusBadge(tomtomStatus), ], ), const SizedBox(height: 8), const Text( 'Supplies real-time accidents, hazards, road closures, and construction feeds.', style: TextStyle( fontFamily: 'Inter', fontSize: 10, color: Colors.white60, height: 1.3, ), ), const SizedBox(height: 12), TextField( controller: _tomtomKeyController, decoration: InputDecoration( labelText: 'TomTom API Key', labelStyle: const TextStyle( fontFamily: 'Inter', fontSize: 11, color: Colors.white60, ), hintText: 'Enter your TomTom API Key', hintStyle: const TextStyle( fontFamily: 'Inter', fontSize: 11, color: Colors.white30, ), filled: true, fillColor: const Color(0xFF141414), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color(0xFF222222)), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color(0xFF222222)), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color(0xFF00E5FF)), ), isDense: true, ), style: const TextStyle( fontFamily: 'Inter', fontSize: 12, color: Colors.white, ), onChanged: (val) { ref.read(tomtomApiKeyProvider.notifier).setApiKey(val); }, ), const SizedBox(height: 12), Align( alignment: Alignment.centerRight, child: ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: const Color( 0xFF00E5FF, ).withValues(alpha: 0.15), foregroundColor: const Color(0xFF00E5FF), side: const BorderSide(color: Color(0xFF00E5FF)), padding: const EdgeInsets.symmetric( horizontal: 14, vertical: 8, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), onPressed: _isTestingTomTom ? null : () async { setState(() => _isTestingTomTom = true); final messenger = ScaffoldMessenger.of(context); final provider = ref.read(tomtomProviderInstance); final status = await provider.testConnection( _tomtomKeyController.text, ); ref.read(tomtomStatusProvider.notifier).state = status; setState(() => _isTestingTomTom = false); String msg = status == RoadAlertProviderStatus.connected ? 'TomTom API Connected successfully!' : 'Status: ${status.name}'; messenger.showSnackBar(SnackBar(content: Text(msg))); }, icon: _isTestingTomTom ? const SizedBox( width: 14, height: 14, child: CircularProgressIndicator( strokeWidth: 2, color: Color(0xFF00E5FF), ), ) : const Icon(Icons.sync, size: 16), label: const Text( 'TEST CONNECTION', style: TextStyle( fontFamily: 'Inter', fontSize: 10, fontWeight: FontWeight.w800, ), ), ), ), ], ), ); } Widget _buildCommunityCard(BuildContext context, WidgetRef ref) { final communityStatus = ref.watch(communityStatusProvider); return Container( padding: const EdgeInsets.all(16), decoration: BoxDecoration( color: const Color(0xFF0D0D0D), borderRadius: BorderRadius.circular(16), border: Border.all(color: const Color(0xFF1F1F1F), width: 1.2), ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ const Expanded( child: Row( children: [ Icon( Icons.local_police, color: Color(0xFF00E5FF), size: 18, ), SizedBox(width: 8), Flexible( child: Text( 'COMMUNITY TRAFFIC PROVIDER', overflow: TextOverflow.ellipsis, style: TextStyle( fontFamily: 'Inter', fontSize: 12, fontWeight: FontWeight.w800, color: Colors.white, letterSpacing: 0.1, ), ), ), ], ), ), const SizedBox(width: 8), _buildStatusBadge(communityStatus), ], ), const SizedBox(height: 8), const Text( 'Live crowdsourced speed traps, police radars, and hazard reports.', style: TextStyle( fontFamily: 'Inter', fontSize: 10, color: Colors.white60, height: 1.3, ), ), const SizedBox(height: 12), TextField( controller: _communityKeyController, decoration: InputDecoration( labelText: 'Community API Key', labelStyle: const TextStyle( fontFamily: 'Inter', fontSize: 11, color: Colors.white60, ), hintText: 'Enter API Key', hintStyle: const TextStyle( fontFamily: 'Inter', fontSize: 11, color: Colors.white30, ), filled: true, fillColor: const Color(0xFF141414), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color(0xFF222222)), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color(0xFF222222)), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color(0xFF00E5FF)), ), isDense: true, ), style: const TextStyle( fontFamily: 'Inter', fontSize: 12, color: Colors.white, ), onChanged: (val) { ref.read(communityApiKeyProvider.notifier).setApiKey(val); }, ), const SizedBox(height: 10), TextField( controller: _communityEndpointController, decoration: InputDecoration( labelText: 'Custom Endpoint URL (Optional)', labelStyle: const TextStyle( fontFamily: 'Inter', fontSize: 11, color: Colors.white60, ), hintText: 'e.g. https://google-map-places.p.rapidapi.com', hintStyle: const TextStyle( fontFamily: 'Inter', fontSize: 11, color: Colors.white30, ), filled: true, fillColor: const Color(0xFF141414), border: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color(0xFF222222)), ), enabledBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color(0xFF222222)), ), focusedBorder: OutlineInputBorder( borderRadius: BorderRadius.circular(8), borderSide: const BorderSide(color: Color(0xFF00E5FF)), ), isDense: true, ), style: const TextStyle( fontFamily: 'Inter', fontSize: 12, color: Colors.white, ), onChanged: (val) { ref.read(communityEndpointUrlProvider.notifier).setEndpoint(val); }, ), const SizedBox(height: 12), Align( alignment: Alignment.centerRight, child: ElevatedButton.icon( style: ElevatedButton.styleFrom( backgroundColor: const Color( 0xFF00E5FF, ).withValues(alpha: 0.15), foregroundColor: const Color(0xFF00E5FF), side: const BorderSide(color: Color(0xFF00E5FF)), padding: const EdgeInsets.symmetric( horizontal: 14, vertical: 8, ), shape: RoundedRectangleBorder( borderRadius: BorderRadius.circular(8), ), ), onPressed: _isTestingCommunity ? null : () async { setState(() => _isTestingCommunity = true); final messenger = ScaffoldMessenger.of(context); final provider = ref.read(communityProviderInstance); final status = await provider.testConnection( _communityKeyController.text, ); ref.read(communityStatusProvider.notifier).state = status; setState(() => _isTestingCommunity = false); String msg = status == RoadAlertProviderStatus.connected ? 'Community API Connected successfully!' : 'Status: ${status.name}'; messenger.showSnackBar(SnackBar(content: Text(msg))); }, icon: _isTestingCommunity ? const SizedBox( width: 14, height: 14, child: CircularProgressIndicator( strokeWidth: 2, color: Color(0xFF00E5FF), ), ) : const Icon(Icons.sync, size: 16), label: const Text( 'TEST CONNECTION', style: TextStyle( fontFamily: 'Inter', fontSize: 10, fontWeight: FontWeight.w800, ), ), ), ), ], ), ); } Widget _buildStatusBadge(RoadAlertProviderStatus status) { Color color = Colors.white30; String text = 'OFF'; if (status == RoadAlertProviderStatus.connected) { color = const Color(0xFF69F0AE); text = 'CONNECTED'; } else if (status == RoadAlertProviderStatus.authError) { color = const Color(0xFFFF5252); text = 'AUTH ERROR'; } else if (status == RoadAlertProviderStatus.rateLimited) { color = const Color(0xFFFFD740); text = 'RATE LIMITED'; } else if (status == RoadAlertProviderStatus.networkError) { color = const Color(0xFFFF5252); text = 'NETWORK ERROR'; } return Container( padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 2), decoration: BoxDecoration( color: color.withValues(alpha: 0.15), borderRadius: BorderRadius.circular(6), border: Border.all(color: color, width: 0.8), ), child: Text( text, style: TextStyle( fontFamily: 'Inter', fontSize: 9, fontWeight: FontWeight.w800, color: color, ), ), ); } Widget _buildVersionFooter(BuildContext context) { return FutureBuilder( future: AppInfo.versionString(), builder: (context, snapshot) { final ver = snapshot.data ?? AppInfo.fallbackVersion; return Center( child: InkWell( onTap: () { final identity = AppInfo.identity; showDialog( context: context, builder: (ctx) => AlertDialog( backgroundColor: const Color(0xFF1E293B), title: const Row( children: [ Icon(Icons.fingerprint, color: Colors.cyanAccent), SizedBox(width: 8), Text( 'Software Identity', style: TextStyle(color: Colors.white, fontSize: 16), ), ], ), content: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ _diagRow('Application', 'MotorSignal'), _diagRow('Version', identity.semanticVersion), _diagRow('Build Number', '${identity.buildNumber}'), _diagRow('Release Channel', identity.releaseChannel), _diagRow( 'Telemetry Schema', '${identity.telemetrySchemaVersion}', ), _diagRow( 'Export Schema', '${identity.exportSchemaVersion}', ), _diagRow( 'Git Commit', identity.gitCommit.length > 12 ? identity.gitCommit.substring(0, 12) : identity.gitCommit, ), _diagRow('Build Timestamp', identity.buildTimestamp), ], ), actions: [ TextButton( onPressed: () => Navigator.of(ctx).pop(), child: const Text( 'CLOSE', style: TextStyle(color: Colors.cyanAccent), ), ), ], ), ); }, borderRadius: BorderRadius.circular(8), child: Padding( padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 16), child: Column( children: [ Text( 'MotorSignal v$ver', style: const TextStyle( fontFamily: 'Inter', fontSize: 12, fontWeight: FontWeight.w700, color: Colors.white54, letterSpacing: 1.0, ), ), const SizedBox(height: 2), const Text( 'High-Performance Motorcycle Telemetry Engine', style: TextStyle( fontFamily: 'Inter', fontSize: 9, color: Colors.white30, ), ), ], ), ), ), ); }, ); } static Widget _diagRow(String label, String value) { return Padding( padding: const EdgeInsets.symmetric(vertical: 4.0), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( label, style: const TextStyle(color: Colors.white70, fontSize: 12), ), Text( value, style: const TextStyle( color: Colors.cyanAccent, fontWeight: FontWeight.bold, fontSize: 12, fontFamily: 'monospace', ), ), ], ), ); } }