import 'package:flutter/material.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:provider/provider.dart'; import 'package:f0ckapp/models/MediaItem.dart'; import 'package:f0ckapp/services/Api.dart'; import 'package:f0ckapp/widgets/VideoWidget.dart'; import 'package:f0ckapp/utils/SmartRefreshIndicator.dart'; import 'package:f0ckapp/utils/PageTransformer.dart'; import 'package:f0ckapp/providers/MediaProvider.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart'; class DetailView extends StatefulWidget { final int initialItemId; const DetailView({super.key, required this.initialItemId}); @override State createState() => _DetailViewState(); } class _DetailViewState extends State { late PageController _pageController; bool isLoading = false; int _currentIndex = 0; @override void initState() { super.initState(); final provider = Provider.of(context, listen: false); final initialIndex = provider.mediaItems.indexWhere( (item) => item.id == widget.initialItemId, ); _pageController = PageController(initialPage: initialIndex); _currentIndex = initialIndex; _pageController.addListener(() { setState(() { _currentIndex = _pageController.page?.round() ?? 0; }); }); _preloadAdjacentMedia(initialIndex); } void _preloadAdjacentMedia(int index) async { final provider = Provider.of(context, listen: false); if (index + 1 < provider.mediaItems.length) { final nextUrl = provider.mediaItems[index + 1].mediaUrl; if (await DefaultCacheManager().getFileFromCache(nextUrl) == null) { await DefaultCacheManager().downloadFile(nextUrl); } } if (index - 1 >= 0) { final prevUrl = provider.mediaItems[index - 1].mediaUrl; if (await DefaultCacheManager().getFileFromCache(prevUrl) == null) { await DefaultCacheManager().downloadFile(prevUrl); } } } Future _loadMoreMedia() async { if (isLoading) return; setState(() => isLoading = true); final provider = Provider.of(context, listen: false); try { final newMedia = await fetchMedia( older: provider.mediaItems.last.id, type: provider.type, mode: provider.mode, random: provider.random, tag: provider.tag, ); if (mounted && newMedia.isNotEmpty) { setState(() => provider.mediaItems.addAll(newMedia)); } } catch (e) { _showError("Fehler beim Laden der Medien: $e"); } finally { setState(() => isLoading = false); } } void _showError(String message) { if (!mounted) return; ScaffoldMessenger.of( context, ).showSnackBar(SnackBar(content: Text(message))); } @override Widget build(BuildContext context) { final provider = Provider.of(context); return Scaffold( appBar: AppBar( centerTitle: true, title: Text('f0ck #${provider.mediaItems.elementAt(_currentIndex).id.toString()} (${provider.type})'), ), body: Stack( children: [ PageTransformer( controller: _pageController, pages: provider.mediaItems.map((item) { int itemIndex = provider.mediaItems.indexOf(item); return SafeArea( child: SmartRefreshIndicator( onRefresh: _loadMoreMedia, child: _buildMediaItem(item, _currentIndex == itemIndex), ), ); }).toList(), ), ], ), persistentFooterButtons: provider.tag != null ? [ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text('tag: '), InputChip( label: Text(provider.tag!), backgroundColor: const Color(0xFF090909), labelStyle: const TextStyle(color: Colors.white), onDeleted: () { provider.setTag(null); Navigator.pop(context); }, ), ], ), ] : null, ); } Widget _buildMediaItem(MediaItem item, bool isActive) { final provider = Provider.of(context); return SingleChildScrollView( child: Column( children: [ if (item.mime.startsWith('image')) CachedNetworkImage( imageUrl: item.mediaUrl, fit: BoxFit.contain, placeholder: (context, url) => CircularProgressIndicator(), errorWidget: (context, url, error) => Icon(Icons.error), ) else VideoWidget(details: item, isActive: isActive), const SizedBox(height: 20), Text( item.mime, style: const TextStyle(color: Colors.white, fontSize: 18), ), const SizedBox(height: 10, width: double.infinity), Wrap( alignment: WrapAlignment.center, spacing: 5.0, children: item.tags.map((tag) { return ActionChip( onPressed: () { if (tag.tag == 'sfw' || tag.tag == 'nsfw') return; setState(() { provider.setTag(tag.tag); Navigator.pop(context); }); }, label: Text(tag.tag), backgroundColor: switch (tag.id) { 1 => Colors.green, 2 => Colors.red, _ => const Color(0xFF090909), }, labelStyle: const TextStyle(color: Colors.white), ); }).toList(), ), const SizedBox(height: 20), ], ), ); } }