fApp/lib/widgets/VideoOverlay.dart
Flummi 1cd10b3809 v1.1.5+35
- overlay buttons
- encrypted storage
- downloadbutton (wip)
2025-06-07 20:32:24 +02:00

162 lines
5.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:cached_video_player_plus/cached_video_player_plus.dart';
import 'package:f0ckapp/providers/MediaProvider.dart';
class VideoControlsOverlay extends ConsumerWidget {
final CachedVideoPlayerPlusController controller;
final VoidCallback button;
const VideoControlsOverlay({
super.key,
required this.controller,
required this.button,
});
@override
Widget build(BuildContext context, ref) {
final mediaState = ref.watch(mediaProvider);
final mediaNotifier = ref.read(mediaProvider.notifier);
return Stack(
alignment: Alignment.center,
children: [
Positioned(
right: 12,
top: 12,
child: _ControlButton(
mediaState.muted ? Icons.volume_off : Icons.volume_up,
() {
button();
mediaNotifier.toggleMute();
},
size: 16,
),
),
Positioned(
right: 12,
bottom: 12,
child: _ControlButton(Icons.fullscreen, () {
button();
}, size: 16),
),
Center(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
_ControlButton(Icons.replay_10, () {
button();
Duration newPosition =
controller.value.position - const Duration(seconds: 10);
if (newPosition < Duration.zero) newPosition = Duration.zero;
controller.seekTo(newPosition);
}),
SizedBox(width: 40),
_ControlButton(
controller.value.isPlaying ? Icons.pause : Icons.play_arrow,
() {
button();
controller.value.isPlaying
? controller.pause()
: controller.play();
},
size: 64,
),
SizedBox(width: 40),
_ControlButton(Icons.forward_10, () {
button();
Duration newPosition =
controller.value.position + const Duration(seconds: 10);
if (newPosition > controller.value.duration) {
newPosition = controller.value.duration;
}
controller.seekTo(newPosition);
}),
],
),
),
Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.only(bottom: 0),
child: Stack(
clipBehavior: Clip.none,
children: [
Positioned(
left: 10,
bottom: 12,
child: Text(
'${_formatDuration(controller.value.position)} / ${_formatDuration(controller.value.duration)}',
style: TextStyle(color: Colors.white),
),
),
Listener(
onPointerDown: (_) {
button();
},
child: VideoProgressIndicator(
controller,
allowScrubbing: true,
padding: const EdgeInsets.only(top: 25.0),
colors: const VideoProgressColors(
playedColor: Colors.red,
backgroundColor: Colors.grey,
bufferedColor: Colors.white54,
),
),
),
Positioned(
left:
(controller.value.position.inMilliseconds /
controller.value.duration.inMilliseconds) *
MediaQuery.of(context).size.width -
6,
bottom: -4,
child: Container(
width: 12,
height: 12,
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.red,
border: Border.all(color: Colors.red, width: 2),
),
),
),
],
),
),
),
],
);
}
String _formatDuration(Duration duration) {
String twoDigits(int n) => n.toString().padLeft(2, '0');
return "${twoDigits(duration.inMinutes % 60)}:${twoDigits(duration.inSeconds % 60)}";
}
}
class _ControlButton extends StatelessWidget {
final IconData icon;
final VoidCallback onPressed;
final double size;
const _ControlButton(this.icon, this.onPressed, {this.size = 24});
@override
Widget build(BuildContext context) {
return Container(
decoration: BoxDecoration(
shape: BoxShape.circle,
color: Colors.black.withValues(alpha: 0.4),
),
child: IconButton(
icon: Icon(icon, color: Colors.white, size: size),
onPressed: onPressed,
),
);
}
}