media_carousel_screen 3.2 KB

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