import 'package:f0ckapp/models/mediaitem.dart'; import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; class VideoWidget extends StatefulWidget { final MediaItem details; const VideoWidget({super.key, required this.details}); @override State createState() => _VideoWidgetState(); } class _VideoWidgetState extends State { late VideoPlayerController _controller; @override void initState() { super.initState(); _initController(); } Future _initController() async { _controller = VideoPlayerController.networkUrl( Uri.parse(widget.details.mediaUrl), ); await _controller.initialize(); setState(() {}); _controller.addListener(() => setState(() {})); _controller.play(); _controller.setLooping(true); } @override void dispose() { _controller.dispose(); super.dispose(); } String _formatDuration(Duration duration) { String twoDigits(int n) => n.toString().padLeft(2, '0'); final minutes = twoDigits(duration.inMinutes.remainder(60)); final seconds = twoDigits(duration.inSeconds.remainder(60)); return "$minutes:$seconds"; } @override Widget build(BuildContext context) { bool isAudio = widget.details.mime.startsWith('audio'); return Column( mainAxisSize: MainAxisSize.min, children: [ AspectRatio( aspectRatio: _controller.value.isInitialized ? _controller.value.aspectRatio : 9 / 16, child: Stack( alignment: Alignment.center, children: [ GestureDetector( onTap: () { setState(() { _controller.value.isPlaying ? _controller.pause() : _controller.play(); }); }, child: isAudio ? Image.network(widget.details.coverUrl, fit: BoxFit.cover) : _controller.value.isInitialized ? VideoPlayer(_controller) : Center(child: CircularProgressIndicator()), ), if (_controller.value.isInitialized) Align( alignment: Alignment.bottomCenter, child: Stack( children: [ SizedBox( height: 10, child: VideoProgressIndicator( _controller, allowScrubbing: true, padding: EdgeInsets.only(bottom: 0), colors: VideoProgressColors( playedColor: Colors.red, bufferedColor: Colors.grey, backgroundColor: Colors.black.withAlpha(128), ), ), ), Positioned( left: (_controller.value.position.inMilliseconds / _controller.value.duration.inMilliseconds) * MediaQuery.of(context).size.width - 6, bottom: -1, child: Container( width: 12, height: 12, decoration: BoxDecoration( shape: BoxShape.circle, color: Colors.white, border: Border.all(color: Colors.red, width: 2), ), ), ), ], ), ), ], ), ), if (_controller.value.isInitialized) SizedBox( child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( _formatDuration(_controller.value.position), style: const TextStyle(color: Colors.white), ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( icon: const Icon(Icons.replay_10), color: Colors.white, onPressed: () { _controller.seekTo( _controller.value.position - const Duration(seconds: 10), ); }, ), IconButton( color: Colors.white, icon: Icon( _controller.value.isPlaying ? Icons.pause : Icons.play_arrow, ), onPressed: () { setState(() { _controller.value.isPlaying ? _controller.pause() : _controller.play(); }); }, ), IconButton( color: Colors.white, icon: const Icon(Icons.forward_10), onPressed: () { _controller.seekTo( _controller.value.position + const Duration(seconds: 10), ); }, ), ], ), Text( _formatDuration(_controller.value.duration), style: const TextStyle(color: Colors.white), ), ], ), ), ], ); } }