This commit is contained in:
2025-06-24 13:05:08 +02:00
parent ba7505c2b3
commit 93a89ba4b9
3 changed files with 67 additions and 67 deletions

View File

@ -282,17 +282,24 @@ class _MediaDetailScreenState extends State<MediaDetailScreen> {
Widget _buildMedia(MediaItem item, bool isActive) { Widget _buildMedia(MediaItem item, bool isActive) {
Widget mediaWidget; Widget mediaWidget;
final bool isFavorite =
item.favorites?.any((f) => f.userId == authController.user.value?.id) ??
false;
if (item.mime.startsWith('image/')) { if (item.mime.startsWith('image/')) {
mediaWidget = CachedNetworkImage( mediaWidget = GestureDetector(
onDoubleTap: () => _handleFavoriteToggle(item, isFavorite),
child: CachedNetworkImage(
imageUrl: item.mediaUrl, imageUrl: item.mediaUrl,
fit: BoxFit.contain, fit: BoxFit.contain,
placeholder: (context, url) => placeholder: (context, url) =>
const Center(child: CircularProgressIndicator()), const Center(child: CircularProgressIndicator()),
errorWidget: (c, e, s) => const Icon(Icons.broken_image, size: 100), errorWidget: (c, e, s) => const Icon(Icons.broken_image, size: 100),
),
); );
} else if (item.mime.startsWith('video/') || } else if (item.mime.startsWith('video/') ||
item.mime.startsWith('audio/')) { item.mime.startsWith('audio/')) {
final key = _videoWidgetKeys.putIfAbsent( final GlobalKey<VideoWidgetState> key = _videoWidgetKeys.putIfAbsent(
item.id, item.id,
() => GlobalKey<VideoWidgetState>(), () => GlobalKey<VideoWidgetState>(),
); );
@ -305,19 +312,14 @@ class _MediaDetailScreenState extends State<MediaDetailScreen> {
setState(() => _readyItemIds.add(item.id)); setState(() => _readyItemIds.add(item.id));
} }
}, },
onDoubleTap: () => _handleFavoriteToggle(item, isFavorite),
); );
} else { } else {
mediaWidget = const Icon(Icons.help_outline, size: 100); mediaWidget = const Icon(Icons.help_outline, size: 100);
} }
final bool isFavorite =
item.favorites?.any((f) => f.userId == authController.user.value?.id) ??
false;
return Hero( return Hero(
tag: 'media_${item.id}', tag: 'media_${item.id}',
child: GestureDetector(
onDoubleTap: () => _handleFavoriteToggle(item, isFavorite),
child: Stack( child: Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: [ children: [
@ -338,7 +340,6 @@ class _MediaDetailScreenState extends State<MediaDetailScreen> {
), ),
], ],
), ),
),
); );
} }

View File

@ -6,8 +6,13 @@ import 'package:f0ckapp/controller/settingscontroller.dart';
class VideoControlsOverlay extends StatefulWidget { class VideoControlsOverlay extends StatefulWidget {
final CachedVideoPlayerPlusController controller; final CachedVideoPlayerPlusController controller;
final VoidCallback? onDoubleTap;
const VideoControlsOverlay({super.key, required this.controller}); const VideoControlsOverlay({
super.key,
required this.controller,
this.onDoubleTap,
});
@override @override
State<VideoControlsOverlay> createState() => _VideoControlsOverlayState(); State<VideoControlsOverlay> createState() => _VideoControlsOverlayState();
@ -140,28 +145,10 @@ class _VideoControlsOverlayState extends State<VideoControlsOverlay> {
AnimatedOpacity( AnimatedOpacity(
opacity: _controlsVisible && !_isScrubbing ? 1.0 : 0.0, opacity: _controlsVisible && !_isScrubbing ? 1.0 : 0.0,
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
child: IgnorePointer( child: Align(
ignoring: !_controlsVisible,
child: Stack(
alignment: Alignment.center,
children: [
IconButton(
icon: Icon(
widget.controller.value.isPlaying
? Icons.pause
: Icons.play_arrow,
size: 64,
color: Theme.of(context).colorScheme.primary,
),
onPressed: _handlePlayPause,
),
Align(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
child: _buildBottomBar(), child: _buildBottomBar(),
), ),
],
),
),
), ),
], ],
), ),
@ -208,6 +195,18 @@ class _VideoControlsOverlayState extends State<VideoControlsOverlay> {
padding: const EdgeInsets.fromLTRB(16, 0, 16, 8), padding: const EdgeInsets.fromLTRB(16, 0, 16, 8),
child: Row( child: Row(
children: [ children: [
IconButton(
icon: Icon(
widget.controller.value.isPlaying
? Icons.pause
: Icons.play_arrow,
color: Theme.of(context).colorScheme.primary,
size: 20,
),
onPressed: _handlePlayPause,
constraints: const BoxConstraints(),
padding: EdgeInsets.zero,
),
Text( Text(
_formatDuration(widget.controller.value.position), _formatDuration(widget.controller.value.position),
style: TextStyle( style: TextStyle(

View File

@ -17,6 +17,7 @@ class VideoWidget extends StatefulWidget {
final bool fullScreen; final bool fullScreen;
final VoidCallback? onInitialized; final VoidCallback? onInitialized;
final Duration? initialPosition; final Duration? initialPosition;
final VoidCallback? onDoubleTap;
const VideoWidget({ const VideoWidget({
super.key, super.key,
@ -25,6 +26,7 @@ class VideoWidget extends StatefulWidget {
this.fullScreen = false, this.fullScreen = false,
this.onInitialized, this.onInitialized,
this.initialPosition, this.initialPosition,
this.onDoubleTap,
}); });
@override @override
@ -56,6 +58,7 @@ class VideoWidgetState extends State<VideoWidget> {
await videoController.initialize(); await videoController.initialize();
if (!mounted) return; if (!mounted) return;
// Rebuild the widget to reflect the initialized state
setState(() {}); setState(() {});
if (widget.initialPosition != null) { if (widget.initialPosition != null) {
@ -100,7 +103,8 @@ class VideoWidgetState extends State<VideoWidget> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
bool isAudio = widget.details.mime.startsWith('audio'); final bool isInitialized = videoController.value.isInitialized;
final bool isAudio = widget.details.mime.startsWith('audio');
Widget mediaContent; Widget mediaContent;
if (isAudio) { if (isAudio) {
@ -114,29 +118,25 @@ class VideoWidgetState extends State<VideoWidget> {
), ),
); );
} else { } else {
mediaContent = videoController.value.isInitialized mediaContent = isInitialized
? CachedVideoPlayerPlus(videoController) ? CachedVideoPlayerPlus(videoController)
: const Center(child: CircularProgressIndicator()); : const Center(child: CircularProgressIndicator());
} }
return AspectRatio( return AspectRatio(
aspectRatio: videoController.value.isInitialized aspectRatio: isInitialized
? videoController.value.aspectRatio ? videoController.value.aspectRatio
: (isAudio ? 16 / 9 : 9 / 16), : (isAudio ? 16 / 9 : 9 / 16),
child: Stack( child: Stack(
alignment: Alignment.center, alignment: Alignment.center,
children: [ children: [
mediaContent, mediaContent,
AnimatedBuilder( if (isInitialized)
animation: videoController, Positioned.fill(
builder: (context, child) { child: VideoControlsOverlay(
if (videoController.value.isInitialized) { controller: videoController,
return Positioned.fill( onDoubleTap: widget.onDoubleTap,
child: VideoControlsOverlay(controller: videoController), ),
);
}
return const SizedBox.shrink();
},
), ),
], ],
), ),