chore: Update Docker cache buster version.

This commit is contained in:
Michael committed 2025-12-13 10:37:46 +01:00
1 parent d0dda60f8c
commit 18d2e0a0ee
6 files changed
+408 -147

No files matched your search

@@ -0,0 +1,161 @@
import 'package:flutter/material.dart';
import 'package:video_player/video_player.dart';
import 'package:chewie/chewie.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'dart:async';
import '../../../core/theme/app_colors.dart';
class LitePlayerView extends ConsumerStatefulWidget {
final String streamUrl;
final bool isLive;
final VoidCallback? onNext;
final VoidCallback? onPrevious;
const LitePlayerView({
super.key,
required this.streamUrl,
required this.isLive,
this.onNext,
this.onPrevious,
});
@override
ConsumerState<LitePlayerView> createState() => _LitePlayerViewState();
}
class _LitePlayerViewState extends ConsumerState<LitePlayerView> {
late VideoPlayerController _videoController;
ChewieController? _chewieController;
bool _error = false;
@override
void initState() {
super.initState();
_initializePlayer();
}
@override
void didUpdateWidget(LitePlayerView oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.streamUrl != widget.streamUrl) {
_disposeControllers();
_initializePlayer();
}
}
Future<void> _initializePlayer() async {
try {
setState(() => _error = false);
_videoController = VideoPlayerController.networkUrl(Uri.parse(widget.streamUrl));
await _videoController.initialize();
_chewieController = ChewieController(
videoPlayerController: _videoController,
autoPlay: true,
looping: false,
isLive: widget.isLive,
aspectRatio: _videoController.value.aspectRatio > 0 ? _videoController.value.aspectRatio : 16/9,
colors: ChewieProgressColors(
playedColor: AppColors.primary,
handleColor: Colors.white,
backgroundColor: Colors.white24,
bufferedColor: Colors.white54,
),
// Custom Controls to include Zapping
additionalOptions: (context) {
return <OptionItem>[
if (widget.onNext != null)
OptionItem(
onTap: widget.onNext!,
iconData: Icons.skip_next,
title: 'Next Channel',
),
if (widget.onPrevious != null)
OptionItem(
onTap: widget.onPrevious!,
iconData: Icons.skip_previous,
title: 'Previous Channel',
),
];
},
);
setState(() {});
} catch (e) {
debugPrint('Error initializing Lite Player: $e');
setState(() => _error = true);
}
}
void _disposeControllers() {
_videoController.dispose();
_chewieController?.dispose();
_chewieController = null;
}
@override
void dispose() {
_disposeControllers();
super.dispose();
}
@override
Widget build(BuildContext context) {
if (_error) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Icon(Icons.error_outline, color: Colors.red, size: 48),
const SizedBox(height: 16),
const Text('Error loading video', style: TextStyle(color: Colors.white)),
const SizedBox(height: 16),
ElevatedButton(
onPressed: () {
_disposeControllers();
_initializePlayer();
},
child: const Text('Retry'),
)
],
),
);
}
if (_chewieController != null && _chewieController!.videoPlayerController.value.isInitialized) {
return Stack(
children: [
Chewie(controller: _chewieController!),
// Overlay Zapping Controls for easy access (since Chewie hides controls)
if (widget.onPrevious != null || widget.onNext != null)
Positioned(
bottom: 20,
right: 80,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (widget.onPrevious != null) ...[
IconButton(
onPressed: widget.onPrevious,
icon: const Icon(Icons.navigate_before, color: Colors.white, size: 32),
tooltip: 'Previous Channel',
),
const SizedBox(width: 16),
],
if (widget.onNext != null)
IconButton(
onPressed: widget.onNext,
icon: const Icon(Icons.navigate_next, color: Colors.white, size: 32),
tooltip: 'Next Channel',
),
],
),
),
],
);
}
return const Center(child: CircularProgressIndicator(color: AppColors.primary));
}
}
+15 -1
View File
@@ -380,8 +380,22 @@ class _LiveTVTabState extends ConsumerState<LiveTVTab>
if (epgList.isEmpty) {
return Text('No Info', style: GoogleFonts.inter(color: Colors.white54, fontSize: 10));
}
final now = DateTime.now();
final currentProgram = epgList.firstWhere(
(entry) {
try {
final start = DateTime.parse(entry.start);
final end = DateTime.parse(entry.end);
return now.isAfter(start) && now.isBefore(end);
} catch (e) {
return false;
}
},
orElse: () => epgList.first,
);
return Text(
epgList.first.title,
currentProgram.title,
style: GoogleFonts.inter(color: const Color(0xFFFFD700), fontSize: 10, fontWeight: FontWeight.w600),
maxLines: 1,
overflow: TextOverflow.ellipsis,
@@ -34,6 +34,27 @@ class StreamingSettingsTab extends ConsumerWidget {
),
const SizedBox(height: 24),
// Player Type Section
_buildSectionCard(
context: context,
title: 'Lecteur Vidéo',
icon: Icons.play_circle_outline,
children: [
_buildDropdownTile<PlayerType>(
title: 'Type de lecteur',
subtitle: 'Changer si vous rencontrez des problèmes de lecture',
value: settings.playerType,
items: PlayerType.values,
onChanged: (v) => notifier.setPlayerType(v!),
labelBuilder: (v) => switch (v) {
PlayerType.standard => 'Standard (Avancé)',
PlayerType.lite => 'Lite (Compatibilité max)',
},
),
],
),
const SizedBox(height: 16),
// Quality Section
_buildSectionCard(
context: context,