Files
fApp/lib/widgets/video_widget.dart
2025-06-24 13:05:08 +02:00

146 lines
3.9 KiB
Dart

import 'dart:async';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:cached_video_player_plus/cached_video_player_plus.dart';
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:f0ckapp/models/item.dart';
import 'package:f0ckapp/widgets/video_controls_overlay.dart';
import 'package:f0ckapp/controller/settingscontroller.dart';
import 'package:f0ckapp/controller/mediacontroller.dart';
class VideoWidget extends StatefulWidget {
final MediaItem details;
final bool isActive;
final bool fullScreen;
final VoidCallback? onInitialized;
final Duration? initialPosition;
final VoidCallback? onDoubleTap;
const VideoWidget({
super.key,
required this.details,
required this.isActive,
this.fullScreen = false,
this.onInitialized,
this.initialPosition,
this.onDoubleTap,
});
@override
State<VideoWidget> createState() => VideoWidgetState();
}
class VideoWidgetState extends State<VideoWidget> {
final MediaController mediaController = Get.find<MediaController>();
final SettingsController settingsController = Get.find<SettingsController>();
late CachedVideoPlayerPlusController videoController;
late Worker _muteWorker;
@override
void initState() {
super.initState();
_initController();
_muteWorker = ever(settingsController.muted, (bool muted) {
if (videoController.value.isInitialized) {
videoController.setVolume(muted ? 0.0 : 1.0);
}
});
}
Future<void> _initController() async {
videoController = CachedVideoPlayerPlusController.networkUrl(
Uri.parse(widget.details.mediaUrl),
videoPlayerOptions: VideoPlayerOptions(mixWithOthers: true),
);
await videoController.initialize();
if (!mounted) return;
// Rebuild the widget to reflect the initialized state
setState(() {});
if (widget.initialPosition != null) {
await videoController.seekTo(widget.initialPosition!);
}
widget.onInitialized?.call();
videoController.setLooping(true);
videoController.setVolume(settingsController.muted.value ? 0.0 : 1.0);
if (widget.isActive) {
videoController.play();
}
}
@override
void didUpdateWidget(covariant VideoWidget oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.details.mediaUrl != oldWidget.details.mediaUrl) {
videoController.dispose();
_initController();
return;
}
if (widget.isActive != oldWidget.isActive) {
if (videoController.value.isInitialized) {
if (widget.isActive) {
videoController.play();
} else {
videoController.pause();
}
}
}
}
@override
void dispose() {
_muteWorker.dispose();
videoController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final bool isInitialized = videoController.value.isInitialized;
final bool isAudio = widget.details.mime.startsWith('audio');
Widget mediaContent;
if (isAudio) {
mediaContent = CachedNetworkImage(
imageUrl: widget.details.coverUrl,
fit: BoxFit.cover,
errorWidget: (c, e, s) => Image.asset(
'assets/images/music.webp',
fit: BoxFit.contain,
width: double.infinity,
),
);
} else {
mediaContent = isInitialized
? CachedVideoPlayerPlus(videoController)
: const Center(child: CircularProgressIndicator());
}
return AspectRatio(
aspectRatio: isInitialized
? videoController.value.aspectRatio
: (isAudio ? 16 / 9 : 9 / 16),
child: Stack(
alignment: Alignment.center,
children: [
mediaContent,
if (isInitialized)
Positioned.fill(
child: VideoControlsOverlay(
controller: videoController,
onDoubleTap: widget.onDoubleTap,
),
),
],
),
);
}
}