fix(theme): remove every hardcoded Apple/Material colour left in the UI

Porting the palette was not enough: the Warm Cinema charter only reached the
widgets that read from AppColors. Nineteen screen and widget files still painted
Apple TV values inline, so the app kept showing blue — most visibly on the
selected navigation pill.

Swept out:
- 0xFF0A84FF (Apple blue) on the selected nav pill, category card icons and the
  "add playlist" button
- 0xFF4FC3F7 and 0xFF1565C0 in the player overlays
- Colors.blueAccent / Colors.blue in dialogs
- Apple greys 1C1C1E / 2C2C2E / 3A3A3C / 8E8E93 -> warm charcoals
- 128 Colors.white* -> the onSurfaceNN cream ladder (a pure white on a warm
  ground reads blue, which is the charter's whole point)
- Colors.red / green / amber / yellow / grey* -> error, success, ratingGold,
  outlineVariant
- pure black ink on light fills -> onPrimaryFixed, a warm near-black
- the white focus glow -> an ember glow

Deliberately left true black: the video surface backgrounds and the scrims over
posters and video, where a warm tint would clash with the picture.

Adds the onPrimaryFixed / primaryFixed / onSurface70 tokens the sweep needed.

Verified: no Material or Apple colour literal remains outside lib/core/theme;
flutter analyze reports no errors; 19/19 tests pass; release APK builds.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
MichaelandClaude Opus 5 committed 2026-08-11 20:39:58 +02:00
1 parent 8d74bbb320
commit 694b1257b9
21 files changed
+221 -184

No files matched your search

+9
View File
@@ -53,6 +53,14 @@ class AppColors {
/// en restant la même couleur perçue. /// en restant la même couleur perçue.
static const Color primaryFill = Color(0xFFA8360C); static const Color primaryFill = Color(0xFFA8360C);
/// Encre chaude — remplace le noir pur pour du texte/des icônes posés sur un
/// remplissage clair (crème, ember clair). Un noir pur sur une teinte chaude
/// paraît sale ; ce brun très sombre garde le contraste sans le décalage.
static const Color onPrimaryFixed = Color(0xFF360F00);
static const Color primaryFixed = Color(0xFFFFDBC8);
static const Color primaryFixedDim = Color(0xFFFFB68C);
static const Color onPrimaryFixedVariant = Color(0xFF7A2C08);
// ============ SECONDARY (Terre cuite / argile) ============ // ============ SECONDARY (Terre cuite / argile) ============
static const Color secondary = Color(0xFFE7C3AC); static const Color secondary = Color(0xFFE7C3AC);
static const Color onSecondary = Color(0xFF442A1B); static const Color onSecondary = Color(0xFF442A1B);
@@ -92,6 +100,7 @@ class AppColors {
static const Color onSurface24 = Color(0x3DF3E9DF); static const Color onSurface24 = Color(0x3DF3E9DF);
static const Color onSurface38 = Color(0x61F3E9DF); static const Color onSurface38 = Color(0x61F3E9DF);
static const Color onSurface54 = Color(0x8AF3E9DF); static const Color onSurface54 = Color(0x8AF3E9DF);
static const Color onSurface70 = Color(0xB3F3E9DF);
// ============ STATUS ============ // ============ STATUS ============
static const Color success = Color(0xFF9BC46A); // olive lumineux static const Color success = Color(0xFF9BC46A); // olive lumineux
+4 -3
View File
@@ -10,6 +10,7 @@ library;
import 'package:cached_network_image/cached_network_image.dart'; import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:xtremobile/core/theme/app_colors.dart';
/// Standard cache manager with 200MB size limit /// Standard cache manager with 200MB size limit
class AppCacheManager { class AppCacheManager {
@@ -103,7 +104,7 @@ class ImageCacheConfig {
width: width, width: width,
height: height, height: height,
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0xFF2C2C2E), color: AppColors.surfaceContainer,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
), ),
@@ -111,10 +112,10 @@ class ImageCacheConfig {
width: width, width: width,
height: height, height: height,
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0xFF3A3A3C), color: AppColors.surfaceContainerHigh,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
child: const Icon(Icons.image_not_supported, color: Color(0xFF8E8E93)), child: const Icon(Icons.image_not_supported, color: AppColors.textTertiary),
), ),
); );
} }
@@ -150,7 +150,7 @@ class _HeroCarouselState extends State<HeroCarousel> {
style: GoogleFonts.outfit( style: GoogleFonts.outfit(
fontSize: 32, fontSize: 32,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: Colors.white, color: AppColors.onSurface,
), ),
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@@ -161,7 +161,7 @@ class _HeroCarouselState extends State<HeroCarousel> {
item.subtitle!, item.subtitle!,
style: GoogleFonts.inter( style: GoogleFonts.inter(
fontSize: 16, fontSize: 16,
color: Colors.white.withOpacity(0.8), color: AppColors.onSurface.withOpacity(0.8),
), ),
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
@@ -227,8 +227,8 @@ class _HeroButtonState extends State<_HeroButton> {
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12), padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: widget.isPrimary color: widget.isPrimary
? (_isHovered ? Colors.white : Colors.white.withOpacity(0.9)) ? (_isHovered ? AppColors.onSurface : AppColors.onSurface.withOpacity(0.9))
: (_isHovered ? Colors.white.withOpacity(0.2) : Colors.white.withOpacity(0.1)), : (_isHovered ? AppColors.onSurface.withOpacity(0.2) : AppColors.onSurface.withOpacity(0.1)),
borderRadius: BorderRadius.circular(AppTheme.radiusFull), borderRadius: BorderRadius.circular(AppTheme.radiusFull),
), ),
child: Row( child: Row(
@@ -236,14 +236,14 @@ class _HeroButtonState extends State<_HeroButton> {
children: [ children: [
Icon( Icon(
widget.icon, widget.icon,
color: widget.isPrimary ? Colors.black : Colors.white, color: widget.isPrimary ? AppColors.onPrimaryFixed : AppColors.onSurface,
size: 20, size: 20,
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
Text( Text(
widget.label, widget.label,
style: GoogleFonts.inter( style: GoogleFonts.inter(
color: widget.isPrimary ? Colors.black : Colors.white, color: widget.isPrimary ? AppColors.onPrimaryFixed : AppColors.onSurface,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
), ),
@@ -134,7 +134,7 @@ class _GradientButtonState extends State<GradientButton>
height: 20, height: 20,
child: CircularProgressIndicator( child: CircularProgressIndicator(
strokeWidth: 2, strokeWidth: 2,
color: Colors.black, color: AppColors.onPrimaryFixed,
), ),
) )
: Row( : Row(
@@ -143,13 +143,13 @@ class _GradientButtonState extends State<GradientButton>
mainAxisAlignment: MainAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
if (widget.icon != null) ...[ if (widget.icon != null) ...[
Icon(widget.icon, color: Colors.black, size: 20), Icon(widget.icon, color: AppColors.onPrimaryFixed, size: 20),
const SizedBox(width: 8), const SizedBox(width: 8),
], ],
Text( Text(
widget.label, widget.label,
style: const TextStyle( style: const TextStyle(
color: Colors.black, color: AppColors.onPrimaryFixed,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
fontSize: 14, fontSize: 14,
), ),
@@ -247,12 +247,12 @@ class LiveBadge extends StatelessWidget {
child: const Row( child: const Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon(Icons.circle, size: 6, color: Colors.white), Icon(Icons.circle, size: 6, color: AppColors.onSurface),
SizedBox(width: 4), SizedBox(width: 4),
Text( Text(
'LIVE', 'LIVE',
style: TextStyle( style: TextStyle(
color: Colors.white, color: AppColors.onSurface,
fontSize: 10, fontSize: 10,
fontWeight: FontWeight.w700, fontWeight: FontWeight.w700,
), ),
@@ -427,11 +427,11 @@ class _MediaCardState extends State<MediaCard>
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Icon(Icons.star, size: 10, color: Color(0xFFFFD700)), const Icon(Icons.star, size: 10, color: AppColors.ratingGold),
const SizedBox(width: 4), const SizedBox(width: 4),
Text( Text(
widget.rating!, widget.rating!,
style: const TextStyle(color: Colors.white, fontSize: 10, fontWeight: FontWeight.bold), style: const TextStyle(color: AppColors.onSurface, fontSize: 10, fontWeight: FontWeight.bold),
), ),
], ],
), ),
@@ -449,7 +449,7 @@ class _MediaCardState extends State<MediaCard>
color: AppColors.success, color: AppColors.success,
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: const Icon(Icons.check, size: 12, color: Colors.white), child: const Icon(Icons.check, size: 12, color: AppColors.onSurface),
), ),
), ),
], ],
+4 -3
View File
@@ -2,6 +2,7 @@ import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart'; import 'package:google_fonts/google_fonts.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import 'package:xtremobile/core/theme/app_colors.dart';
class DigitalClock extends StatefulWidget { class DigitalClock extends StatefulWidget {
const DigitalClock({super.key}); const DigitalClock({super.key});
@@ -31,16 +32,16 @@ class _DigitalClockState extends State<DigitalClock> {
return Container( return Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white.withOpacity(0.1), color: AppColors.onSurface.withOpacity(0.1),
borderRadius: BorderRadius.circular(20), borderRadius: BorderRadius.circular(20),
border: Border.all(color: Colors.white.withOpacity(0.05)), border: Border.all(color: AppColors.onSurface.withOpacity(0.05)),
), ),
child: Text( child: Text(
timeString, timeString,
style: GoogleFonts.inter( style: GoogleFonts.inter(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
fontSize: 16, fontSize: 16,
color: Colors.white, color: AppColors.onSurface,
), ),
), ),
); );
+3 -2
View File
@@ -1,4 +1,5 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:xtremobile/core/theme/app_colors.dart';
class ThemedLoading extends StatelessWidget { class ThemedLoading extends StatelessWidget {
const ThemedLoading({super.key}); const ThemedLoading({super.key});
@@ -11,7 +12,7 @@ class ThemedLoading extends StatelessWidget {
center: Alignment(0, -0.2), center: Alignment(0, -0.2),
radius: 1.5, radius: 1.5,
colors: [ colors: [
Color(0xFF2C2C2E), AppColors.surfaceContainerHigh,
Color(0xFF000000), Color(0xFF000000),
], ],
stops: [0.0, 1.0], stops: [0.0, 1.0],
@@ -19,7 +20,7 @@ class ThemedLoading extends StatelessWidget {
), ),
child: const Center( child: const Center(
child: CircularProgressIndicator( child: CircularProgressIndicator(
color: Colors.white, color: AppColors.onSurface,
strokeWidth: 3, strokeWidth: 3,
), ),
), ),
@@ -416,6 +416,7 @@ class _LitePlayerScreenState extends ConsumerState<LitePlayerScreen>
: widget.title; : widget.title;
return Scaffold( return Scaffold(
// True black behind the video surface, never the warm ink.
backgroundColor: Colors.black, backgroundColor: Colors.black,
body: GestureDetector( body: GestureDetector(
onTap: _onUserInteraction, onTap: _onUserInteraction,
@@ -453,7 +454,7 @@ class _LitePlayerScreenState extends ConsumerState<LitePlayerScreen>
), ),
child: const Icon( child: const Icon(
Icons.arrow_back, Icons.arrow_back,
color: Colors.white, color: AppColors.onSurface,
size: 28, size: 28,
), ),
), ),
@@ -472,7 +473,7 @@ class _LitePlayerScreenState extends ConsumerState<LitePlayerScreen>
child: Text( child: Text(
_currentTime, _currentTime,
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: AppColors.onSurface,
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
@@ -495,7 +496,7 @@ class _LitePlayerScreenState extends ConsumerState<LitePlayerScreen>
), ),
child: Text( child: Text(
_errorMessage!, _errorMessage!,
style: const TextStyle(color: Colors.red), style: const TextStyle(color: AppColors.error),
), ),
), ),
), ),
@@ -554,7 +555,7 @@ class _LitePlayerScreenState extends ConsumerState<LitePlayerScreen>
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.black.withOpacity(0.7), color: Colors.black.withOpacity(0.7),
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
border: Border.all(color: Colors.white10), border: Border.all(color: AppColors.onSurface12),
), ),
child: IntrinsicHeight( child: IntrinsicHeight(
child: Row( child: Row(
@@ -579,7 +580,7 @@ class _LitePlayerScreenState extends ConsumerState<LitePlayerScreen>
), ),
child: const Icon( child: const Icon(
Icons.skip_previous, Icons.skip_previous,
color: Colors.white, color: AppColors.onSurface,
size: 36, size: 36,
), ),
), ),
@@ -591,7 +592,7 @@ class _LitePlayerScreenState extends ConsumerState<LitePlayerScreen>
_isPlaying _isPlaying
? Icons.pause_circle_filled ? Icons.pause_circle_filled
: Icons.play_circle_filled, : Icons.play_circle_filled,
color: Colors.white, color: AppColors.onSurface,
size: 56, size: 56,
), ),
), ),
@@ -605,7 +606,7 @@ class _LitePlayerScreenState extends ConsumerState<LitePlayerScreen>
), ),
child: const Icon( child: const Icon(
Icons.skip_next, Icons.skip_next,
color: Colors.white, color: AppColors.onSurface,
size: 36, size: 36,
), ),
), ),
@@ -642,7 +643,7 @@ class _LitePlayerScreenState extends ConsumerState<LitePlayerScreen>
child: const Icon( child: const Icon(
Icons Icons
.grid_on, // Icon representing interlaced grid/mesh .grid_on, // Icon representing interlaced grid/mesh
color: Colors.white, color: AppColors.onSurface,
size: 32, size: 32,
), ),
), ),
@@ -684,7 +685,7 @@ class _LitePlayerScreenState extends ConsumerState<LitePlayerScreen>
child: Text( child: Text(
title, title,
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: AppColors.onSurface,
fontSize: 18, fontSize: 18,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
@@ -710,7 +711,7 @@ class _LitePlayerScreenState extends ConsumerState<LitePlayerScreen>
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
child: LinearProgressIndicator( child: LinearProgressIndicator(
value: progress, value: progress,
backgroundColor: Colors.white10, backgroundColor: AppColors.onSurface12,
color: AppColors.primary, color: AppColors.primary,
minHeight: 4, minHeight: 4,
), ),
@@ -718,7 +719,7 @@ class _LitePlayerScreenState extends ConsumerState<LitePlayerScreen>
const SizedBox(height: 6), const SizedBox(height: 6),
Text( Text(
next, next,
style: const TextStyle(color: Colors.white54, fontSize: 12), style: const TextStyle(color: AppColors.onSurface54, fontSize: 12),
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
@@ -758,7 +759,7 @@ class _LitePlayerScreenState extends ConsumerState<LitePlayerScreen>
min: 0, min: 0,
max: _duration.inSeconds.toDouble(), max: _duration.inSeconds.toDouble(),
activeColor: AppColors.primary, activeColor: AppColors.primary,
inactiveColor: Colors.white24, inactiveColor: AppColors.onSurface24,
onChanged: (v) => setState(() { onChanged: (v) => setState(() {
_position = Duration(seconds: v.toInt()); _position = Duration(seconds: v.toInt());
_isSeeking = true; _isSeeking = true;
@@ -236,7 +236,7 @@ class _MobilePlaylistScreenState extends ConsumerState<MobilePlaylistScreen> {
? 'Playlist modifiée' ? 'Playlist modifiée'
: 'Playlist ajoutée', : 'Playlist ajoutée',
), ),
backgroundColor: Colors.green, backgroundColor: AppColors.success,
), ),
); );
} }
@@ -125,7 +125,7 @@ class _MobilePlaylistSelectionScreenState
const SizedBox(height: 16), const SizedBox(height: 16),
Text( Text(
'Erreur de chargement', 'Erreur de chargement',
style: GoogleFonts.inter(color: Colors.white), style: GoogleFonts.inter(color: AppColors.onSurface),
), ),
TextButton( TextButton(
onPressed: () => ref.invalidate(playlistsProvider), onPressed: () => ref.invalidate(playlistsProvider),
@@ -143,14 +143,14 @@ class _MobilePlaylistSelectionScreenState
const Icon( const Icon(
Icons.playlist_add, Icons.playlist_add,
size: 64, size: 64,
color: Colors.white54, color: AppColors.onSurface54,
), ),
const SizedBox(height: 24), const SizedBox(height: 24),
Text( Text(
'Aucune playlist configurée', 'Aucune playlist configurée',
style: GoogleFonts.inter( style: GoogleFonts.inter(
fontSize: 18, fontSize: 18,
color: Colors.white70, color: AppColors.onSurface70,
), ),
), ),
const SizedBox(height: 32), const SizedBox(height: 32),
@@ -163,18 +163,18 @@ class _MobilePlaylistSelectionScreenState
vertical: 14, vertical: 14,
), ),
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0xFF0A84FF), color: AppColors.primaryFill,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
child: const Row( child: const Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
Icon(Icons.add, color: Colors.white, size: 20), Icon(Icons.add, color: AppColors.onSurface, size: 20),
SizedBox(width: 10), SizedBox(width: 10),
Text( Text(
'Ajouter une Playlist', 'Ajouter une Playlist',
style: TextStyle( style: TextStyle(
color: Colors.white, color: AppColors.onSurface,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 15, fontSize: 15,
), ),
@@ -268,21 +268,21 @@ class _PlaylistEditDialogState extends State<_PlaylistEditDialog> {
context: context, context: context,
builder: (ctx) => AlertDialog( builder: (ctx) => AlertDialog(
backgroundColor: AppColors.surface, backgroundColor: AppColors.surface,
title: Text(label, style: const TextStyle(color: Colors.white)), title: Text(label, style: const TextStyle(color: AppColors.onSurface)),
content: TextField( content: TextField(
controller: controller, controller: controller,
autofocus: true, autofocus: true,
obscureText: obscure, obscureText: obscure,
keyboardType: keyboardType, keyboardType: keyboardType,
textInputAction: TextInputAction.done, textInputAction: TextInputAction.done,
style: const TextStyle(color: Colors.white), style: const TextStyle(color: AppColors.onSurface),
decoration: const InputDecoration( decoration: const InputDecoration(
labelStyle: TextStyle(color: Colors.white70), labelStyle: TextStyle(color: AppColors.onSurface70),
enabledBorder: UnderlineInputBorder( enabledBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white24), borderSide: BorderSide(color: AppColors.onSurface24),
), ),
focusedBorder: UnderlineInputBorder( focusedBorder: UnderlineInputBorder(
borderSide: BorderSide(color: Colors.white), borderSide: BorderSide(color: AppColors.onSurface),
), ),
), ),
onSubmitted: (val) => Navigator.pop(ctx, val), onSubmitted: (val) => Navigator.pop(ctx, val),
@@ -327,7 +327,7 @@ class _PlaylistEditDialogState extends State<_PlaylistEditDialog> {
child: Container( child: Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 14),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white.withOpacity(0.07), color: AppColors.onSurface.withOpacity(0.07),
borderRadius: BorderRadius.circular(10), borderRadius: BorderRadius.circular(10),
), ),
child: Row( child: Row(
@@ -341,7 +341,7 @@ class _PlaylistEditDialogState extends State<_PlaylistEditDialog> {
Text( Text(
label, label,
style: const TextStyle( style: const TextStyle(
color: Colors.white70, color: AppColors.onSurface70,
fontSize: 11, fontSize: 11,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
@@ -350,7 +350,7 @@ class _PlaylistEditDialogState extends State<_PlaylistEditDialog> {
Text( Text(
displayValue, displayValue,
style: TextStyle( style: TextStyle(
color: value.isEmpty ? Colors.white38 : Colors.white, color: value.isEmpty ? AppColors.onSurface38 : AppColors.onSurface,
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
@@ -360,7 +360,7 @@ class _PlaylistEditDialogState extends State<_PlaylistEditDialog> {
], ],
), ),
), ),
const Icon(Icons.edit, color: Colors.white38, size: 18), const Icon(Icons.edit, color: AppColors.onSurface38, size: 18),
], ],
), ),
), ),
@@ -374,7 +374,7 @@ class _PlaylistEditDialogState extends State<_PlaylistEditDialog> {
backgroundColor: AppColors.surface, backgroundColor: AppColors.surface,
title: Text( title: Text(
widget.isEditing ? 'Modifier la Playlist' : 'Ajouter une Playlist', widget.isEditing ? 'Modifier la Playlist' : 'Ajouter une Playlist',
style: GoogleFonts.inter(color: Colors.white), style: GoogleFonts.inter(color: AppColors.onSurface),
), ),
content: SizedBox( content: SizedBox(
width: 480, width: 480,
@@ -435,8 +435,8 @@ class _PlaylistEditDialogState extends State<_PlaylistEditDialog> {
context: context, context: context,
builder: (ctx) => AlertDialog( builder: (ctx) => AlertDialog(
backgroundColor: AppColors.surface, backgroundColor: AppColors.surface,
title: const Text('Confirmer', style: TextStyle(color: Colors.white)), title: const Text('Confirmer', style: TextStyle(color: AppColors.onSurface)),
content: const Text('Supprimer cette playlist ?', style: TextStyle(color: Colors.white70)), content: const Text('Supprimer cette playlist ?', style: TextStyle(color: AppColors.onSurface70)),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Navigator.pop(ctx, false), onPressed: () => Navigator.pop(ctx, false),
@@ -444,7 +444,7 @@ class _PlaylistEditDialogState extends State<_PlaylistEditDialog> {
), ),
TextButton( TextButton(
onPressed: () => Navigator.pop(ctx, true), onPressed: () => Navigator.pop(ctx, true),
style: TextButton.styleFrom(foregroundColor: Colors.red), style: TextButton.styleFrom(foregroundColor: AppColors.error),
child: const Text('Supprimer'), child: const Text('Supprimer'),
), ),
], ],
@@ -458,7 +458,7 @@ class _PlaylistEditDialogState extends State<_PlaylistEditDialog> {
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
child: const Padding( child: const Padding(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Text('Supprimer', style: TextStyle(color: Colors.red)), child: Text('Supprimer', style: TextStyle(color: AppColors.error)),
), ),
), ),
TVFocusable( TVFocusable(
@@ -466,7 +466,7 @@ class _PlaylistEditDialogState extends State<_PlaylistEditDialog> {
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
child: const Padding( child: const Padding(
padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4), padding: EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Text('Annuler', style: TextStyle(color: Colors.white70)), child: Text('Annuler', style: TextStyle(color: AppColors.onSurface70)),
), ),
), ),
TVFocusable( TVFocusable(
@@ -482,14 +482,14 @@ class _PlaylistEditDialogState extends State<_PlaylistEditDialog> {
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: _name.isEmpty || _dns.isEmpty color: _name.isEmpty || _dns.isEmpty
? Colors.white12 ? AppColors.onSurface12
: AppColors.primary, : AppColors.primary,
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
), ),
child: Text( child: Text(
_isSaving ? '...' : 'Enregistrer', _isSaving ? '...' : 'Enregistrer',
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: AppColors.onSurface,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
@@ -129,7 +129,7 @@ class _MobileSeriesDetailScreenState
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: IconButton( child: IconButton(
icon: const Icon(Icons.arrow_back, color: Colors.white), icon: const Icon(Icons.arrow_back, color: AppColors.onSurface),
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
tooltip: 'Back', tooltip: 'Back',
), ),
@@ -149,7 +149,7 @@ class _MobileSeriesDetailScreenState
maxHeightDiskCache: 720, maxHeightDiskCache: 720,
cacheManager: AppCacheManager.instance, cacheManager: AppCacheManager.instance,
errorWidget: (_, __, ___) => errorWidget: (_, __, ___) =>
Container(color: Colors.grey.shade900), Container(color: AppColors.surfaceContainerLowest),
), ),
// Gradient Overlay // Gradient Overlay
Container( Container(
@@ -190,7 +190,7 @@ class _MobileSeriesDetailScreenState
const Icon( const Icon(
Icons.star, Icons.star,
size: 16, size: 16,
color: Colors.amber, color: AppColors.ratingGold,
), ),
const SizedBox(width: 4), const SizedBox(width: 4),
Text( Text(
@@ -261,15 +261,15 @@ class _MobileSeriesDetailScreenState
} }
}, },
backgroundColor: isDark backgroundColor: isDark
? const Color(0xFF1C1C1E) ? AppColors.surfaceContainer
: Colors.grey.shade300, : AppColors.surfaceContainerHigh,
selectedColor: isDark ? Colors.white : Colors.blue, selectedColor: isDark ? AppColors.onSurface : AppColors.primaryFill,
labelStyle: TextStyle( labelStyle: TextStyle(
color: isSelected color: isSelected
? (isDark ? Colors.black : Colors.white) ? (isDark ? AppColors.onPrimaryFixed : AppColors.onSurface)
: (isDark : (isDark
? Colors.grey.shade400 ? AppColors.textSecondary
: Colors.grey.shade700), : AppColors.outlineVariant),
fontWeight: fontWeight:
isSelected ? FontWeight.w600 : FontWeight.w400, isSelected ? FontWeight.w600 : FontWeight.w400,
), ),
@@ -323,10 +323,10 @@ class _MobileSeriesDetailScreenState
} }
// Force dark mode colors since background is hardcoded dark // Force dark mode colors since background is hardcoded dark
const textColor = Colors.white; const textColor = AppColors.onSurface;
final secondaryTextColor = Colors.grey.shade400; final secondaryTextColor = AppColors.textSecondary;
const surfaceColor = Color(0xFF1C1C1E); const surfaceColor = AppColors.surfaceContainer;
const primaryColor = Colors.white; // Or accent color if preferred const primaryColor = AppColors.onSurface; // Or accent color if preferred
return InkWell( return InkWell(
onTap: () { onTap: () {
@@ -356,7 +356,7 @@ class _MobileSeriesDetailScreenState
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12), padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
decoration: const BoxDecoration( decoration: const BoxDecoration(
border: Border(bottom: BorderSide(color: Colors.white10)), border: Border(bottom: BorderSide(color: AppColors.onSurface12)),
), ),
child: Row( child: Row(
children: [ children: [
@@ -374,7 +374,7 @@ class _MobileSeriesDetailScreenState
child: Icon( child: Icon(
isWatched ? Icons.check : Icons.play_arrow, isWatched ? Icons.check : Icons.play_arrow,
color: isWatched color: isWatched
? Colors.black // Checkmark on white bg ? AppColors.onPrimaryFixed // Checkmark on white bg
: primaryColor, // Play icon : primaryColor, // Play icon
size: 20, size: 20,
), ),
@@ -413,7 +413,7 @@ class _MobileSeriesDetailScreenState
LinearProgressIndicator( LinearProgressIndicator(
value: progress, value: progress,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
valueColor: const AlwaysStoppedAnimation<Color>(Colors.red), valueColor: const AlwaysStoppedAnimation<Color>(AppColors.error),
minHeight: 2, minHeight: 2,
), ),
], ],
@@ -654,7 +654,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
'Reprise à ${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}', 'Reprise à ${minutes.toString().padLeft(2, '0')}:${seconds.toString().padLeft(2, '0')}',
), ),
duration: const Duration(seconds: 2), duration: const Duration(seconds: 2),
backgroundColor: Colors.green.shade700, backgroundColor: AppColors.success,
), ),
); );
} else { } else {
@@ -1293,6 +1293,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
// Loading Overlay — black only on FIRST load // Loading Overlay — black only on FIRST load
if (_isLoading && _errorMessage == null) if (_isLoading && _errorMessage == null)
Container( Container(
// True black, not the warm ink: this sits over the video surface.
color: Colors.black, color: Colors.black,
child: _buildLoadingView(), child: _buildLoadingView(),
), ),
@@ -1313,7 +1314,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
height: 20, height: 20,
child: CircularProgressIndicator( child: CircularProgressIndicator(
strokeWidth: 2, strokeWidth: 2,
color: Colors.white70, color: AppColors.onSurface70,
), ),
), ),
), ),
@@ -1349,7 +1350,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
child: IconButton( child: IconButton(
icon: const Icon( icon: const Icon(
Icons.arrow_back, Icons.arrow_back,
color: Colors.white, color: AppColors.onSurface,
), ),
onPressed: () => Navigator.pop(context), onPressed: () => Navigator.pop(context),
), ),
@@ -1380,7 +1381,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
Text( Text(
title, title,
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: AppColors.onSurface,
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
@@ -1392,7 +1393,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
Text( Text(
_currentTime, _currentTime,
style: const TextStyle( style: const TextStyle(
color: Colors.white70, color: AppColors.onSurface70,
fontSize: 12, fontSize: 12,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
@@ -1485,7 +1486,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.black.withOpacity(0.7), color: Colors.black.withOpacity(0.7),
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
border: Border.all(color: Colors.white10), border: Border.all(color: AppColors.onSurface12),
), ),
child: IntrinsicHeight( child: IntrinsicHeight(
child: Row( child: Row(
@@ -1506,7 +1507,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
onFocus: _resetControlsTimer, onFocus: _resetControlsTimer,
child: const Icon( child: const Icon(
Icons.skip_previous, Icons.skip_previous,
color: Colors.white, color: AppColors.onSurface,
size: 36, size: 36,
), ),
), ),
@@ -1521,7 +1522,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
_isPlaying _isPlaying
? Icons.pause_circle_filled ? Icons.pause_circle_filled
: Icons.play_circle_filled, : Icons.play_circle_filled,
color: Colors.white, color: AppColors.onSurface,
size: 56, size: 56,
), ),
), ),
@@ -1534,7 +1535,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
onFocus: _resetControlsTimer, onFocus: _resetControlsTimer,
child: const Icon( child: const Icon(
Icons.skip_next, Icons.skip_next,
color: Colors.white, color: AppColors.onSurface,
size: 36, size: 36,
), ),
), ),
@@ -1570,7 +1571,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
onFocus: _resetControlsTimer, onFocus: _resetControlsTimer,
child: const Icon( child: const Icon(
Icons.grid_off, Icons.grid_off,
color: Colors.white, color: AppColors.onSurface,
size: 32, size: 32,
), ),
), ),
@@ -1618,7 +1619,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
imageUrl: widget.channels![_currentIndex].streamIcon, imageUrl: widget.channels![_currentIndex].streamIcon,
fit: BoxFit.contain, fit: BoxFit.contain,
errorWidget: (_, __, ___) => errorWidget: (_, __, ___) =>
const Icon(Icons.tv, color: Colors.white38), const Icon(Icons.tv, color: AppColors.onSurface38),
), ),
), ),
Expanded( Expanded(
@@ -1628,7 +1629,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
Text( Text(
title, title,
style: const TextStyle( style: const TextStyle(
color: Colors.white70, color: AppColors.onSurface70,
fontSize: 14, fontSize: 14,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
@@ -1639,7 +1640,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
Text( Text(
nowPlaying, nowPlaying,
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: AppColors.onSurface,
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
@@ -1654,7 +1655,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
Text( Text(
startTime, startTime,
style: const TextStyle( style: const TextStyle(
color: Colors.white54, fontSize: 11), color: AppColors.onSurface54, fontSize: 11),
), ),
const SizedBox(width: 6), const SizedBox(width: 6),
Expanded( Expanded(
@@ -1663,9 +1664,9 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
child: LinearProgressIndicator( child: LinearProgressIndicator(
value: epgProgress.clamp(0.0, 1.0), value: epgProgress.clamp(0.0, 1.0),
minHeight: 4, minHeight: 4,
backgroundColor: Colors.white24, backgroundColor: AppColors.onSurface24,
valueColor: const AlwaysStoppedAnimation<Color>( valueColor: const AlwaysStoppedAnimation<Color>(
Color(0xFF4FC3F7), AppColors.primary,
), ),
), ),
), ),
@@ -1674,7 +1675,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
Text( Text(
endTime, endTime,
style: const TextStyle( style: const TextStyle(
color: Colors.white54, fontSize: 11), color: AppColors.onSurface54, fontSize: 11),
), ),
], ],
), ),
@@ -1714,7 +1715,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.black.withOpacity(0.82), color: Colors.black.withOpacity(0.82),
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
border: Border.all(color: Colors.white12), border: Border.all(color: AppColors.onSurface12),
), ),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
@@ -1728,7 +1729,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
margin: const EdgeInsets.only(right: 16), margin: const EdgeInsets.only(right: 16),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
color: Colors.white10, color: AppColors.onSurface12,
), ),
child: ClipRRect( child: ClipRRect(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
@@ -1736,7 +1737,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
imageUrl: ch.streamIcon, imageUrl: ch.streamIcon,
fit: BoxFit.contain, fit: BoxFit.contain,
errorWidget: (_, __, ___) => errorWidget: (_, __, ___) =>
const Icon(Icons.tv, color: Colors.white38, size: 32), const Icon(Icons.tv, color: AppColors.onSurface38, size: 32),
), ),
), ),
) )
@@ -1747,9 +1748,9 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
margin: const EdgeInsets.only(right: 16), margin: const EdgeInsets.only(right: 16),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
color: Colors.white10, color: AppColors.onSurface12,
), ),
child: const Icon(Icons.tv, color: Colors.white38, size: 32), child: const Icon(Icons.tv, color: AppColors.onSurface38, size: 32),
), ),
// Channel info // Channel info
@@ -1765,13 +1766,13 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
horizontal: 6, vertical: 2), horizontal: 6, vertical: 2),
margin: const EdgeInsets.only(right: 8), margin: const EdgeInsets.only(right: 8),
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color(0xFF1565C0), color: const AppColors.primaryFill,
borderRadius: BorderRadius.circular(4), borderRadius: BorderRadius.circular(4),
), ),
child: Text( child: Text(
'CH $chNum', 'CH $chNum',
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: AppColors.onSurface,
fontSize: 11, fontSize: 11,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
@@ -1781,7 +1782,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
child: Text( child: Text(
ch.name, ch.name,
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: AppColors.onSurface,
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
@@ -1797,9 +1798,9 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
child: SizedBox( child: SizedBox(
height: 3, height: 3,
child: LinearProgressIndicator( child: LinearProgressIndicator(
backgroundColor: Colors.white24, backgroundColor: AppColors.onSurface24,
valueColor: AlwaysStoppedAnimation<Color>( valueColor: AlwaysStoppedAnimation<Color>(
Color(0xFF4FC3F7)), AppColors.primary),
), ),
), ),
) )
@@ -1808,7 +1809,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
Text( Text(
nowPlaying, nowPlaying,
style: const TextStyle( style: const TextStyle(
color: Colors.white70, color: AppColors.onSurface70,
fontSize: 13, fontSize: 13,
), ),
maxLines: 1, maxLines: 1,
@@ -1820,9 +1821,9 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
child: LinearProgressIndicator( child: LinearProgressIndicator(
value: epgProgress.clamp(0.0, 1.0), value: epgProgress.clamp(0.0, 1.0),
minHeight: 3, minHeight: 3,
backgroundColor: Colors.white24, backgroundColor: AppColors.onSurface24,
valueColor: const AlwaysStoppedAnimation<Color>( valueColor: const AlwaysStoppedAnimation<Color>(
Color(0xFF4FC3F7)), AppColors.primary),
), ),
), ),
], ],
@@ -1861,18 +1862,18 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
padding: const EdgeInsets.fromLTRB(16, 12, 16, 8), padding: const EdgeInsets.fromLTRB(16, 12, 16, 8),
decoration: const BoxDecoration( decoration: const BoxDecoration(
border: Border( border: Border(
bottom: BorderSide(color: Colors.white12), bottom: BorderSide(color: AppColors.onSurface12),
), ),
), ),
child: Row( child: Row(
children: [ children: [
const Icon(Icons.list, color: Colors.white70, size: 18), const Icon(Icons.list, color: AppColors.onSurface70, size: 18),
const SizedBox(width: 8), const SizedBox(width: 8),
const Expanded( const Expanded(
child: Text( child: Text(
'Chaînes', 'Chaînes',
style: TextStyle( style: TextStyle(
color: Colors.white, color: AppColors.onSurface,
fontSize: 15, fontSize: 15,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
@@ -1881,7 +1882,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
GestureDetector( GestureDetector(
onTap: () => setState(() => _showChannelList = false), onTap: () => setState(() => _showChannelList = false),
child: const Icon(Icons.close, child: const Icon(Icons.close,
color: Colors.white54, size: 18), color: AppColors.onSurface54, size: 18),
), ),
], ],
), ),
@@ -1903,12 +1904,12 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
color: isActive color: isActive
? const Color(0xFF1565C0).withOpacity(0.6) ? AppColors.primaryFill.withValues(alpha: 0.6)
: Colors.transparent, : Colors.transparent,
border: isActive border: isActive
? const Border( ? const Border(
left: BorderSide( left: BorderSide(
color: Color(0xFF4FC3F7), color: AppColors.primary,
width: 3, width: 3,
), ),
) )
@@ -1924,7 +1925,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
height: 40, height: 40,
margin: const EdgeInsets.only(right: 10), margin: const EdgeInsets.only(right: 10),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white10, color: AppColors.onSurface12,
borderRadius: BorderRadius.circular(6), borderRadius: BorderRadius.circular(6),
), ),
child: ch.streamIcon.isNotEmpty child: ch.streamIcon.isNotEmpty
@@ -1935,12 +1936,12 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
fit: BoxFit.contain, fit: BoxFit.contain,
errorWidget: (_, __, ___) => errorWidget: (_, __, ___) =>
const Icon(Icons.tv, const Icon(Icons.tv,
color: Colors.white38, color: AppColors.onSurface38,
size: 20), size: 20),
), ),
) )
: const Icon(Icons.tv, : const Icon(Icons.tv,
color: Colors.white38, size: 20), color: AppColors.onSurface38, size: 20),
), ),
// Name + num // Name + num
Expanded( Expanded(
@@ -1952,8 +1953,8 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
ch.name, ch.name,
style: TextStyle( style: TextStyle(
color: isActive color: isActive
? Colors.white ? AppColors.onSurface
: Colors.white70, : AppColors.onSurface70,
fontSize: 13, fontSize: 13,
fontWeight: isActive fontWeight: isActive
? FontWeight.bold ? FontWeight.bold
@@ -1965,7 +1966,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
Text( Text(
'CH ${index + 1}', 'CH ${index + 1}',
style: const TextStyle( style: const TextStyle(
color: Colors.white38, color: AppColors.onSurface38,
fontSize: 11, fontSize: 11,
), ),
), ),
@@ -1976,7 +1977,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
if (isActive) if (isActive)
const Icon( const Icon(
Icons.play_arrow, Icons.play_arrow,
color: Color(0xFF4FC3F7), color: AppColors.primary,
size: 18, size: 18,
), ),
], ],
@@ -2021,7 +2022,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
child: IconButton( child: IconButton(
icon: const Icon( icon: const Icon(
Icons.replay_10, Icons.replay_10,
color: Colors.white, color: AppColors.onSurface,
size: 48, size: 48,
), ),
onPressed: () async { onPressed: () async {
@@ -2046,7 +2047,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
_isPlaying _isPlaying
? Icons.pause_circle_filled ? Icons.pause_circle_filled
: Icons.play_circle_filled, : Icons.play_circle_filled,
color: Colors.white, color: AppColors.onSurface,
), ),
onPressed: _togglePlayPause, onPressed: _togglePlayPause,
), ),
@@ -2067,7 +2068,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
child: IconButton( child: IconButton(
icon: const Icon( icon: const Icon(
Icons.forward_10, Icons.forward_10,
color: Colors.white, color: AppColors.onSurface,
size: 48, size: 48,
), ),
onPressed: () async { onPressed: () async {
@@ -2103,7 +2104,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
Text( Text(
_formatDuration(_position), _formatDuration(_position),
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: AppColors.onSurface,
fontSize: 14, fontSize: 14,
), ),
), ),
@@ -2157,14 +2158,14 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
_resetControlsTimer(); _resetControlsTimer();
}, },
activeColor: AppColors.primary, activeColor: AppColors.primary,
inactiveColor: Colors.white24, inactiveColor: AppColors.onSurface24,
), ),
), ),
), ),
Text( Text(
_formatDuration(_duration), _formatDuration(_duration),
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: AppColors.onSurface,
fontSize: 14, fontSize: 14,
), ),
), ),
@@ -2199,7 +2200,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
height: 72, height: 72,
margin: const EdgeInsets.only(bottom: 16), margin: const EdgeInsets.only(bottom: 16),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.white10, color: AppColors.onSurface12,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
child: ClipRRect( child: ClipRRect(
@@ -2208,7 +2209,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
imageUrl: ch.streamIcon, imageUrl: ch.streamIcon,
fit: BoxFit.contain, fit: BoxFit.contain,
errorWidget: (_, __, ___) => errorWidget: (_, __, ___) =>
const Icon(Icons.tv, color: Colors.white38, size: 40), const Icon(Icons.tv, color: AppColors.onSurface38, size: 40),
), ),
), ),
), ),
@@ -2217,7 +2218,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
Text( Text(
ch != null ? ch.name : 'Chargement...', ch != null ? ch.name : 'Chargement...',
style: const TextStyle( style: const TextStyle(
color: Colors.white70, color: AppColors.onSurface70,
fontSize: 15, fontSize: 15,
fontWeight: FontWeight.w500, fontWeight: FontWeight.w500,
), ),
@@ -2232,18 +2233,18 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
child: Column( child: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Icon(Icons.error_outline, size: 64, color: Colors.red), const Icon(Icons.error_outline, size: 64, color: AppColors.error),
const SizedBox(height: 16), const SizedBox(height: 16),
const Text( const Text(
'Erreur de lecture', 'Erreur de lecture',
style: TextStyle(color: Colors.white, fontSize: 18), style: TextStyle(color: AppColors.onSurface, fontSize: 18),
), ),
const SizedBox(height: 8), const SizedBox(height: 8),
Padding( Padding(
padding: const EdgeInsets.symmetric(horizontal: 32), padding: const EdgeInsets.symmetric(horizontal: 32),
child: Text( child: Text(
_errorMessage ?? 'Une erreur inconnue est survenue', _errorMessage ?? 'Une erreur inconnue est survenue',
style: const TextStyle(color: Colors.white70), style: const TextStyle(color: AppColors.onSurface70),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
), ),
@@ -2256,8 +2257,8 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
icon: const Icon(Icons.arrow_back), icon: const Icon(Icons.arrow_back),
label: const Text('Retour'), label: const Text('Retour'),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: Colors.white, backgroundColor: AppColors.onSurface,
foregroundColor: Colors.black, foregroundColor: AppColors.onPrimaryFixed,
), ),
), ),
const SizedBox(width: 16), const SizedBox(width: 16),
@@ -2267,7 +2268,7 @@ class _NativePlayerScreenState extends ConsumerState<NativePlayerScreen>
label: const Text('Réessayer'), label: const Text('Réessayer'),
style: ElevatedButton.styleFrom( style: ElevatedButton.styleFrom(
backgroundColor: AppColors.primary, backgroundColor: AppColors.primary,
foregroundColor: Colors.black, foregroundColor: AppColors.onPrimaryFixed,
), ),
), ),
], ],
@@ -2328,7 +2329,7 @@ class _StatsOverlayWidgetState extends ConsumerState<StatsOverlayWidget> {
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.black.withOpacity(0.7), color: Colors.black.withOpacity(0.7),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(8),
border: Border.all(color: Colors.green.withOpacity(0.5)), border: Border.all(color: AppColors.success.withOpacity(0.5)),
), ),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@@ -2337,7 +2338,7 @@ class _StatsOverlayWidgetState extends ConsumerState<StatsOverlayWidget> {
const Text( const Text(
'STATS FOR NERDS 🤓', 'STATS FOR NERDS 🤓',
style: TextStyle( style: TextStyle(
color: Colors.green, color: AppColors.success,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 12, fontSize: 12,
), ),
@@ -2345,11 +2346,11 @@ class _StatsOverlayWidgetState extends ConsumerState<StatsOverlayWidget> {
const SizedBox(height: 4), const SizedBox(height: 4),
Text( Text(
'Buffer: ${_buffer.inSeconds}s', 'Buffer: ${_buffer.inSeconds}s',
style: const TextStyle(color: Colors.white, fontSize: 12), style: const TextStyle(color: AppColors.onSurface, fontSize: 12),
), ),
Text( Text(
'Decoder: $_decoder', 'Decoder: $_decoder',
style: const TextStyle(color: Colors.white, fontSize: 12), style: const TextStyle(color: AppColors.onSurface, fontSize: 12),
), ),
], ],
), ),
@@ -16,6 +16,7 @@ import 'package:xtremobile/features/iptv/screens/lite_player_screen.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:xtremobile/core/services/ip_service.dart'; import 'package:xtremobile/core/services/ip_service.dart';
import 'package:xtremobile/core/models/iptv_models.dart' as model; import 'package:xtremobile/core/models/iptv_models.dart' as model;
import 'package:xtremobile/core/theme/app_colors.dart';
class MobileLiveTVTab extends ConsumerStatefulWidget { class MobileLiveTVTab extends ConsumerStatefulWidget {
final PlaylistConfig playlist; final PlaylistConfig playlist;
@@ -130,14 +131,14 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab>
final shouldExit = await showDialog<bool>( final shouldExit = await showDialog<bool>(
context: context, context: context,
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
backgroundColor: Colors.grey[900], backgroundColor: AppColors.surfaceContainerLowest,
title: const Text( title: const Text(
"Quitter l'application", "Quitter l'application",
style: TextStyle(color: Colors.white), style: TextStyle(color: AppColors.onSurface),
), ),
content: const Text( content: const Text(
"Voulez-vous vraiment quitter l'application ?", "Voulez-vous vraiment quitter l'application ?",
style: TextStyle(color: Colors.white70), style: TextStyle(color: AppColors.onSurface70),
), ),
actions: [ actions: [
TextButton( TextButton(
@@ -145,14 +146,14 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab>
autofocus: true, autofocus: true,
child: const Text( child: const Text(
'Annuler', 'Annuler',
style: TextStyle(color: Colors.blueAccent), style: TextStyle(color: AppColors.primary),
), ),
), ),
TextButton( TextButton(
onPressed: () => Navigator.of(context).pop(true), onPressed: () => Navigator.of(context).pop(true),
child: const Text( child: const Text(
'Quitter', 'Quitter',
style: TextStyle(color: Colors.redAccent), style: TextStyle(color: AppColors.error),
), ),
), ),
], ],
@@ -171,7 +172,7 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab>
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: Text( child: Text(
'Erreur: $e', 'Erreur: $e',
style: const TextStyle(color: Colors.red), style: const TextStyle(color: AppColors.error),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
), ),
@@ -235,7 +236,7 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab>
// Search Bar // Search Bar
TVFocusable( TVFocusable(
scale: 1.0, scale: 1.0,
focusColor: Colors.white, focusColor: AppColors.onSurface,
onPressed: () { onPressed: () {
setState(() => _isSearchEditing = true); setState(() => _isSearchEditing = true);
WidgetsBinding.instance WidgetsBinding.instance
@@ -263,7 +264,7 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab>
child: ExcludeFocus( child: ExcludeFocus(
excluding: !_isSearchEditing, excluding: !_isSearchEditing,
child: TextField( child: TextField(
cursorColor: Colors.white, cursorColor: AppColors.onSurface,
controller: _searchController, controller: _searchController,
focusNode: _searchFocusNode, focusNode: _searchFocusNode,
readOnly: !_isSearchEditing, readOnly: !_isSearchEditing,
@@ -357,7 +358,7 @@ class _MobileLiveTVTabState extends ConsumerState<MobileLiveTVTab>
? Icons.favorite ? Icons.favorite
: Icons.favorite_border, : Icons.favorite_border,
color: _showFavoritesOnly color: _showFavoritesOnly
? const Color(0xFFFF453A) ? AppColors.live
: AppDecorations.textSecondary( : AppDecorations.textSecondary(
context), context),
), ),
@@ -535,7 +536,7 @@ class _ChannelListView extends ConsumerWidget {
child: Center( child: Center(
child: Text( child: Text(
'Aucune catégorie sélectionnée', 'Aucune catégorie sélectionnée',
style: TextStyle(color: Colors.white70), style: TextStyle(color: AppColors.onSurface70),
), ),
), ),
); );
@@ -557,7 +558,7 @@ class _ChannelListView extends ConsumerWidget {
showFavoritesOnly showFavoritesOnly
? 'Sélectionnez une catégorie pour voir vos favoris' ? 'Sélectionnez une catégorie pour voir vos favoris'
: 'Sélectionnez une catégorie pour rechercher', : 'Sélectionnez une catégorie pour rechercher',
style: const TextStyle(color: Colors.white70), style: const TextStyle(color: AppColors.onSurface70),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
), ),
@@ -575,7 +576,7 @@ class _ChannelListView extends ConsumerWidget {
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(16),
child: Text( child: Text(
'Erreur: $e', 'Erreur: $e',
style: const TextStyle(color: Colors.red), style: const TextStyle(color: AppColors.error),
textAlign: TextAlign.center, textAlign: TextAlign.center,
), ),
), ),
@@ -600,7 +601,7 @@ class _ChannelListView extends ConsumerWidget {
child: Center( child: Center(
child: Text( child: Text(
'Aucune chaîne trouvée', 'Aucune chaîne trouvée',
style: TextStyle(color: Colors.white70), style: TextStyle(color: AppColors.onSurface70),
), ),
), ),
); );
@@ -754,12 +755,12 @@ class _MobileChannelCardState extends ConsumerState<_MobileChannelCard> {
child: Container( child: Container(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
decoration: BoxDecoration( decoration: BoxDecoration(
color: Colors.red, color: AppColors.error,
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(12),
), ),
child: const Icon( child: const Icon(
Icons.favorite, Icons.favorite,
color: Colors.white, color: AppColors.onSurface,
size: 10, size: 10,
), ),
), ),
@@ -779,7 +780,7 @@ class _MobileChannelCardState extends ConsumerState<_MobileChannelCard> {
Text( Text(
widget.channel.name, widget.channel.name,
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: AppColors.onSurface,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
fontSize: 10, fontSize: 10,
), ),
@@ -792,7 +793,7 @@ class _MobileChannelCardState extends ConsumerState<_MobileChannelCard> {
Text( Text(
_epgTitle!, _epgTitle!,
style: const TextStyle( style: const TextStyle(
color: Colors.yellow, color: AppColors.ratingGold,
fontSize: 8, fontSize: 8,
), ),
textAlign: TextAlign.center, textAlign: TextAlign.center,
@@ -11,6 +11,7 @@ import 'package:xtremobile/mobile/providers/mobile_settings_providers.dart';
import 'package:xtremobile/mobile/providers/mobile_xtream_providers.dart'; import 'package:xtremobile/mobile/providers/mobile_xtream_providers.dart';
import 'package:xtremobile/core/models/iptv_models.dart' as model; import 'package:xtremobile/core/models/iptv_models.dart' as model;
import 'package:xtremobile/features/iptv/screens/native_player_screen.dart'; import 'package:xtremobile/features/iptv/screens/native_player_screen.dart';
import 'package:xtremobile/core/theme/app_colors.dart';
class MobileMoviesTab extends ConsumerStatefulWidget { class MobileMoviesTab extends ConsumerStatefulWidget {
final PlaylistConfig playlist; final PlaylistConfig playlist;
@@ -285,14 +286,14 @@ class _MobileMoviesTabState extends ConsumerState<MobileMoviesTab>
final shouldExit = await showDialog<bool>( final shouldExit = await showDialog<bool>(
context: context, context: context,
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
backgroundColor: Colors.grey[900], backgroundColor: AppColors.surfaceContainerLowest,
title: const Text( title: const Text(
"Quitter l'application", "Quitter l'application",
style: TextStyle(color: Colors.white), style: TextStyle(color: AppColors.onSurface),
), ),
content: const Text( content: const Text(
"Voulez-vous vraiment quitter l'application ?", "Voulez-vous vraiment quitter l'application ?",
style: TextStyle(color: Colors.white70), style: TextStyle(color: AppColors.onSurface70),
), ),
actions: [ actions: [
TextButton( TextButton(
@@ -300,14 +301,14 @@ class _MobileMoviesTabState extends ConsumerState<MobileMoviesTab>
autofocus: true, autofocus: true,
child: const Text( child: const Text(
'Annuler', 'Annuler',
style: TextStyle(color: Colors.blueAccent), style: TextStyle(color: AppColors.primary),
), ),
), ),
TextButton( TextButton(
onPressed: () => Navigator.of(context).pop(true), onPressed: () => Navigator.of(context).pop(true),
child: const Text( child: const Text(
'Quitter', 'Quitter',
style: TextStyle(color: Colors.redAccent), style: TextStyle(color: AppColors.error),
), ),
), ),
], ],
@@ -346,7 +347,7 @@ class _MobileMoviesTabState extends ConsumerState<MobileMoviesTab>
// Search Bar // Search Bar
TVFocusable( TVFocusable(
scale: 1.0, scale: 1.0,
focusColor: Colors.white, focusColor: AppColors.onSurface,
onPressed: () { onPressed: () {
setState(() => _isSearchEditing = true); setState(() => _isSearchEditing = true);
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -367,7 +368,7 @@ class _MobileMoviesTabState extends ConsumerState<MobileMoviesTab>
child: ExcludeFocus( child: ExcludeFocus(
excluding: !_isSearchEditing, excluding: !_isSearchEditing,
child: TextField( child: TextField(
cursorColor: Colors.white, cursorColor: AppColors.onSurface,
controller: _searchController, controller: _searchController,
focusNode: _searchFocusNode, focusNode: _searchFocusNode,
readOnly: !_isSearchEditing, readOnly: !_isSearchEditing,
@@ -11,6 +11,7 @@ import 'package:xtremobile/mobile/providers/mobile_settings_providers.dart';
import 'package:xtremobile/mobile/providers/mobile_xtream_providers.dart'; import 'package:xtremobile/mobile/providers/mobile_xtream_providers.dart';
import 'package:xtremobile/core/models/iptv_models.dart' as model; import 'package:xtremobile/core/models/iptv_models.dart' as model;
import 'package:xtremobile/features/iptv/screens/mobile_series_detail_screen.dart'; import 'package:xtremobile/features/iptv/screens/mobile_series_detail_screen.dart';
import 'package:xtremobile/core/theme/app_colors.dart';
class MobileSeriesTab extends ConsumerStatefulWidget { class MobileSeriesTab extends ConsumerStatefulWidget {
final PlaylistConfig playlist; final PlaylistConfig playlist;
@@ -269,18 +270,18 @@ class _MobileSeriesTabState extends ConsumerState<MobileSeriesTab>
final shouldExit = await showDialog<bool>( final shouldExit = await showDialog<bool>(
context: context, context: context,
builder: (context) => AlertDialog( builder: (context) => AlertDialog(
backgroundColor: Colors.grey[900], backgroundColor: AppColors.surfaceContainerLowest,
title: const Text("Quitter l'application", style: TextStyle(color: Colors.white)), title: const Text("Quitter l'application", style: TextStyle(color: AppColors.onSurface)),
content: const Text("Voulez-vous vraiment quitter l'application ?", style: TextStyle(color: Colors.white70)), content: const Text("Voulez-vous vraiment quitter l'application ?", style: TextStyle(color: AppColors.onSurface70)),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Navigator.of(context).pop(false), onPressed: () => Navigator.of(context).pop(false),
autofocus: true, autofocus: true,
child: const Text('Annuler', style: TextStyle(color: Colors.blueAccent)), child: const Text('Annuler', style: TextStyle(color: AppColors.primary)),
), ),
TextButton( TextButton(
onPressed: () => Navigator.of(context).pop(true), onPressed: () => Navigator.of(context).pop(true),
child: const Text('Quitter', style: TextStyle(color: Colors.redAccent)), child: const Text('Quitter', style: TextStyle(color: AppColors.error)),
), ),
], ],
), ),
@@ -316,7 +317,7 @@ class _MobileSeriesTabState extends ConsumerState<MobileSeriesTab>
// Search Bar // Search Bar
TVFocusable( TVFocusable(
scale: 1.0, scale: 1.0,
focusColor: Colors.white, focusColor: AppColors.onSurface,
onPressed: () { onPressed: () {
setState(() => _isSearchEditing = true); setState(() => _isSearchEditing = true);
WidgetsBinding.instance.addPostFrameCallback((_) { WidgetsBinding.instance.addPostFrameCallback((_) {
@@ -337,7 +338,7 @@ class _MobileSeriesTabState extends ConsumerState<MobileSeriesTab>
child: ExcludeFocus( child: ExcludeFocus(
excluding: !_isSearchEditing, excluding: !_isSearchEditing,
child: TextField( child: TextField(
cursorColor: Colors.white, cursorColor: AppColors.onSurface,
controller: _searchController, controller: _searchController,
focusNode: _searchFocusNode, focusNode: _searchFocusNode,
readOnly: !_isSearchEditing, readOnly: !_isSearchEditing,
@@ -8,6 +8,7 @@ import 'package:xtremobile/core/theme/app_decorations.dart';
import 'package:xtremobile/core/theme/app_theme.dart'; import 'package:xtremobile/core/theme/app_theme.dart';
import 'package:xtremobile/core/providers/theme_provider.dart'; import 'package:xtremobile/core/providers/theme_provider.dart';
import 'package:xtremobile/features/iptv/screens/mobile_playlist_selection_screen.dart'; import 'package:xtremobile/features/iptv/screens/mobile_playlist_selection_screen.dart';
import 'package:xtremobile/core/theme/app_colors.dart';
/// Simplified mobile settings tab - optimized for TV remote control /// Simplified mobile settings tab - optimized for TV remote control
class MobileSettingsTab extends ConsumerStatefulWidget { class MobileSettingsTab extends ConsumerStatefulWidget {
@@ -105,7 +106,7 @@ class _MobileSettingsTabState extends ConsumerState<MobileSettingsTab> {
), ),
), ),
Text( Text(
'Version 1.5.1', 'Version 1.6.1',
style: GoogleFonts.inter( style: GoogleFonts.inter(
fontSize: 13, fontSize: 13,
color: AppDecorations.textSecondary(context), color: AppDecorations.textSecondary(context),
@@ -327,7 +328,7 @@ class _MobileSettingsTabState extends ConsumerState<MobileSettingsTab> {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
const SnackBar( const SnackBar(
content: Text('Cache actualisé ! Relancez l\'app pour recharger.'), content: Text('Cache actualisé ! Relancez l\'app pour recharger.'),
backgroundColor: Colors.green, backgroundColor: AppColors.success,
duration: Duration(seconds: 3), duration: Duration(seconds: 3),
), ),
); );
@@ -335,7 +336,7 @@ class _MobileSettingsTabState extends ConsumerState<MobileSettingsTab> {
} catch (e) { } catch (e) {
if (mounted) { if (mounted) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text('Erreur: $e'), backgroundColor: Colors.red), SnackBar(content: Text('Erreur: $e'), backgroundColor: AppColors.error),
); );
} }
} finally { } finally {
@@ -415,7 +416,7 @@ class _MobileSettingsTabState extends ConsumerState<MobileSettingsTab> {
icon, icon,
size: 16, size: 16,
color: selected color: selected
? Colors.white ? AppColors.onSurface
: AppDecorations.textSecondary(context), : AppDecorations.textSecondary(context),
), ),
const SizedBox(height: 3), const SizedBox(height: 3),
@@ -427,7 +428,7 @@ class _MobileSettingsTabState extends ConsumerState<MobileSettingsTab> {
? FontWeight.w700 ? FontWeight.w700
: FontWeight.w500, : FontWeight.w500,
color: selected color: selected
? Colors.white ? AppColors.onSurface
: AppDecorations.textSecondary(context), : AppDecorations.textSecondary(context),
), ),
), ),
+2 -1
View File
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:xtremobile/core/theme/app_decorations.dart'; import 'package:xtremobile/core/theme/app_decorations.dart';
import 'package:xtremobile/mobile/widgets/tv_focusable.dart'; import 'package:xtremobile/mobile/widgets/tv_focusable.dart';
import 'package:xtremobile/core/theme/app_colors.dart';
class MobileCategoryCard extends StatelessWidget { class MobileCategoryCard extends StatelessWidget {
final String title; final String title;
@@ -13,7 +14,7 @@ class MobileCategoryCard extends StatelessWidget {
required this.title, required this.title,
required this.onTap, required this.onTap,
this.icon = Icons.folder_rounded, this.icon = Icons.folder_rounded,
this.iconColor = const Color(0xFF0A84FF), this.iconColor = AppColors.primary,
}); });
@override @override
+5 -4
View File
@@ -3,6 +3,7 @@ import 'package:cached_network_image/cached_network_image.dart';
import 'package:xtremobile/core/theme/app_decorations.dart'; import 'package:xtremobile/core/theme/app_decorations.dart';
import 'package:xtremobile/mobile/widgets/tv_focusable.dart'; import 'package:xtremobile/mobile/widgets/tv_focusable.dart';
import 'package:xtremobile/core/utils/image_cache_config.dart'; import 'package:xtremobile/core/utils/image_cache_config.dart';
import 'package:xtremobile/core/theme/app_colors.dart';
class MobilePosterCard extends StatelessWidget { class MobilePosterCard extends StatelessWidget {
final String title; final String title;
@@ -134,12 +135,12 @@ class MobilePosterCard extends StatelessWidget {
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
const Icon(Icons.star, color: Colors.amber, size: 10), const Icon(Icons.star, color: AppColors.ratingGold, size: 10),
const SizedBox(width: 2), const SizedBox(width: 2),
Text( Text(
rating!, rating!,
style: const TextStyle( style: const TextStyle(
color: Colors.white, color: AppColors.onSurface,
fontSize: 10, fontSize: 10,
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
@@ -157,13 +158,13 @@ class MobilePosterCard extends StatelessWidget {
child: Container( child: Container(
padding: const EdgeInsets.all(4), padding: const EdgeInsets.all(4),
decoration: const BoxDecoration( decoration: const BoxDecoration(
color: Color(0xFF30D158), color: AppColors.success,
shape: BoxShape.circle, shape: BoxShape.circle,
), ),
child: const Icon( child: const Icon(
Icons.check, Icons.check,
size: 10, size: 10,
color: Colors.white, color: AppColors.onSurface,
), ),
), ),
); );
+5 -4
View File
@@ -4,6 +4,7 @@ import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:intl/intl.dart'; import 'package:intl/intl.dart';
import '../../core/theme/app_decorations.dart'; import '../../core/theme/app_decorations.dart';
import 'package:xtremobile/core/theme/app_colors.dart';
class MobileScaffold extends ConsumerStatefulWidget { class MobileScaffold extends ConsumerStatefulWidget {
final Widget child; final Widget child;
@@ -71,7 +72,7 @@ class _MobileScaffoldState extends ConsumerState<MobileScaffold> {
fit: BoxFit.contain, fit: BoxFit.contain,
errorBuilder: (_, __, ___) => const Icon( errorBuilder: (_, __, ___) => const Icon(
Icons.play_circle_filled, Icons.play_circle_filled,
color: Colors.white, color: AppColors.onSurface,
size: 40, size: 40,
), ),
), ),
@@ -201,12 +202,12 @@ class _AppleTVNavItemState extends State<_AppleTVNavItem> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
const Color selectedColor = Color(0xFF0A84FF); const Color selectedColor = AppColors.primaryFill;
final Color unselectedColor = AppDecorations.textSecondary(context); final Color unselectedColor = AppDecorations.textSecondary(context);
final Color textColor = final Color textColor =
widget.isSelected ? Colors.white : unselectedColor; widget.isSelected ? AppColors.onSurface : unselectedColor;
final Color iconColor = final Color iconColor =
widget.isSelected ? Colors.white : unselectedColor; widget.isSelected ? AppColors.onSurface : unselectedColor;
final FontWeight fontWeight = final FontWeight fontWeight =
widget.isSelected ? FontWeight.w700 : FontWeight.w500; widget.isSelected ? FontWeight.w700 : FontWeight.w500;
+3 -2
View File
@@ -1,6 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:xtremobile/core/theme/app_colors.dart';
class TVFocusable extends StatefulWidget { class TVFocusable extends StatefulWidget {
final Widget child; final Widget child;
@@ -25,7 +26,7 @@ class TVFocusable extends StatefulWidget {
this.autofocus = false, this.autofocus = false,
this.scale = 1.05, // Apple TV subtle lift this.scale = 1.05, // Apple TV subtle lift
this.borderWidth = 2.0, this.borderWidth = 2.0,
this.focusColor = Colors.white, this.focusColor = AppColors.onSurface,
this.borderRadius, this.borderRadius,
this.longPressDuration = const Duration(seconds: 3), this.longPressDuration = const Duration(seconds: 3),
}); });
@@ -162,7 +163,7 @@ class _TVFocusableState extends State<TVFocusable> {
offset: const Offset(0, 6), offset: const Offset(0, 6),
), ),
const BoxShadow( const BoxShadow(
color: Color(0x40FFFFFF), // White glow color: Color(0x59D9541F), // Ember glow
blurRadius: 12, blurRadius: 12,
spreadRadius: 0, spreadRadius: 0,
), ),
+1 -1
View File
@@ -1,7 +1,7 @@
name: xtremobile name: xtremobile
description: High-performance IPTV Android Application with Xtream Codes API description: High-performance IPTV Android Application with Xtream Codes API
publish_to: 'none' publish_to: 'none'
version: 1.6.0+12 version: 1.6.1+13
environment: environment:
sdk: '>=3.0.0 <4.0.0' sdk: '>=3.0.0 <4.0.0'
+15
View File
@@ -25,6 +25,21 @@
- [x] `mobile_theme.dart` : dérive désormais de `AppTheme` (échelle typo mobile) - [x] `mobile_theme.dart` : dérive désormais de `AppTheme` (échelle typo mobile)
au lieu de dupliquer 390 lignes au lieu de dupliquer 390 lignes
- [x] `app_decorations.dart` : hexs Apple codés en dur remplacés par la palette - [x] `app_decorations.dart` : hexs Apple codés en dur remplacés par la palette
- [x] **Passe 2 (v1.6.1)** — le thème ne suffisait pas : du bleu restait codé en
dur dans 19 fichiers d'écran/widget, hors palette. Balayage complet :
- `0xFF0A84FF` (bleu Apple) dans la **pilule de navigation sélectionnée**
(`mobile_scaffold`), les icônes de catégorie et le bouton « ajouter »
- `0xFF4FC3F7` / `0xFF1565C0` (bleus) dans les overlays du lecteur
- `Colors.blueAccent` / `Colors.blue` dans les boîtes de dialogue
- gris Apple `1C1C1E` / `2C2C2E` / `3A3A3C` / `8E8E93` → charbons chauds
- `Colors.white*` (128 occurrences) → paliers crème `onSurfaceNN`
- `Colors.red/green/amber/yellow/grey*` → `error` / `success` /
`ratingGold` / `outlineVariant`
- noir pur sur remplissage clair → encre chaude `onPrimaryFixed`
- halo de focus blanc → halo ember
- Conservés en noir vrai : fonds de surface vidéo et voiles (`scrims`)
- Vérification : plus **aucune** couleur Material/Apple codée en dur hors
de `lib/core/theme/`
## 3. Lecture — arrêt en arrière-plan et tenue dans la durée ## 3. Lecture — arrêt en arrière-plan et tenue dans la durée