mirror of
https://github.com/R0m1k3/xtremflow.git
synced 2026-10-21 14:08:04 +02:00
Rebranche les fonctionnalités codées mais inaccessibles
Onglet Enregistrements : - TabBar à 3 vues : Guide TV (programmer depuis l'EPG), liste des enregistrements, Season Passes. _EpgGuideView et _SeasonPassesView (~800 lignes fonctionnelles) n'étaient plus instanciés depuis une refonte — programmer depuis le guide et les enregistrements récurrents étaient devenus inaccessibles - Confirmation avant suppression d'un enregistrement (la corbeille supprimait immédiatement, sans retour ni annulation) - Erreur de chargement avec bouton Réessayer Favoris : - Bouton cœur sur les tuiles chaînes desktop (overlay) et mobile : toggleFavorite() n'était appelé nulle part, le filtre « Favoris » affichait toujours une liste vide Reprise de lecture : - Films et épisodes lisent playbackPositionsProvider et passent startTime au player : les positions étaient écrites mais jamais relues, tout repartait de zéro - Plus de sauvegarde de position en live (une entrée bidon par chaîne zappée) Mobile : - 5e onglet REC réutilisant RecordingsTab - IndexedStack au lieu du switch : les onglets conservent scroll et catalogues chargés (aligné sur le dashboard desktop) Dashboard : - Menu profil sur l'avatar de la sidebar (nom d'utilisateur + déconnexion) : le bouton était mort, aucune déconnexion possible depuis le dashboard desktop - Erreur de chargement des chaînes avec bouton Réessayer Validé : flutter analyze (202 issues, identique à la baseline main, 0 erreur/warning), flutter test (OK), flutter build web --release (OK). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_015oEu9QayWsw7hCKhenxgVa
This commit is contained in:
10 files changed
+294
-47
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import '../../auth/providers/auth_provider.dart';
|
||||
import '../../../core/models/playlist_config.dart';
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import '../../../core/widgets/glass_container.dart';
|
||||
@@ -200,13 +201,61 @@ class _DashboardScreenState extends ConsumerState<DashboardScreen> {
|
||||
|
||||
const Spacer(),
|
||||
|
||||
// Settings / Profile
|
||||
// Profil : nom d'utilisateur + déconnexion. L'avatar était
|
||||
// un bouton mort (onTap vide) — aucune déconnexion possible
|
||||
// depuis le dashboard desktop.
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 24),
|
||||
child: TvFocusableCard(
|
||||
onTap: () {},
|
||||
borderRadius: 50,
|
||||
scaleFactor: 1.1,
|
||||
child: PopupMenuButton<String>(
|
||||
tooltip: 'Profil',
|
||||
color: AppColors.surfaceContainerHigh,
|
||||
offset: const Offset(56, -12),
|
||||
itemBuilder: (context) => [
|
||||
PopupMenuItem<String>(
|
||||
enabled: false,
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(
|
||||
Icons.person,
|
||||
size: 18,
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
const SizedBox(width: 8),
|
||||
Text(
|
||||
ref.read(authProvider).currentUser?.username ??
|
||||
'Utilisateur',
|
||||
style: const TextStyle(
|
||||
color: AppColors.onSurface,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const PopupMenuDivider(),
|
||||
const PopupMenuItem<String>(
|
||||
value: 'logout',
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.logout,
|
||||
size: 18,
|
||||
color: AppColors.textSecondary,
|
||||
),
|
||||
SizedBox(width: 8),
|
||||
Text(
|
||||
'Déconnexion',
|
||||
style: TextStyle(color: AppColors.onSurface),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
onSelected: (value) {
|
||||
if (value == 'logout') {
|
||||
ref.read(authProvider.notifier).logout();
|
||||
}
|
||||
},
|
||||
child: const CircleAvatar(
|
||||
radius: 20,
|
||||
backgroundColor: AppColors.surfaceContainerHigh,
|
||||
|
||||
@@ -271,8 +271,10 @@ class _PlayerScreenState extends ConsumerState<PlayerScreen> {
|
||||
});
|
||||
}
|
||||
|
||||
// Update watch history if relevant
|
||||
if (currentTime > 0) {
|
||||
// Update watch history if relevant. Jamais en live : la « position »
|
||||
// d'un flux continu n'a pas de sens et polluait le stockage avec une
|
||||
// entrée bidon par chaîne zappée.
|
||||
if (currentTime > 0 && widget.streamType != StreamType.live) {
|
||||
ref.read(playbackPositionsProvider.notifier).savePosition(
|
||||
widget.streamId,
|
||||
currentTime,
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:google_fonts/google_fonts.dart';
|
||||
import '../../../core/models/playlist_config.dart';
|
||||
import '../models/xtream_models.dart';
|
||||
import '../providers/xtream_provider.dart';
|
||||
import '../providers/playback_positions_provider.dart';
|
||||
import '../providers/watch_history_provider.dart';
|
||||
import '../../../core/theme/app_colors.dart';
|
||||
import 'player_screen.dart';
|
||||
@@ -287,7 +288,14 @@ class _SeriesDetailScreenState extends ConsumerState<SeriesDetailScreen> {
|
||||
}
|
||||
|
||||
if (!context.mounted) return;
|
||||
|
||||
|
||||
// Reprise de lecture : le player sauvegarde la position sous
|
||||
// episode.id, on la relit ici pour reprendre où on s'était arrêté.
|
||||
final positions = ref.read(playbackPositionsProvider);
|
||||
final resumeAt = positions.hasPosition(episode.id)
|
||||
? positions.getPosition(episode.id)
|
||||
: null;
|
||||
|
||||
Navigator.push(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
@@ -298,6 +306,7 @@ class _SeriesDetailScreenState extends ConsumerState<SeriesDetailScreen> {
|
||||
streamType: StreamType.series,
|
||||
containerExtension: episode.containerExtension ?? 'mkv',
|
||||
duration: episodeDuration,
|
||||
startTime: resumeAt,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
Reference in new issue
Block a user