import 'package:flutter/material.dart'; import 'package:video_player/video_player.dart'; import 'package:f0ckapp/models/mediaitem_detail.dart'; import 'package:f0ckapp/services/api.dart'; class DetailView extends StatefulWidget { final MediaItemDetail details; const DetailView({super.key, required this.details}); @override State createState() => _DetailViewState(); } class _DetailViewState extends State { late VideoPlayerController _controller; late Future _initializeVideoPlayer; bool isAudio = false; @override void initState() { super.initState(); isAudio = widget.details.mime.startsWith("audio/"); _controller = VideoPlayerController.networkUrl( Uri.parse(widget.details.mediaUrl), ); if (!widget.details.mime.startsWith("image/")) { _initializeVideoPlayer = _controller .initialize() .then((_) { setState(() { _controller.play(); _controller.setLooping(true); }); }) .catchError((error) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("Fehler beim Laden des Videos: $error")), ); }); } } @override void dispose() { _controller.dispose(); super.dispose(); } Future _loadNewMediaItem(int itemId, bool swipeLeft) async { try { var newDetails = await fetchMediaDetail(itemId); Navigator.of(context).pushReplacement( PageRouteBuilder( pageBuilder: (context, animation, secondaryAnimation) => DetailView(details: newDetails), transitionsBuilder: (context, animation, secondaryAnimation, child) { Offset begin = swipeLeft ? const Offset(-1.0, 0.0) : const Offset(1.0, 0.0); const Offset end = Offset.zero; const curve = Curves.easeInOut; var tween = Tween( begin: begin, end: end, ).chain(CurveTween(curve: curve)); var offsetAnimation = animation.drive(tween); return SlideTransition(position: offsetAnimation, child: child); }, ), ); } catch (error) { ScaffoldMessenger.of(context).showSnackBar( SnackBar(content: Text("Fehler beim Laden des Items: $error")), ); } } @override Widget build(BuildContext context) { return GestureDetector( onHorizontalDragEnd: (details) { if (details.velocity.pixelsPerSecond.dx > 0) { _loadNewMediaItem(widget.details.next, true); } else if (details.velocity.pixelsPerSecond.dx < 0) { _loadNewMediaItem(widget.details.prev, false); } }, child: Scaffold( appBar: AppBar( backgroundColor: const Color(0xFF2B2B2B), foregroundColor: Colors.white, title: Text('f0ck #${widget.details.id}'), centerTitle: true, ), body: SingleChildScrollView( child: Column( children: [ if (widget.details.mime.contains( RegExp(r'image/(jpeg|png|gif|webp)'), )) ...[ Image.network(widget.details.mediaUrl), ] else ...[ Stack( alignment: Alignment.center, children: [ if (isAudio) Image.network( 'https://f0ck.me/ca/${widget.details.id}.webp', ), FutureBuilder( future: _initializeVideoPlayer, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.done && _controller.value.isInitialized) { return AspectRatio( aspectRatio: isAudio ? 1 : _controller.value.aspectRatio, child: VideoPlayer(_controller), ); } else { return const CircularProgressIndicator(); } }, ), ], ), Padding( padding: const EdgeInsets.symmetric(vertical: 8.0), child: VideoProgressIndicator( _controller, allowScrubbing: true, ), ), Row( mainAxisAlignment: MainAxisAlignment.center, children: [ IconButton( icon: const Icon(Icons.replay_10), onPressed: () { _controller.seekTo( _controller.value.position - const Duration(seconds: 10), ); }, ), IconButton( icon: Icon( _controller.value.isPlaying ? Icons.pause : Icons.play_arrow, ), onPressed: () { setState(() { _controller.value.isPlaying ? _controller.pause() : _controller.play(); }); }, ), IconButton( icon: const Icon(Icons.forward_10), onPressed: () { _controller.seekTo( _controller.value.position + const Duration(seconds: 10), ); }, ), ], ), ], const SizedBox(height: 16), Padding( padding: const EdgeInsets.all(16.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( '${widget.details.mime}', style: const TextStyle(fontSize: 16, color: Colors.white), ), Text( "Benutzername: ${widget.details.username}", style: const TextStyle(fontSize: 16, color: Colors.white), ), Text( "Zeitstempel: ${widget.details.stamp}", style: const TextStyle(fontSize: 16, color: Colors.white), ), ], ), ), ], ), ), ), ); } }