app.dart 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101
  1. import 'package:flutter/material.dart';
  2. import 'package:flutter/services.dart';
  3. import 'package:provider/provider.dart';
  4. import 'core/theme/app_theme.dart';
  5. import 'core/theme/theme_controller.dart';
  6. import 'features/home/home_screen.dart';
  7. import 'features/home/launcher_controller.dart';
  8. import 'features/home/system_controller.dart';
  9. import 'features/lock/lock_controller.dart';
  10. import 'features/lock/lock_screen.dart';
  11. class CarDashApp extends StatefulWidget {
  12. const CarDashApp({super.key});
  13. @override
  14. State<CarDashApp> createState() => _CarDashAppState();
  15. }
  16. class _CarDashAppState extends State<CarDashApp> with WidgetsBindingObserver {
  17. @override
  18. void initState() {
  19. super.initState();
  20. WidgetsBinding.instance.addObserver(this);
  21. WidgetsBinding.instance.addPostFrameCallback((_) {
  22. if (!mounted) return;
  23. _applyImmersive();
  24. context.read<SystemController>().start();
  25. });
  26. }
  27. @override
  28. void dispose() {
  29. WidgetsBinding.instance.removeObserver(this);
  30. super.dispose();
  31. }
  32. @override
  33. void didChangeAppLifecycleState(AppLifecycleState state) {
  34. if (!mounted) return;
  35. final system = context.read<SystemController>();
  36. switch (state) {
  37. case AppLifecycleState.resumed:
  38. _applyImmersive();
  39. context.read<ThemeController>().refreshNow();
  40. system.start();
  41. context.read<LauncherController>().refresh();
  42. case AppLifecycleState.inactive:
  43. // The system volume panel and permission dialogs can make the activity
  44. // inactive without hiding it. Keep polling so the volume ring stays in
  45. // sync while that panel is open.
  46. break;
  47. case AppLifecycleState.hidden:
  48. case AppLifecycleState.paused:
  49. case AppLifecycleState.detached:
  50. system.stop();
  51. }
  52. }
  53. Future<void> _applyImmersive() async {
  54. await SystemChrome.setPreferredOrientations(const [
  55. DeviceOrientation.landscapeLeft,
  56. DeviceOrientation.landscapeRight,
  57. ]);
  58. await SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky);
  59. }
  60. @override
  61. Widget build(BuildContext context) {
  62. final themeController = context.watch<ThemeController>();
  63. final lightTheme = AppTheme.light(accent: themeController.accent);
  64. final darkTheme = AppTheme.dark(accent: themeController.accent);
  65. return MaterialApp(
  66. debugShowCheckedModeBanner: false,
  67. title: 'CarDash',
  68. theme: lightTheme,
  69. darkTheme: darkTheme,
  70. themeMode: themeController.themeMode,
  71. themeAnimationDuration: const Duration(milliseconds: 260),
  72. themeAnimationCurve: Curves.easeOutCubic,
  73. builder: (context, child) {
  74. final media = MediaQuery.of(context);
  75. return MediaQuery(
  76. data: media.copyWith(
  77. textScaler: media.textScaler.clamp(
  78. minScaleFactor: 0.9,
  79. maxScaleFactor: 1.15,
  80. ),
  81. ),
  82. child: child ?? const SizedBox.shrink(),
  83. );
  84. },
  85. home: Consumer<LockController>(
  86. builder: (context, lock, _) {
  87. return lock.isLocked ? const LockScreen() : const HomeScreen();
  88. },
  89. ),
  90. );
  91. }
  92. }