fApp/lib/screens/detail.dart
2025-05-31 16:48:33 +02:00

206 lines
6.8 KiB
Dart

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<DetailView> createState() => _DetailViewState();
}
class _DetailViewState extends State<DetailView> {
late VideoPlayerController _controller;
late Future<void> _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<void> _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),
),
],
),
),
],
),
),
),
);
}
}