media_carousel_screen 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. import 'package:flutter/material.dart';
  2. import 'package:photo_view/photo_view.dart';
  3. import 'package:veloe_kemono_party_flutter/pages/widgets/video_player_widget';
  4. import '../models/post.dart';
  5. class MediaCarouselItem {
  6. final String url;
  7. final String type; // 'image' or 'video'
  8. final int postIndex;
  9. final int attachmentIndex;
  10. MediaCarouselItem({
  11. required this.url,
  12. required this.type,
  13. required this.postIndex,
  14. required this.attachmentIndex,
  15. });
  16. }
  17. class MediaCarouselScreen extends StatefulWidget {
  18. final int initialIndex;
  19. final List<MediaCarouselItem> mediaItems;
  20. final Future<void> Function() loadMorePosts;
  21. final List<Post> allPosts;
  22. const MediaCarouselScreen({
  23. super.key,
  24. required this.initialIndex,
  25. required this.mediaItems,
  26. required this.loadMorePosts,
  27. required this.allPosts,
  28. });
  29. @override
  30. State<MediaCarouselScreen> createState() => _MediaCarouselScreenState();
  31. }
  32. class _MediaCarouselScreenState extends State<MediaCarouselScreen> {
  33. late PageController _pageController;
  34. late int _currentIndex;
  35. late List<MediaCarouselItem> _mediaItems;
  36. @override
  37. void initState() {
  38. super.initState();
  39. _currentIndex = widget.initialIndex;
  40. _mediaItems = widget.mediaItems;
  41. _pageController = PageController(initialPage: widget.initialIndex);
  42. }
  43. @override
  44. Widget build(BuildContext context) {
  45. return Scaffold(
  46. backgroundColor: Colors.black,
  47. body: Stack(
  48. children: [
  49. PageView.builder(
  50. controller: _pageController,
  51. itemCount: _mediaItems.length,
  52. onPageChanged: (index) {
  53. setState(() {
  54. _currentIndex = index;
  55. });
  56. // Check if we are near the end and load more
  57. if (index >= _mediaItems.length - 3) {
  58. _loadMoreIfNeeded();
  59. }
  60. },
  61. itemBuilder: (context, index) {
  62. final item = _mediaItems[index];
  63. if (item.type == 'image') {
  64. return PhotoView(
  65. imageProvider: NetworkImage(item.url),
  66. backgroundDecoration: const BoxDecoration(color: Colors.black),
  67. );
  68. } else {
  69. return VideoPlayerWidget(videoUrl: item.url);
  70. }
  71. },
  72. ),
  73. Positioned(
  74. top: 40,
  75. left: 20,
  76. child: IconButton(
  77. icon: const Icon(Icons.close, color: Colors.white),
  78. onPressed: () => Navigator.pop(context),
  79. ),
  80. ),
  81. ],
  82. ),
  83. );
  84. }
  85. Future<void> _loadMoreIfNeeded() async {
  86. if (_currentIndex >= _mediaItems.length - 3) {
  87. await widget.loadMorePosts();
  88. setState(() {
  89. _mediaItems = _compileMediaItems(widget.allPosts);
  90. });
  91. }
  92. }
  93. List<MediaCarouselItem> _compileMediaItems(List<Post> posts) {
  94. List<MediaCarouselItem> items = [];
  95. for (int i = 0; i < posts.length; i++) {
  96. final post = posts[i];
  97. for (int j = 0; j < post.attachments.length; j++) {
  98. final attachment = post.attachments[j];
  99. items.add(
  100. MediaCarouselItem(
  101. url: attachment.link,
  102. type: attachment.isImage ? "image" : "video",
  103. postIndex: i,
  104. attachmentIndex: j,
  105. ),
  106. );
  107. }
  108. }
  109. return items;
  110. }
  111. }