- preload adjacent media
This commit is contained in:
		@@ -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<DetailView> {
 | 
			
		||||
    _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<DetailView> {
 | 
			
		||||
          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<DetailView> {
 | 
			
		||||
    );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  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<DetailView> {
 | 
			
		||||
              errorWidget: (context, url, error) => Icon(Icons.error),
 | 
			
		||||
            )
 | 
			
		||||
          else
 | 
			
		||||
            VideoWidget(details: item),
 | 
			
		||||
            VideoWidget(details: item, isActive: isActive),
 | 
			
		||||
          const SizedBox(height: 20),
 | 
			
		||||
          Text(
 | 
			
		||||
            item.mime,
 | 
			
		||||
 
 | 
			
		||||
@@ -14,7 +14,7 @@ class MediaGrid extends StatefulWidget {
 | 
			
		||||
 | 
			
		||||
class _MediaGridState extends State<MediaGrid> {
 | 
			
		||||
  final ScrollController _scrollController = ScrollController();
 | 
			
		||||
  final String _version = '1.0.24+24';
 | 
			
		||||
  final String _version = '1.0.25+25';
 | 
			
		||||
  List<MediaItem> mediaItems = [];
 | 
			
		||||
  bool isLoading = false;
 | 
			
		||||
  Timer? _debounceTimer;
 | 
			
		||||
 
 | 
			
		||||
@@ -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<VideoWidget> {
 | 
			
		||||
    setState(() {});
 | 
			
		||||
 | 
			
		||||
    _controller.addListener(() => setState(() {}));
 | 
			
		||||
    _controller.play();
 | 
			
		||||
    if (widget.isActive) {
 | 
			
		||||
      _controller.play();
 | 
			
		||||
    }
 | 
			
		||||
    _controller.setLooping(true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@@ -43,6 +47,16 @@ class _VideoWidgetState extends State<VideoWidget> {
 | 
			
		||||
    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<VideoWidget> {
 | 
			
		||||
                        errorWidget: (context, url, error) => Image.asset(
 | 
			
		||||
                          'assets/images/music.webp',
 | 
			
		||||
                          fit: BoxFit.contain,
 | 
			
		||||
                          width: double.infinity
 | 
			
		||||
                          width: double.infinity,
 | 
			
		||||
                        ),
 | 
			
		||||
                      )
 | 
			
		||||
                    : _controller.value.isInitialized
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user