From ae5f395331f81d59be6cd173875911260701bbbd Mon Sep 17 00:00:00 2001 From: Flummi Date: Thu, 5 Jun 2025 08:41:48 +0200 Subject: [PATCH] 1.0.25+25 - preload adjacent media --- lib/screens/DetailView.dart | 48 +++++++++++++++++++++++++++--------- lib/screens/MediaGrid.dart | 2 +- lib/widgets/VideoWidget.dart | 20 ++++++++++++--- pubspec.yaml | 2 +- 4 files changed, 56 insertions(+), 16 deletions(-) diff --git a/lib/screens/DetailView.dart b/lib/screens/DetailView.dart index b6437b9..d5a3be0 100644 --- a/lib/screens/DetailView.dart +++ b/lib/screens/DetailView.dart @@ -5,6 +5,7 @@ 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:flutter_cache_manager/flutter_cache_manager.dart'; class DetailView extends StatefulWidget { final int initialItemId; @@ -46,18 +47,42 @@ class _DetailViewState extends State { _pageController = PageController(initialPage: initialIndex); currentItemId = mediaItems[initialIndex].id; - _pageController.addListener(_onPageScroll); + int? lastLoadedIndex; + _pageController.addListener(() async { + final newIndex = _pageController.page?.round(); + if (newIndex != null && + newIndex < mediaItems.length && + newIndex != lastLoadedIndex) { + setState(() => currentItemId = mediaItems[newIndex].id); + lastLoadedIndex = newIndex; + + _preloadAdjacentMedia(newIndex); + } + + if (_pageController.position.pixels >= + _pageController.position.maxScrollExtent - 100) { + _loadMoreMedia(); + } + }); + + _preloadAdjacentMedia(initialIndex); } - void _onPageScroll() { - final newIndex = _pageController.page?.round(); - if (newIndex != null && newIndex < mediaItems.length) { - setState(() => currentItemId = mediaItems[newIndex].id); + void _preloadAdjacentMedia(int index) async { + if (index + 1 < mediaItems.length) { + final nextUrl = mediaItems[index + 1].mediaUrl; + if (await DefaultCacheManager().getFileFromCache(nextUrl) == null) { + await DefaultCacheManager().downloadFile(nextUrl); + print('preload ${mediaItems[index + 1].id}'); + } } - if (_pageController.position.pixels >= - _pageController.position.maxScrollExtent - 100) { - _loadMoreMedia(); + if (index - 1 >= 0) { + final prevUrl = mediaItems[index - 1].mediaUrl; + if (await DefaultCacheManager().getFileFromCache(prevUrl) == null) { + await DefaultCacheManager().downloadFile(prevUrl); + print('preload ${mediaItems[index - 1].id}'); + } } } @@ -120,11 +145,12 @@ class _DetailViewState extends State { PageTransformer( controller: _pageController, pages: mediaItems.map((item) { + final isActive = item.id == currentItemId; return Scaffold( body: SafeArea( child: SmartRefreshIndicator( onRefresh: _refreshMediaItem, - child: _buildMediaItem(item), + child: _buildMediaItem(item, isActive), ), ), ); @@ -169,7 +195,7 @@ class _DetailViewState extends State { ); } - Widget _buildMediaItem(MediaItem item) { + Widget _buildMediaItem(MediaItem item, bool isActive) { return SingleChildScrollView( child: Column( mainAxisAlignment: MainAxisAlignment.center, @@ -182,7 +208,7 @@ class _DetailViewState extends State { errorWidget: (context, url, error) => Icon(Icons.error), ) else - VideoWidget(details: item), + VideoWidget(details: item, isActive: isActive), const SizedBox(height: 20), Text( item.mime, diff --git a/lib/screens/MediaGrid.dart b/lib/screens/MediaGrid.dart index 29a3659..1e67478 100644 --- a/lib/screens/MediaGrid.dart +++ b/lib/screens/MediaGrid.dart @@ -14,7 +14,7 @@ class MediaGrid extends StatefulWidget { class _MediaGridState extends State { final ScrollController _scrollController = ScrollController(); - final String _version = '1.0.24+24'; + final String _version = '1.0.25+25'; List mediaItems = []; bool isLoading = false; Timer? _debounceTimer; diff --git a/lib/widgets/VideoWidget.dart b/lib/widgets/VideoWidget.dart index 88cdf98..d148af2 100644 --- a/lib/widgets/VideoWidget.dart +++ b/lib/widgets/VideoWidget.dart @@ -7,7 +7,9 @@ import 'dart:async'; class VideoWidget extends StatefulWidget { final MediaItem details; - const VideoWidget({super.key, required this.details}); + final bool isActive; + + const VideoWidget({super.key, required this.details, required this.isActive}); @override State createState() => _VideoWidgetState(); @@ -32,7 +34,9 @@ class _VideoWidgetState extends State { setState(() {}); _controller.addListener(() => setState(() {})); - _controller.play(); + if (widget.isActive) { + _controller.play(); + } _controller.setLooping(true); } @@ -43,6 +47,16 @@ class _VideoWidgetState extends State { super.dispose(); } + @override + void didUpdateWidget(VideoWidget oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.isActive) { + _controller.play(); + } else { + _controller.pause(); + } + } + void _onTap({bool ctrlButton = false}) { if (!ctrlButton) { setState(() => _showControls = !_showControls); @@ -81,7 +95,7 @@ class _VideoWidgetState extends State { errorWidget: (context, url, error) => Image.asset( 'assets/images/music.webp', fit: BoxFit.contain, - width: double.infinity + width: double.infinity, ), ) : _controller.value.isInitialized diff --git a/pubspec.yaml b/pubspec.yaml index 3e53f59..4ff2c76 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -16,7 +16,7 @@ publish_to: 'none' # Remove this line if you wish to publish to pub.dev # https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html # In Windows, build-name is used as the major, minor, and patch parts # of the product and file versions while build-number is used as the build suffix. -version: 1.0.24+24 +version: 1.0.25+25 environment: sdk: ^3.9.0-100.2.beta