From ef744c215e7c1de1eb0b603003915dc135ea31c5 Mon Sep 17 00:00:00 2001 From: Michael Date: Mon, 10 Aug 2026 21:57:35 +0200 Subject: [PATCH] fix(ui): make screen backgrounds full-bleed instead of content-sized The gradient Container in the playlist selection and admin screens sized itself to its content rather than the viewport: under the loose body constraints, SingleChildScrollView and Wrap both shrink-wrap, so the gradient was painted only across a 436 px band (48 padding + 340 card + 48 padding) with the rest of the screen falling through to bare black. BoxConstraints.expand() forces full coverage. Also: - both screens now use AppColors.backgroundGradient. The previous ramp ran surfaceContainerLowest -> background -> baseLevel0, i.e. dark to lighter to dark, which put a pale band across the middle - the playlist card was a 3% cream translucent plate, so it took on whatever sat behind it instead of resting on it; it is now an opaque surface (surfaceContainerLow, surfaceContainerHigh on hover) with the lift() shadow at rest and the ember focus halo on hover - Scaffold backgroundColor pinned to baseLevel0 so route transitions never flash pure black Co-Authored-By: Claude Opus 5 --- lib/features/admin/screens/admin_panel.dart | 13 ++--- .../screens/playlist_selection_screen.dart | 47 +++++++++---------- 2 files changed, 27 insertions(+), 33 deletions(-) diff --git a/lib/features/admin/screens/admin_panel.dart b/lib/features/admin/screens/admin_panel.dart index 15c1813..0fde8cf 100644 --- a/lib/features/admin/screens/admin_panel.dart +++ b/lib/features/admin/screens/admin_panel.dart @@ -24,16 +24,13 @@ class AdminPanel extends StatelessWidget { Widget build(BuildContext context) { return Scaffold( extendBodyBehindAppBar: true, + backgroundColor: AppColors.baseLevel0, body: Container( + // Meme precaution que sur l'ecran de selection de playlist : sans + // contrainte d'expansion, le degrade ne couvre que le contenu. + constraints: const BoxConstraints.expand(), decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - AppColors.surfaceVariant, - AppColors.background, - ], - ), + gradient: AppColors.backgroundGradient, ), child: const AdminContent(), ), diff --git a/lib/features/iptv/screens/playlist_selection_screen.dart b/lib/features/iptv/screens/playlist_selection_screen.dart index e15544f..e2cf84a 100644 --- a/lib/features/iptv/screens/playlist_selection_screen.dart +++ b/lib/features/iptv/screens/playlist_selection_screen.dart @@ -5,6 +5,7 @@ import 'package:google_fonts/google_fonts.dart'; import '../../../core/services/playlist_api_service.dart'; import '../../../core/models/playlist_config.dart'; import '../../../core/theme/app_colors.dart'; +import '../../../core/theme/app_theme.dart'; import '../../auth/providers/auth_provider.dart'; import '../providers/xtream_provider.dart'; @@ -24,6 +25,9 @@ class PlaylistSelectionScreen extends ConsumerWidget { return Scaffold( extendBodyBehindAppBar: true, + // Filet de securite : meme pendant une transition de route, le fond + // reste dans la palette au lieu de virer au noir pur. + backgroundColor: AppColors.baseLevel0, appBar: AppBar( title: Text( 'Select Playlist', @@ -57,16 +61,14 @@ class PlaylistSelectionScreen extends ConsumerWidget { ], ), body: Container( + // `BoxConstraints.expand()` est indispensable ici : sous les + // contraintes laches du body, ce Container se dimensionnait sur son + // contenu (SingleChildScrollView -> Wrap shrink-wrappent tous les + // deux), si bien que le degrade n'etait peint que sur un rectangle + // de la taille des cartes, le reste de l'ecran restant noir. + constraints: const BoxConstraints.expand(), decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - AppColors.surfaceContainerLowest, - AppColors.background, - AppColors.baseLevel0, - ], - ), + gradient: AppColors.backgroundGradient, ), child: SafeArea( child: LayoutBuilder( @@ -208,26 +210,21 @@ class _PlaylistCardState extends State<_PlaylistCard> { child: AnimatedContainer( duration: const Duration(milliseconds: 200), decoration: BoxDecoration( + // Surface OPAQUE : une plaque a 3 % de creme prenait la couleur du + // fond et flottait sans jamais se poser dessus. Un cran de la + // hierarchie de surfaces ancre la carte, l'ombre fait le relief. color: _isHovered - ? AppColors.onSurface.withOpacity(0.1) - : AppColors.onSurface.withOpacity(0.03), - borderRadius: BorderRadius.circular(24), + ? AppColors.surfaceContainerHigh + : AppColors.surfaceContainerLow, + borderRadius: BorderRadius.circular(AppTheme.radiusXl), border: Border.all( color: _isHovered - ? AppColors.primary.withOpacity(0.5) - : AppColors.onSurface.withOpacity(0.08), - width: 1.5, + ? AppColors.primaryContainer + : AppColors.glassLevel1Border, + width: _isHovered ? 2 : 1, ), - boxShadow: _isHovered - ? [ - BoxShadow( - color: AppColors.primary.withOpacity(0.2), - blurRadius: 30, - spreadRadius: -5, - offset: const Offset(0, 10), - ), - ] - : [], + boxShadow: + _isHovered ? AppColors.emberFocus() : AppColors.lift(), ), padding: const EdgeInsets.all(24), child: Column(