import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import '../../core/theme/app_colors.dart'; import '../../core/widgets/app_icon.dart'; import '../../core/widgets/surface_card.dart'; import '../../data/models/slot_type.dart'; import '../apps/all_apps_screen.dart'; import '../apps/app_picker_sheet.dart'; import '../settings/settings_screen.dart'; import 'launcher_controller.dart'; import 'system_controller.dart'; import 'widgets/clock_block.dart'; import 'widgets/shortcut_grid.dart'; import 'widgets/status_cluster.dart'; import 'widgets/volume_card.dart'; /// The only home page. No app bar, no dock, no pages: information, the main /// volume control, and five configurable shortcuts. class HomeScreen extends StatelessWidget { const HomeScreen({super.key}); @override Widget build(BuildContext context) { final colors = context.colors; final theme = Theme.of(context); final launcher = context.watch(); final system = context.watch(); final screen = MediaQuery.sizeOf(context); final compact = screen.height < 700 || screen.width < 1100; final horizontalPadding = compact ? 30.0 : 44.0; final leftWidth = (screen.width * 0.37).clamp(300.0, 440.0); final gap = compact ? 26.0 : 40.0; final showHomeBanner = launcher.defaultHomeKnown && !launcher.isDefaultHome; final navigation = launcher.assignmentFor(SlotType.navigation); final music = launcher.assignmentFor(SlotType.music); final radio = launcher.assignmentFor(SlotType.radio); final shortcuts = [ ShortcutSpec( title: 'Navigation', subtitle: navigation?.label ?? 'Select app', iconAsset: SlotType.navigation.iconAsset, assigned: navigation != null, onTap: () => _openSlot(context, SlotType.navigation), onLongPress: () => showAppPicker(context, SlotType.navigation), ), ShortcutSpec( title: 'Music', subtitle: music?.label ?? 'Select app', iconAsset: SlotType.music.iconAsset, assigned: music != null, onTap: () => _openSlot(context, SlotType.music), onLongPress: () => showAppPicker(context, SlotType.music), ), ShortcutSpec( title: 'Radio', subtitle: radio?.label ?? 'Select app', iconAsset: SlotType.radio.iconAsset, assigned: radio != null, onTap: () => _openSlot(context, SlotType.radio), onLongPress: () => showAppPicker(context, SlotType.radio), ), ShortcutSpec( title: 'Settings', subtitle: 'Theme & PIN', iconAsset: 'assets/icons/settings.svg', assigned: true, onTap: () => _openSettings(context), ), ShortcutSpec( title: 'All apps', subtitle: 'Installed apps', iconAsset: 'assets/icons/layout-grid.svg', assigned: true, onTap: () => _openAllApps(context), ), ]; return PopScope( canPop: false, child: Scaffold( backgroundColor: colors.canvas, body: Stack( children: [ Positioned.fill( child: DecoratedBox( decoration: homeBackground( colors, Theme.of(context).brightness, ), ), ), Positioned( top: -190, right: -120, child: IgnorePointer( child: Container( width: 560, height: 560, decoration: BoxDecoration( shape: BoxShape.circle, gradient: RadialGradient( colors: [ colors.accent.withValues( alpha: Theme.of(context).brightness == Brightness.dark ? 0.16 : 0.10, ), colors.accent.withValues(alpha: 0), ], ), ), ), ), ), SafeArea( minimum: EdgeInsets.fromLTRB( horizontalPadding, compact ? 18 : 24, horizontalPadding, compact ? 14 : 18, ), child: SizedBox.expand( child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ ClockBlock(compact: compact), const Spacer(), StatusCluster(status: system.status, compact: compact), ], ), SizedBox(height: compact ? 16 : 24), Expanded( child: Row( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ SizedBox( width: leftWidth, child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, mainAxisAlignment: MainAxisAlignment.end, children: [ if (showHomeBanner) ...[ _HomeRoleBanner( launcher: launcher, onSetUp: () => _requestHome(context), ), const SizedBox(height: 14), ], VolumeCard( volume: system.volume, compact: compact, onSetVolume: system.setVolume, onToggleMute: system.toggleMute, ), ], ), ), SizedBox(width: gap), Expanded( child: Column( children: [ Expanded( child: ShortcutGrid( shortcuts: shortcuts, compact: compact, ), ), if (!compact) ...[ const SizedBox(height: 4), Text( 'Hold a shortcut to change the app', style: theme.textTheme.bodySmall?.copyWith( color: colors.inkFaint, ), ), ], ], ), ), ], ), ), ], ), ), ), ], ), ), ); } Future _openSlot(BuildContext context, SlotType slot) async { final launcher = context.read(); if (launcher.assignmentFor(slot) == null) { await showAppPicker(context, slot); return; } final error = await launcher.launchSlot(slot); if (error != null && context.mounted) { _showMessage(context, error); } } void _openSettings(BuildContext context) { Navigator.of(context) .push(MaterialPageRoute(builder: (_) => const SettingsScreen())); } void _openAllApps(BuildContext context) { Navigator.of(context) .push(MaterialPageRoute(builder: (_) => const AllAppsScreen())); } Future _requestHome(BuildContext context) async { final launcher = context.read(); final launched = await launcher.requestDefaultHome(); if (!launched && context.mounted) { _showMessage(context, 'Could not open the home app settings.'); } } void _showMessage(BuildContext context, String message) { ScaffoldMessenger.of(context) .showSnackBar(SnackBar(content: Text(message))); } } class _HomeRoleBanner extends StatelessWidget { const _HomeRoleBanner({required this.launcher, required this.onSetUp}); final LauncherController launcher; final VoidCallback onSetUp; @override Widget build(BuildContext context) { final colors = context.colors; final theme = Theme.of(context); return SurfaceCard( padding: const EdgeInsets.fromLTRB(18, 16, 18, 16), radius: 24, color: colors.accentSoft.withValues(alpha: 0.62), borderColor: colors.accent.withValues(alpha: 0.18), showShadow: false, child: Row( children: [ Container( width: 38, height: 38, decoration: BoxDecoration( color: colors.accent.withValues(alpha: 0.14), borderRadius: BorderRadius.circular(13), ), alignment: Alignment.center, child: AppIcon( 'assets/icons/smartphone.svg', size: 18, color: colors.accent, ), ), const SizedBox(width: 13), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'Make CarDash your home app', style: theme.textTheme.titleSmall, ), const SizedBox(height: 2), Text( 'Open it with the Home button.', style: theme.textTheme.bodySmall?.copyWith( color: colors.inkMuted, ), ), ], ), ), TextButton( onPressed: onSetUp, style: TextButton.styleFrom( foregroundColor: colors.accent, textStyle: theme.textTheme.labelLarge, ), child: const Text('Set up'), ), ], ), ); } }