mirror of
https://github.com/R0m1k3/xtremflow.git
synced 2026-10-22 06:28:04 +02:00
feat(theme): complete redesign to Cyber-Cinematic Glass (Stitch)
Replace the legacy Apple TV-style purple/cyan theme with the full Google Stitch Cyber-Cinematic Glass design system across the entire app (desktop + mobile). - New Material 3 dark ColorScheme: background #121317, primary #adc6ff, primaryContainer #4b8eff, surface containers, etc. - Typography: Space Grotesk (headlines) + Inter (body/labels) - 3-level glassmorphism via GlassContainer: base, glass, floating - Primary gradient: #007AFF → #00C6FF with blue glow effects - Removed old compatibility aliases (focusColor, border, textPrimary, textSecondary); all code now uses semantic Stitch tokens - Systematically replaced all Colors.white/black/red/grey and GoogleFonts.roboto/outfit with Stitch equivalents - All 36 lib/ files updated, zero compilation errors Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
1 parent
a9a1127d6b
commit
f7eaa724e2
36 files changed
+1651
-986
No files matched your search
@@ -5,6 +5,7 @@ import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import '../../../core/models/iptv_models.dart';
|
||||
import '../../../core/models/playlist_config.dart';
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../core/widgets/glass_container.dart';
|
||||
import '../providers/xtream_provider.dart';
|
||||
import '../providers/settings_provider.dart';
|
||||
@@ -49,24 +50,24 @@ class _RecordingsTabState extends State<RecordingsTab>
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(children: [
|
||||
const Icon(Icons.tv, color: Colors.white, size: 28),
|
||||
const Icon(Icons.tv, color: AppColors.onSurface, size: 28),
|
||||
const SizedBox(width: 12),
|
||||
Text('TV & Enregistrements',
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.inter(
|
||||
fontSize: 26,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white)),
|
||||
color: AppColors.onSurface)),
|
||||
]),
|
||||
const SizedBox(height: 16),
|
||||
TabBar(
|
||||
controller: _tabController,
|
||||
labelColor: Colors.white,
|
||||
unselectedLabelColor: Colors.white54,
|
||||
indicatorColor: Colors.redAccent,
|
||||
labelColor: AppColors.onSurface,
|
||||
unselectedLabelColor: AppColors.onSurfaceVariant,
|
||||
indicatorColor: AppColors.live,
|
||||
indicatorWeight: 3,
|
||||
labelStyle: GoogleFonts.outfit(
|
||||
labelStyle: GoogleFonts.inter(
|
||||
fontWeight: FontWeight.w600, fontSize: 14),
|
||||
unselectedLabelStyle: GoogleFonts.outfit(fontSize: 14),
|
||||
unselectedLabelStyle: GoogleFonts.inter(fontSize: 14),
|
||||
tabs: const [
|
||||
Tab(icon: Icon(Icons.grid_view, size: 18), text: 'Guide TV'),
|
||||
Tab(
|
||||
@@ -218,8 +219,8 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
child: Column(
|
||||
children: [
|
||||
Text('GROUPES',
|
||||
style: GoogleFonts.outfit(
|
||||
color: Colors.white38,
|
||||
style: GoogleFonts.inter(
|
||||
color: AppColors.outline,
|
||||
fontSize: 10,
|
||||
fontWeight: FontWeight.bold,
|
||||
letterSpacing: 1.2)),
|
||||
@@ -242,16 +243,16 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
margin: const EdgeInsets.only(bottom: 4),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? Colors.white.withOpacity(0.1)
|
||||
? AppColors.outlineVariant
|
||||
: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
),
|
||||
child: Text(
|
||||
cat,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.inter(
|
||||
color: isSelected
|
||||
? Colors.white
|
||||
: Colors.white60,
|
||||
? AppColors.onSurface
|
||||
: AppColors.onSurfaceVariant,
|
||||
fontSize: 12,
|
||||
fontWeight: isSelected
|
||||
? FontWeight.bold
|
||||
@@ -268,7 +269,7 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
),
|
||||
),
|
||||
|
||||
const VerticalDivider(width: 32, color: Colors.white10),
|
||||
const VerticalDivider(width: 32, color: AppColors.outlineVariant),
|
||||
|
||||
// ── Colonne 2 : CHAÎNES ──
|
||||
SizedBox(
|
||||
@@ -277,15 +278,15 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
// Barre de recherche
|
||||
TextField(
|
||||
controller: _searchCtrl,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 13),
|
||||
style: const TextStyle(color: AppColors.onSurface, fontSize: 13),
|
||||
decoration: InputDecoration(
|
||||
hintText: 'Rechercher...',
|
||||
hintStyle:
|
||||
const TextStyle(color: Colors.white38, fontSize: 13),
|
||||
const TextStyle(color: AppColors.outline, fontSize: 13),
|
||||
prefixIcon: const Icon(Icons.search,
|
||||
color: Colors.white38, size: 18),
|
||||
color: AppColors.outline, size: 18),
|
||||
filled: true,
|
||||
fillColor: Colors.white.withOpacity(0.07),
|
||||
fillColor: AppColors.surfaceContainer,
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 8),
|
||||
border: OutlineInputBorder(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
@@ -299,7 +300,7 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
? Center(
|
||||
child: Text('Aucune chaîne',
|
||||
style: TextStyle(
|
||||
color: Colors.white24, fontSize: 12)))
|
||||
color: AppColors.outline, fontSize: 12)))
|
||||
: ListView.builder(
|
||||
itemCount: visibleChannels.length,
|
||||
itemBuilder: (ctx, i) {
|
||||
@@ -315,12 +316,12 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
horizontal: 10, vertical: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: isSelected
|
||||
? Colors.redAccent.withOpacity(0.2)
|
||||
: Colors.white.withOpacity(0.05),
|
||||
? AppColors.live.withOpacity(0.2)
|
||||
: AppColors.surfaceContainerLow,
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
border: Border.all(
|
||||
color: isSelected
|
||||
? Colors.redAccent.withOpacity(0.5)
|
||||
? AppColors.live.withOpacity(0.5)
|
||||
: Colors.transparent,
|
||||
),
|
||||
),
|
||||
@@ -332,18 +333,18 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
fit: BoxFit.contain,
|
||||
errorBuilder: (_, __, ___) =>
|
||||
const Icon(Icons.tv,
|
||||
color: Colors.white24,
|
||||
color: AppColors.outline,
|
||||
size: 16))
|
||||
: const Icon(Icons.tv,
|
||||
color: Colors.white24, size: 16),
|
||||
color: AppColors.outline, size: 16),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(
|
||||
child: Text(
|
||||
ch.name,
|
||||
style: GoogleFonts.outfit(
|
||||
style: GoogleFonts.inter(
|
||||
color: isSelected
|
||||
? Colors.white
|
||||
: Colors.white70,
|
||||
? AppColors.onSurface
|
||||
: AppColors.onSurfaceVariant,
|
||||
fontSize: 12,
|
||||
),
|
||||
maxLines: 1,
|
||||
@@ -359,7 +360,7 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
]),
|
||||
),
|
||||
|
||||
const VerticalDivider(width: 32, color: Colors.white10),
|
||||
const VerticalDivider(width: 32, color: AppColors.outlineVariant),
|
||||
|
||||
// ── Colonne droite : programmes EPG ──
|
||||
Expanded(
|
||||
@@ -368,14 +369,14 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.tv_off,
|
||||
size: 64, color: Color(0x1FFFFFFF)),
|
||||
Icon(Icons.tv_off,
|
||||
size: 64, color: AppColors.outline.withOpacity(0.1)),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
'Sélectionnez une chaîne\npour voir son guide des programmes',
|
||||
textAlign: TextAlign.center,
|
||||
style: GoogleFonts.outfit(
|
||||
color: Colors.white38, fontSize: 15),
|
||||
style: GoogleFonts.inter(
|
||||
color: AppColors.outline, fontSize: 15),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -386,8 +387,8 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
Row(children: [
|
||||
Text(
|
||||
_selectedChannel!.name,
|
||||
style: GoogleFonts.outfit(
|
||||
color: Colors.white,
|
||||
style: GoogleFonts.inter(
|
||||
color: AppColors.onSurface,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16,
|
||||
),
|
||||
@@ -395,12 +396,12 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
const Spacer(),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh,
|
||||
color: Colors.white54, size: 18),
|
||||
color: AppColors.onSurfaceVariant, size: 18),
|
||||
tooltip: 'Recharger l\'EPG',
|
||||
onPressed: () => _loadEpg(_selectedChannel!),
|
||||
),
|
||||
]),
|
||||
const Divider(color: Colors.white12),
|
||||
const Divider(color: AppColors.outlineVariant),
|
||||
Expanded(
|
||||
child: _loadingEpg
|
||||
? const Center(
|
||||
@@ -410,7 +411,7 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
child: Text(
|
||||
'Erreur EPG: $_epgError',
|
||||
style: const TextStyle(
|
||||
color: Colors.redAccent,
|
||||
color: AppColors.live,
|
||||
fontSize: 12),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
@@ -420,8 +421,8 @@ class _EpgGuideViewState extends ConsumerState<_EpgGuideView>
|
||||
child: Text(
|
||||
'Aucun programme EPG disponible\npour cette chaîne',
|
||||
textAlign: TextAlign.center,
|
||||
style: GoogleFonts.outfit(
|
||||
color: Colors.white38),
|
||||
style: GoogleFonts.inter(
|
||||
color: AppColors.outline),
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
@@ -503,28 +504,28 @@ class _ProgrammeCard extends StatelessWidget {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
backgroundColor: const Color(0xFF1E1E2E),
|
||||
backgroundColor: AppColors.surfaceContainerHigh,
|
||||
title: Row(children: [
|
||||
const Icon(Icons.fiber_manual_record,
|
||||
color: Colors.redAccent, size: 20),
|
||||
color: AppColors.live, size: 20),
|
||||
const SizedBox(width: 8),
|
||||
Expanded(
|
||||
child: Text('Enregistrer',
|
||||
style: GoogleFonts.outfit(color: Colors.white))),
|
||||
style: GoogleFonts.inter(color: AppColors.onSurface))),
|
||||
]),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(title.isEmpty ? channel.name : title,
|
||||
style: GoogleFonts.outfit(
|
||||
color: Colors.white,
|
||||
style: GoogleFonts.inter(
|
||||
color: AppColors.onSurface,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 16)),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'${_fmt(_start)} → ${_fmt(_end)}',
|
||||
style: const TextStyle(color: Colors.white70),
|
||||
style: const TextStyle(color: AppColors.onSurfaceVariant),
|
||||
),
|
||||
if (_description.isNotEmpty) ...[
|
||||
const SizedBox(height: 8),
|
||||
@@ -532,7 +533,7 @@ class _ProgrammeCard extends StatelessWidget {
|
||||
_description,
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(color: Colors.white38, fontSize: 12),
|
||||
style: const TextStyle(color: AppColors.outline, fontSize: 12),
|
||||
),
|
||||
],
|
||||
],
|
||||
@@ -542,7 +543,7 @@ class _ProgrammeCard extends StatelessWidget {
|
||||
onPressed: () => Navigator.pop(ctx),
|
||||
child: const Text('Annuler')),
|
||||
ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(backgroundColor: Colors.redAccent),
|
||||
style: ElevatedButton.styleFrom(backgroundColor: AppColors.live),
|
||||
onPressed: () async {
|
||||
Navigator.pop(ctx);
|
||||
await _saveRecording(
|
||||
@@ -575,8 +576,8 @@ class _ProgrammeCard extends StatelessWidget {
|
||||
? '✅ "$title" planifié !'
|
||||
: '❌ Erreur: ${response.body}'),
|
||||
backgroundColor: response.statusCode == 200
|
||||
? Colors.green.shade800
|
||||
: Colors.red.shade800,
|
||||
? AppColors.success
|
||||
: AppColors.error,
|
||||
));
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -596,15 +597,15 @@ class _ProgrammeCard extends StatelessWidget {
|
||||
margin: const EdgeInsets.only(bottom: 6),
|
||||
decoration: BoxDecoration(
|
||||
color: isNow
|
||||
? Colors.red.withOpacity(0.15)
|
||||
? AppColors.live.withOpacity(0.15)
|
||||
: isPast
|
||||
? Colors.white.withOpacity(0.03)
|
||||
: Colors.white.withOpacity(0.06),
|
||||
? AppColors.surfaceContainerLowest
|
||||
: AppColors.surfaceContainerLow,
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(
|
||||
color: isNow
|
||||
? Colors.redAccent.withOpacity(0.4)
|
||||
: Colors.white.withOpacity(0.07),
|
||||
? AppColors.live.withOpacity(0.4)
|
||||
: AppColors.surfaceContainer,
|
||||
),
|
||||
),
|
||||
child: ListTile(
|
||||
@@ -619,19 +620,19 @@ class _ProgrammeCard extends StatelessWidget {
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 5, vertical: 2),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.redAccent,
|
||||
color: AppColors.live,
|
||||
borderRadius: BorderRadius.circular(4)),
|
||||
child: Text('LIVE',
|
||||
style: GoogleFonts.outfit(
|
||||
color: Colors.white,
|
||||
style: GoogleFonts.inter(
|
||||
color: AppColors.onSurface,
|
||||
fontSize: 8,
|
||||
fontWeight: FontWeight.bold)),
|
||||
)
|
||||
else
|
||||
Text(
|
||||
_fmt(_start),
|
||||
style: GoogleFonts.outfit(
|
||||
color: isPast ? Colors.white24 : Colors.white70,
|
||||
style: GoogleFonts.inter(
|
||||
color: isPast ? AppColors.outline : AppColors.onSurfaceVariant,
|
||||
fontSize: 13,
|
||||
fontWeight: FontWeight.w600,
|
||||
),
|
||||
@@ -640,15 +641,15 @@ class _ProgrammeCard extends StatelessWidget {
|
||||
Text(
|
||||
_fmt(_end),
|
||||
style:
|
||||
GoogleFonts.outfit(color: Colors.white24, fontSize: 10),
|
||||
GoogleFonts.inter(color: AppColors.outline, fontSize: 10),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
title: Text(
|
||||
_title.isEmpty ? '—' : _title,
|
||||
style: GoogleFonts.outfit(
|
||||
color: isPast ? Colors.white38 : Colors.white,
|
||||
style: GoogleFonts.inter(
|
||||
color: isPast ? AppColors.outline : AppColors.onSurface,
|
||||
fontWeight: isNow ? FontWeight.bold : FontWeight.normal,
|
||||
),
|
||||
maxLines: 2,
|
||||
@@ -659,13 +660,13 @@ class _ProgrammeCard extends StatelessWidget {
|
||||
_description,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: const TextStyle(color: Colors.white38, fontSize: 11),
|
||||
style: const TextStyle(color: AppColors.outline, fontSize: 11),
|
||||
)
|
||||
: null,
|
||||
trailing: !isPast
|
||||
? IconButton(
|
||||
icon: const Icon(Icons.fiber_manual_record,
|
||||
color: Colors.redAccent, size: 20),
|
||||
color: AppColors.live, size: 20),
|
||||
tooltip: 'Enregistrer ce programme',
|
||||
onPressed: () => _record(context),
|
||||
)
|
||||
@@ -746,16 +747,16 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
backgroundColor: const Color(0xFF1E1E2E),
|
||||
backgroundColor: AppColors.surfaceContainerHigh,
|
||||
title: Text(title,
|
||||
style: GoogleFonts.outfit(color: Colors.white, fontSize: 14)),
|
||||
style: GoogleFonts.inter(color: AppColors.onSurface, fontSize: 14)),
|
||||
content: SizedBox(
|
||||
width: 500,
|
||||
height: 300,
|
||||
child: SingleChildScrollView(
|
||||
child: Text(content,
|
||||
style: const TextStyle(
|
||||
color: Colors.white70,
|
||||
color: AppColors.onSurfaceVariant,
|
||||
fontSize: 11,
|
||||
fontFamily: 'monospace')),
|
||||
),
|
||||
@@ -776,10 +777,10 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
|
||||
}
|
||||
|
||||
Color _statusColor(String status) => switch (status) {
|
||||
'recording' => Colors.redAccent,
|
||||
'completed' => Colors.green,
|
||||
'failed' => Colors.orangeAccent,
|
||||
_ => Colors.blueAccent,
|
||||
'recording' => AppColors.live,
|
||||
'completed' => AppColors.success,
|
||||
'failed' => AppColors.warning,
|
||||
_ => AppColors.primaryContainer,
|
||||
};
|
||||
|
||||
String _statusLabel(String status) => switch (status) {
|
||||
@@ -809,7 +810,7 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
|
||||
children: [
|
||||
Row(mainAxisAlignment: MainAxisAlignment.end, children: [
|
||||
IconButton(
|
||||
icon: const Icon(Icons.refresh, color: Colors.white70),
|
||||
icon: const Icon(Icons.refresh, color: AppColors.onSurfaceVariant),
|
||||
onPressed: _fetchRecordings,
|
||||
tooltip: 'Rafraîchir',
|
||||
),
|
||||
@@ -820,18 +821,18 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
|
||||
: _error != null
|
||||
? Center(
|
||||
child: Text(_error!,
|
||||
style: const TextStyle(color: Colors.redAccent)))
|
||||
style: const TextStyle(color: AppColors.live)))
|
||||
: _recordings.isEmpty
|
||||
? Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.videocam_off,
|
||||
size: 64, color: Color(0x1FFFFFFF)),
|
||||
Icon(Icons.videocam_off,
|
||||
size: 64, color: AppColors.outline.withOpacity(0.1)),
|
||||
const SizedBox(height: 16),
|
||||
Text('Aucun enregistrement',
|
||||
style: GoogleFonts.outfit(
|
||||
color: Colors.white38, fontSize: 16)),
|
||||
style: GoogleFonts.inter(
|
||||
color: AppColors.outline, fontSize: 16)),
|
||||
],
|
||||
),
|
||||
)
|
||||
@@ -845,10 +846,10 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.05),
|
||||
color: AppColors.surfaceContainerLow,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: Colors.white.withOpacity(0.1)),
|
||||
color: AppColors.outlineVariant),
|
||||
),
|
||||
child: ListTile(
|
||||
contentPadding: const EdgeInsets.symmetric(
|
||||
@@ -861,8 +862,8 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
|
||||
size: 28,
|
||||
),
|
||||
title: Text(rec['title'] ?? '—',
|
||||
style: GoogleFonts.outfit(
|
||||
color: Colors.white,
|
||||
style: GoogleFonts.inter(
|
||||
color: AppColors.onSurface,
|
||||
fontWeight: FontWeight.w600)),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment:
|
||||
@@ -871,13 +872,13 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
|
||||
Text(
|
||||
'${_fmtDate(rec['start_time'])} → ${_fmtDate(rec['end_time'])}',
|
||||
style: const TextStyle(
|
||||
color: Colors.white54,
|
||||
color: AppColors.onSurfaceVariant,
|
||||
fontSize: 12),
|
||||
),
|
||||
if (rec['error_reason'] != null)
|
||||
Text('⚠ ${rec['error_reason']}',
|
||||
style: const TextStyle(
|
||||
color: Colors.orangeAccent,
|
||||
color: AppColors.warning,
|
||||
fontSize: 11)),
|
||||
],
|
||||
),
|
||||
@@ -904,7 +905,7 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
|
||||
if (status == 'recording')
|
||||
IconButton(
|
||||
icon: const Icon(Icons.stop_circle,
|
||||
color: Colors.redAccent),
|
||||
color: AppColors.live),
|
||||
tooltip: 'Arrêter',
|
||||
onPressed: () => _stopRecording(
|
||||
rec['id'], rec['title'] ?? ''),
|
||||
@@ -912,7 +913,7 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
|
||||
IconButton(
|
||||
icon: const Icon(
|
||||
Icons.description_outlined,
|
||||
color: Colors.blueAccent,
|
||||
color: AppColors.primaryContainer,
|
||||
size: 20),
|
||||
tooltip: 'Logs',
|
||||
onPressed: () => _showLogs(
|
||||
@@ -920,7 +921,7 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
|
||||
),
|
||||
IconButton(
|
||||
icon: const Icon(Icons.delete_outline,
|
||||
color: Colors.white38, size: 20),
|
||||
color: AppColors.outline, size: 20),
|
||||
tooltip: 'Supprimer',
|
||||
onPressed: () =>
|
||||
_deleteRecording(rec['id']),
|
||||
@@ -991,19 +992,19 @@ class _SeasonPassesViewState extends State<_SeasonPassesView> {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (ctx) => AlertDialog(
|
||||
backgroundColor: const Color(0xFF1E1E2E),
|
||||
backgroundColor: AppColors.surfaceContainerHigh,
|
||||
title: Row(children: [
|
||||
const Icon(Icons.repeat, color: Colors.purpleAccent),
|
||||
const Icon(Icons.repeat, color: AppColors.primary),
|
||||
const SizedBox(width: 8),
|
||||
Text('Nouveau Season Pass',
|
||||
style: GoogleFonts.outfit(color: Colors.white)),
|
||||
style: GoogleFonts.inter(color: AppColors.onSurface)),
|
||||
]),
|
||||
content: SizedBox(
|
||||
width: 400,
|
||||
child: Column(mainAxisSize: MainAxisSize.min, children: [
|
||||
Text(
|
||||
'Enregistre automatiquement toutes les nouvelles diffusions d\'une émission.',
|
||||
style: GoogleFonts.outfit(color: Colors.white54, fontSize: 13),
|
||||
style: GoogleFonts.inter(color: AppColors.onSurfaceVariant, fontSize: 13),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
_buildField(
|
||||
@@ -1021,7 +1022,7 @@ class _SeasonPassesViewState extends State<_SeasonPassesView> {
|
||||
child: const Text('Annuler')),
|
||||
ElevatedButton(
|
||||
style:
|
||||
ElevatedButton.styleFrom(backgroundColor: Colors.purpleAccent),
|
||||
ElevatedButton.styleFrom(backgroundColor: AppColors.primary),
|
||||
onPressed: () async {
|
||||
final t = titleCtrl.text.trim();
|
||||
final c = channelCtrl.text.trim();
|
||||
@@ -1055,14 +1056,14 @@ class _SeasonPassesViewState extends State<_SeasonPassesView> {
|
||||
Widget _buildField(TextEditingController c, String label) {
|
||||
return TextField(
|
||||
controller: c,
|
||||
style: const TextStyle(color: Colors.white),
|
||||
style: const TextStyle(color: AppColors.onSurface),
|
||||
decoration: InputDecoration(
|
||||
labelText: label,
|
||||
labelStyle: const TextStyle(color: Colors.white54, fontSize: 12),
|
||||
labelStyle: const TextStyle(color: AppColors.onSurfaceVariant, fontSize: 12),
|
||||
enabledBorder: const UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.white24)),
|
||||
borderSide: BorderSide(color: AppColors.outline)),
|
||||
focusedBorder: const UnderlineInputBorder(
|
||||
borderSide: BorderSide(color: Colors.purpleAccent)),
|
||||
borderSide: BorderSide(color: AppColors.primary)),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -1076,10 +1077,10 @@ class _SeasonPassesViewState extends State<_SeasonPassesView> {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text('Enregistrements automatiques',
|
||||
style: GoogleFonts.outfit(color: Colors.white54, fontSize: 13)),
|
||||
style: GoogleFonts.inter(color: AppColors.onSurfaceVariant, fontSize: 13)),
|
||||
ElevatedButton.icon(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.purpleAccent),
|
||||
backgroundColor: AppColors.primary),
|
||||
icon: const Icon(Icons.add, size: 18),
|
||||
label: const Text('Nouveau'),
|
||||
onPressed: _showCreate,
|
||||
@@ -1090,19 +1091,19 @@ class _SeasonPassesViewState extends State<_SeasonPassesView> {
|
||||
Container(
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.purpleAccent.withOpacity(0.08),
|
||||
color: AppColors.primary.withOpacity(0.08),
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
border: Border.all(color: Colors.purpleAccent.withOpacity(0.2)),
|
||||
border: Border.all(color: AppColors.primary.withOpacity(0.2)),
|
||||
),
|
||||
child: Row(children: [
|
||||
const Icon(Icons.info_outline,
|
||||
color: Colors.purpleAccent, size: 18),
|
||||
color: AppColors.primary, size: 18),
|
||||
const SizedBox(width: 12),
|
||||
Expanded(
|
||||
child: Text(
|
||||
'Scanne l\'EPG toutes les 4h et programme automatiquement les nouvelles diffusions. Seuls les nouveaux épisodes sont enregistrés.',
|
||||
style: GoogleFonts.outfit(
|
||||
color: Colors.purpleAccent.shade100, fontSize: 12),
|
||||
style: GoogleFonts.inter(
|
||||
color: AppColors.primaryFixedDim, fontSize: 12),
|
||||
),
|
||||
),
|
||||
]),
|
||||
@@ -1116,17 +1117,17 @@ class _SeasonPassesViewState extends State<_SeasonPassesView> {
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Icon(Icons.repeat,
|
||||
size: 64, color: Color(0x1FFFFFFF)),
|
||||
Icon(Icons.repeat,
|
||||
size: 64, color: AppColors.outline.withOpacity(0.1)),
|
||||
const SizedBox(height: 16),
|
||||
Text('Aucun Season Pass actif',
|
||||
style: GoogleFonts.outfit(
|
||||
color: Colors.white38, fontSize: 16)),
|
||||
style: GoogleFonts.inter(
|
||||
color: AppColors.outline, fontSize: 16)),
|
||||
const SizedBox(height: 8),
|
||||
Text(
|
||||
'Créez-en un pour enregistrer automatiquement vos émissions préférées',
|
||||
style: GoogleFonts.outfit(
|
||||
color: Colors.white24, fontSize: 12),
|
||||
style: GoogleFonts.inter(
|
||||
color: AppColors.outline, fontSize: 12),
|
||||
textAlign: TextAlign.center),
|
||||
],
|
||||
),
|
||||
@@ -1138,32 +1139,32 @@ class _SeasonPassesViewState extends State<_SeasonPassesView> {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(bottom: 8),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.purpleAccent.withOpacity(0.08),
|
||||
color: AppColors.primary.withOpacity(0.08),
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
border: Border.all(
|
||||
color: Colors.purpleAccent.withOpacity(0.2)),
|
||||
color: AppColors.primary.withOpacity(0.2)),
|
||||
),
|
||||
child: ListTile(
|
||||
leading: const Icon(Icons.repeat,
|
||||
color: Colors.purpleAccent),
|
||||
color: AppColors.primary),
|
||||
title: Text(p['show_title'] ?? '—',
|
||||
style: GoogleFonts.outfit(
|
||||
color: Colors.white,
|
||||
style: GoogleFonts.inter(
|
||||
color: AppColors.onSurface,
|
||||
fontWeight: FontWeight.w600)),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text('Chaîne : ${p['channel_id']}',
|
||||
style: const TextStyle(
|
||||
color: Colors.white54, fontSize: 11)),
|
||||
color: AppColors.onSurfaceVariant, fontSize: 11)),
|
||||
Text('Flux : ${p['stream_url']}',
|
||||
style: const TextStyle(
|
||||
color: Colors.white38, fontSize: 10)),
|
||||
color: AppColors.outline, fontSize: 10)),
|
||||
],
|
||||
),
|
||||
trailing: IconButton(
|
||||
icon: const Icon(Icons.delete_outline,
|
||||
color: Colors.white38),
|
||||
color: AppColors.outline),
|
||||
tooltip: 'Supprimer',
|
||||
onPressed: () =>
|
||||
_deletePass(p['id'], p['show_title'] ?? ''),
|
||||
|
||||
Reference in new issue
Block a user