import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:provider/provider.dart'; import 'core/theme/app_theme.dart'; import 'core/display_controller.dart'; import 'core/theme/theme_controller.dart'; import 'features/home/home_screen.dart'; import 'features/home/gps_speed_controller.dart'; import 'features/home/launcher_controller.dart'; import 'features/home/obd_controller.dart'; import 'features/home/system_controller.dart'; import 'features/home/weather_controller.dart'; import 'features/lock/lock_controller.dart'; import 'features/lock/lock_screen.dart'; class CarDashApp extends StatefulWidget { const CarDashApp({super.key}); @override State createState() => _CarDashAppState(); } class _CarDashAppState extends State with WidgetsBindingObserver { @override void initState() { super.initState(); WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addPostFrameCallback((_) { if (!mounted) return; _applyImmersive(); context.read().start(); unawaited(context.read().start()); unawaited(context.read().start()); unawaited(context.read().start()); }); } @override void dispose() { WidgetsBinding.instance.removeObserver(this); super.dispose(); } @override void didChangeAppLifecycleState(AppLifecycleState state) { if (!mounted) return; final system = context.read(); switch (state) { case AppLifecycleState.resumed: _applyImmersive(); context.read().refreshNow(); system.start(); unawaited(context.read().apply()); unawaited(context.read().start()); unawaited(context.read().start()); unawaited(context.read().start()); unawaited(context.read().start()); context.read().refresh(); case AppLifecycleState.inactive: // The system volume panel and permission dialogs can make the activity // inactive without hiding it. Keep polling so the volume ring stays in // sync while that panel is open. break; case AppLifecycleState.hidden: case AppLifecycleState.paused: case AppLifecycleState.detached: system.stop(); context.read().stop(); context.read().stop(); context.read().stop(); } } Future _applyImmersive() async { await SystemChrome.setPreferredOrientations(const [ DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight, ]); await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky); } @override Widget build(BuildContext context) { final themeController = context.watch(); final lightTheme = AppTheme.light(accent: themeController.accent); final darkTheme = AppTheme.dark(accent: themeController.accent); return MaterialApp( debugShowCheckedModeBanner: false, title: 'CarDash', theme: lightTheme, darkTheme: darkTheme, themeMode: themeController.themeMode, themeAnimationDuration: const Duration(milliseconds: 260), themeAnimationCurve: Curves.easeOutCubic, builder: (context, child) { final media = MediaQuery.of(context); return MediaQuery( data: media.copyWith( textScaler: media.textScaler.clamp( minScaleFactor: 0.9, maxScaleFactor: 1.15, ), ), child: child ?? const SizedBox.shrink(), ); }, home: Consumer( builder: (context, lock, _) { return lock.isLocked ? const LockScreen() : const HomeScreen(); }, ), ); } }