feat: add RecordingsTab widget and local settings configuration file

This commit is contained in:
Michael committed 2026-04-01 20:41:27 +02:00
1 parent 1e6d3741d1
commit 0049a7c596
1 file changed
+39 -2
+39 -2
View File
@@ -7,6 +7,7 @@ import '../../../core/models/iptv_models.dart';
import '../../../core/models/playlist_config.dart'; import '../../../core/models/playlist_config.dart';
import '../providers/xtream_provider.dart'; import '../providers/xtream_provider.dart';
import '../providers/settings_provider.dart'; import '../providers/settings_provider.dart';
import '../screens/player_screen.dart';
// ═══════════════════════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════════════════════
// ENTRÉE — Onglet "Enregistrements" // ENTRÉE — Onglet "Enregistrements"
@@ -49,7 +50,7 @@ class _RecordingsTabState extends State<RecordingsTab> {
), ),
), ),
Expanded( Expanded(
child: const _RecordingsListView(), child: _RecordingsListView(playlist: widget.playlist),
), ),
], ],
); );
@@ -721,7 +722,8 @@ class _ProgrammeCard extends StatelessWidget {
// ═══════════════════════════════════════════════════════════════════════════ // ═══════════════════════════════════════════════════════════════════════════
class _RecordingsListView extends StatefulWidget { class _RecordingsListView extends StatefulWidget {
const _RecordingsListView(); final PlaylistConfig playlist;
const _RecordingsListView({required this.playlist});
@override @override
State<_RecordingsListView> createState() => _RecordingsListViewState(); State<_RecordingsListView> createState() => _RecordingsListViewState();
} }
@@ -777,6 +779,31 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
_fetchRecordings(); _fetchRecordings();
} }
Future<void> _playRecording(BuildContext context, Map<String, dynamic> rec) async {
final streamUrl = rec['stream_url'] as String? ?? '';
final title = rec['title'] as String? ?? 'Enregistrement';
if (streamUrl.isEmpty) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('URL du flux indisponible')),
);
return;
}
if (!mounted) return;
Navigator.of(context).push(
MaterialPageRoute(
builder: (ctx) => PlayerScreen(
streamId: streamUrl,
title: title,
playlist: widget.playlist,
streamType: StreamType.vod,
containerExtension: 'ts',
),
),
);
}
Future<void> _showLogs(String id, String title) async { Future<void> _showLogs(String id, String title) async {
try { try {
final response = await http.get(Uri.parse('/api/recordings/logs/$id')); final response = await http.get(Uri.parse('/api/recordings/logs/$id'));
@@ -989,6 +1016,16 @@ class _RecordingsListViewState extends State<_RecordingsListView> {
rec['title'] ?? '', rec['title'] ?? '',
), ),
), ),
if (status == 'completed')
IconButton(
icon: const Icon(
Icons.play_circle_outline,
color: Colors.greenAccent,
size: 20,
),
tooltip: 'Lecture',
onPressed: () => _playRecording(context, rec),
),
IconButton( IconButton(
icon: const Icon( icon: const Icon(
Icons.description_outlined, Icons.description_outlined,