From 582e7ad4a82799e9841736dd0931400ebb9c1c87 Mon Sep 17 00:00:00 2001 From: kodjomoustapha <107993382+kodjodevf@users.noreply.github.com> Date: Fri, 18 Aug 2023 11:18:26 +0100 Subject: [PATCH] Fix next chapter preload, Flutter 3.13.0, update dependecies --- .../manga/reader/image_view_center.dart | 6 - .../manga/reader/image_view_vertical.dart | 16 +- lib/modules/manga/reader/reader_view.dart | 703 ++++++++---------- pubspec.lock | 160 ++-- pubspec.yaml | 28 +- windows/runner/flutter_window.cpp | 5 + 6 files changed, 433 insertions(+), 485 deletions(-) diff --git a/lib/modules/manga/reader/image_view_center.dart b/lib/modules/manga/reader/image_view_center.dart index 3370625..3a2606e 100644 --- a/lib/modules/manga/reader/image_view_center.dart +++ b/lib/modules/manga/reader/image_view_center.dart @@ -8,12 +8,9 @@ import 'package:mangayomi/utils/reg_exp_matcher.dart'; class ImageViewCenter extends ConsumerWidget { final String lang; - final int length; final String url; final int index; - final String titleManga; final String source; - final String chapter; final Directory path; final bool isLocale; final Uint8List? archiveImage; @@ -24,12 +21,9 @@ class ImageViewCenter extends ConsumerWidget { const ImageViewCenter({ super.key, required this.url, - required this.chapter, required this.index, required this.path, - required this.titleManga, required this.source, - required this.length, required this.loadStateChanged, required this.onDoubleTap, required this.initGestureConfigHandler, diff --git a/lib/modules/manga/reader/image_view_vertical.dart b/lib/modules/manga/reader/image_view_vertical.dart index 2abedb0..966f5e4 100644 --- a/lib/modules/manga/reader/image_view_vertical.dart +++ b/lib/modules/manga/reader/image_view_vertical.dart @@ -9,13 +9,10 @@ import 'package:mangayomi/utils/reg_exp_matcher.dart'; import 'package:mangayomi/modules/manga/reader/widgets/circular_progress_indicator_animate_rotate.dart'; class ImageViewVertical extends ConsumerWidget { - final int length; final bool isLocale; final String url; final int index; - final String titleManga; final String source; - final String chapter; final Directory path; final String lang; final Uint8List? archiveImage; @@ -23,12 +20,9 @@ class ImageViewVertical extends ConsumerWidget { const ImageViewVertical({ super.key, required this.url, - required this.chapter, required this.index, required this.path, - required this.titleManga, required this.source, - required this.length, required this.isLocale, required this.lang, this.archiveImage, @@ -48,12 +42,14 @@ class ImageViewVertical extends ConsumerWidget { isLocale ? archiveImage != null ? ExtendedImage.memory(archiveImage!, - fit: BoxFit.contain, enableMemoryCache: false, + fit: BoxFit.contain, + enableMemoryCache: false, + enableLoadState: true, loadStateChanged: (ExtendedImageState state) { if (state.extendedImageLoadState == LoadState.loading) { return Container( color: Colors.black, - height: mediaHeight(context, 0.8), + height: mediaHeight(context, 0.6), ); } return null; @@ -62,11 +58,12 @@ class ImageViewVertical extends ConsumerWidget { fit: BoxFit.contain, enableMemoryCache: false, File('${path.path}${padIndex(index + 1)}.jpg'), + enableLoadState: true, loadStateChanged: (ExtendedImageState state) { if (state.extendedImageLoadState == LoadState.loading) { return Container( color: Colors.black, - height: mediaHeight(context, 0.8), + height: mediaHeight(context, 0.6), ); } return null; @@ -78,6 +75,7 @@ class ImageViewVertical extends ConsumerWidget { cacheMaxAge: const Duration(days: 7), fit: BoxFit.contain, enableMemoryCache: true, + enableLoadState: true, loadStateChanged: (ExtendedImageState state) { if (state.extendedImageLoadState == LoadState.loading) { final ImageChunkEvent? loadingProgress = diff --git a/lib/modules/manga/reader/reader_view.dart b/lib/modules/manga/reader/reader_view.dart index bf112e4..5cc088b 100644 --- a/lib/modules/manga/reader/reader_view.dart +++ b/lib/modules/manga/reader/reader_view.dart @@ -12,7 +12,6 @@ import 'package:mangayomi/main.dart'; import 'package:mangayomi/models/chapter.dart'; import 'package:mangayomi/models/settings.dart'; import 'package:mangayomi/modules/more/settings/reader/providers/reader_state_provider.dart'; -import 'package:mangayomi/providers/l10n_providers.dart'; import 'package:mangayomi/sources/utils/utils.dart'; import 'package:mangayomi/modules/manga/reader/providers/push_router.dart'; import 'package:mangayomi/services/get_chapter_url.dart'; @@ -26,7 +25,7 @@ import 'package:mangayomi/modules/more/settings/reader/reader_screen.dart'; import 'package:mangayomi/modules/widgets/progress_center.dart'; import 'package:photo_view/photo_view.dart'; import 'package:photo_view/photo_view_gallery.dart'; -import 'package:scrollview_observer/scrollview_observer.dart'; +import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; typedef DoubleClickAnimationListener = void Function(); @@ -157,8 +156,7 @@ class _MangaChapterPageGalleryState @override void dispose() { _readerController.setMangaHistoryUpdate(); - _readerController - .setPageIndex(_uChapDataPreload[_currentIndex ?? 0].index!); + _readerController.setPageIndex(_uChapDataPreload[_currentIndex!].index!); _rebuildDetail.close(); _doubleClickAnimationController.dispose(); clearGestureDetailsCache(); @@ -169,7 +167,7 @@ class _MangaChapterPageGalleryState late Chapter chapter = widget.chapter; - final List _uChapDataPreload = []; + List _uChapDataPreload = []; bool animatePageTransitions = isar.settings.getSync(227)!.animatePageTransitions!; Duration? _doubleTapAnimationDuration() { @@ -185,14 +183,12 @@ class _MangaChapterPageGalleryState late int? _currentIndex = _readerController.getPageIndex(); - late ListObserverController _observerController; - final ScrollController _scrollController = ScrollController(); + late final ItemScrollController _itemScrollController = + ItemScrollController(); + final ItemPositionsListener _itemPositionsListener = + ItemPositionsListener.create(); @override void initState() { - _observerController = ListObserverController( - controller: _scrollController, - ); - _doubleClickAnimationController = AnimationController( duration: _doubleTapAnimationDuration(), vsync: this); @@ -201,11 +197,48 @@ class _MangaChapterPageGalleryState _animation = Tween(begin: 1.0, end: 2.0).animate( CurvedAnimation(curve: Curves.ease, parent: _scaleAnimationController)); _animation.addListener(() => _photoViewController.scale = _animation.value); + _itemPositionsListener.itemPositions.addListener(_readProgressListener); _initCurrentIndex(); super.initState(); } + void _readProgressListener() { + _currentIndex = _itemPositionsListener.itemPositions.value.first.index; + if (_currentIndex! >= 0 && _currentIndex! < _uChapDataPreload.length) { + if (_readerController.chapter.id != + _uChapDataPreload[_currentIndex!].chapter!.id) { + setState(() { + _readerController = ReaderController( + chapter: _uChapDataPreload[_currentIndex!].chapter!); + + _chapterUrlModel = _uChapDataPreload[_currentIndex!].chapterUrlModel!; + }); + } + + ref.read(currentIndexProvider(chapter).notifier).setCurrentIndex( + _uChapDataPreload[_currentIndex!].index!, + ); + } + if (_itemPositionsListener.itemPositions.value.last.index == + _uChapDataPreload.length - 1) { + try { + bool hasNextChapter = _readerController.getChapterIndex() != 0; + final chapter = + hasNextChapter ? _readerController.getNextChapter() : null; + if (chapter != null) { + ref + .watch(getChapterUrlProvider( + chapter: chapter, + ).future) + .then((value) { + _preloadNextChapter(value, chapter); + }); + } + } catch (_) {} + } + } + _preloadNextChapter(GetChapterUrlModel chapterData, Chapter chap) { try { int length = 0; @@ -213,15 +246,15 @@ class _MangaChapterPageGalleryState List uChapDataPreloadP = []; List uChapDataPreloadL = _uChapDataPreload; List preChap = []; - for (var data in _uChapDataPreload) { + for (var ee in _uChapDataPreload) { if (chapterData.uChapDataPreload.first.chapter!.url == - data.chapter!.url) { + ee.chapter!.url) { isExist = true; } } if (!isExist) { - for (var data in chapterData.uChapDataPreload) { - preChap.add(data); + for (var aa in chapterData.uChapDataPreload) { + preChap.add(aa); } } @@ -230,10 +263,26 @@ class _MangaChapterPageGalleryState for (var i = 0; i < preChap.length; i++) { int index = i + length; final dataPreload = preChap[i]; - uChapDataPreloadP.add(dataPreload..index = index); + uChapDataPreloadP.add(UChapDataPreload( + dataPreload.chapter, + dataPreload.path, + dataPreload.url, + dataPreload.isLocale, + dataPreload.archiveImage, + dataPreload.index, + dataPreload.chapterUrlModel, + index)); } if (mounted) { uChapDataPreloadL.addAll(uChapDataPreloadP); + setState(() { + _uChapDataPreload = uChapDataPreloadL; + _chapterUrlModel = chapterData; + _readerController = ReaderController(chapter: chap); + _readerController = ReaderController( + chapter: _uChapDataPreload[_currentIndex!].chapter!); + chapter = chap; + }); } } } catch (_) {} @@ -247,27 +296,26 @@ class _MangaChapterPageGalleryState _selectedValue = _readerController.getReaderMode(); _setReaderMode(_selectedValue!, true); ref.read(currentIndexProvider(chapter).notifier).setCurrentIndex( - _uChapDataPreload[_currentIndex ?? 0].index!, + _uChapDataPreload[_currentIndex!].index!, ); } void _onPageChanged(int index) { - _currentIndex = index; - if (_chapterId != _uChapDataPreload[_currentIndex ?? 0].chapter!.id) { - if (mounted) { - setState(() { - _chapterUrlModel = - _uChapDataPreload[_currentIndex ?? 0].chapterUrlModel!; - _chapterId = _uChapDataPreload[_currentIndex ?? 0].chapter!.id; - }); - } + if (_readerController.chapter.id != _uChapDataPreload[index].chapter!.id) { + setState(() { + _readerController = + ReaderController(chapter: _uChapDataPreload[index].chapter!); + + _chapterUrlModel = _uChapDataPreload[index].chapterUrlModel!; + }); } + _currentIndex = index; ref.read(currentIndexProvider(chapter).notifier).setCurrentIndex( _uChapDataPreload[index].index!, ); - if (_uChapDataPreload[index].index! == - _readerController.getPageLength([]) - 1) { + + if (_uChapDataPreload[index].pageIndex! == _uChapDataPreload.length - 1) { try { bool hasNextChapter = _readerController.getChapterIndex() != 0; final chapter = @@ -293,25 +341,22 @@ class _MangaChapterPageGalleryState _selectedValue == ReaderMode.webtoon) { if (index != -1) { if (isSlide) { - _observerController.jumpTo( + _itemScrollController.jumpTo( index: index, ); } else { animatePageTransitions - ? _observerController.animateTo( + ? _itemScrollController.scrollTo( curve: Curves.ease, index: index, duration: const Duration(milliseconds: 150)) - : _observerController.jumpTo( + : _itemScrollController.jumpTo( index: index, ); } } } else { if (index != -1) { - setState(() { - _isZoom = false; - }); if (_extendedController.hasClients) { if (isSlide) { _extendedController.jumpToPage(index); @@ -329,26 +374,23 @@ class _MangaChapterPageGalleryState if (_selectedValue == ReaderMode.verticalContinuous || _selectedValue == ReaderMode.webtoon) { if (isSlide) { - _observerController.jumpTo( + _itemScrollController.jumpTo( index: index, ); } else { animatePageTransitions - ? _observerController.animateTo( + ? _itemScrollController.scrollTo( curve: Curves.ease, index: index, duration: const Duration(milliseconds: 150)) - : _observerController.jumpTo( + : _itemScrollController.jumpTo( index: index, ); } } else { if (_extendedController.hasClients) { - setState(() { - _isZoom = false; - }); if (isSlide) { - _observerController.jumpTo( + _itemScrollController.jumpTo( index: index, ); } else { @@ -395,7 +437,7 @@ class _MangaChapterPageGalleryState } late final _extendedController = ExtendedPageController( - initialPage: _currentIndex ?? 0, + initialPage: _currentIndex!, shouldIgnorePointerWhenScrolling: false, ); @@ -472,7 +514,7 @@ class _MangaChapterPageGalleryState _isReversHorizontal = false; }); await Future.delayed(const Duration(milliseconds: 30)); - _observerController.animateTo( + _itemScrollController.scrollTo( index: _currentIndex!, duration: const Duration(milliseconds: 1), curve: Curves.ease); @@ -491,11 +533,11 @@ class _MangaChapterPageGalleryState mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ AnimatedContainer( - height: _isView ? Platform.isIOS?120:80 : 0, + height: _isView ? 80 : 0, curve: Curves.ease, duration: const Duration(milliseconds: 200), child: PreferredSize( - preferredSize: Size.fromHeight(_isView ?Platform.isIOS?120: 80 : 0), + preferredSize: Size.fromHeight(_isView ? 80 : 0), child: AppBar( centerTitle: false, automaticallyImplyLeading: false, @@ -995,13 +1037,11 @@ class _MangaChapterPageGalleryState ); } - bool _isZoom = false; bool _isVerticalContinous() { return _selectedValue == ReaderMode.verticalContinuous || _selectedValue == ReaderMode.webtoon; } - late int? _chapterId = widget.chapter.id; final StreamController _rebuildDetail = StreamController.broadcast(); final Map detailKeys = {}; @@ -1029,329 +1069,236 @@ class _MangaChapterPageGalleryState if (notification.direction == ScrollDirection.idle) { _readerController.setMangaHistoryUpdate(); _readerController - .setPageIndex(_uChapDataPreload[_currentIndex ?? 0].index!); + .setPageIndex(_uChapDataPreload[_currentIndex!].index!); + _isBookmarked = _readerController.getChapterBookmarked(); } return true; }, - child: StreamBuilder( - stream: - isar.chapters.watchObject(_chapterId!, fireImmediately: true), - builder: (context, snapshot) { - final chapterData = snapshot.hasData && snapshot.data != null - ? snapshot.data - : chapter; - if (chapterData != null) { - _readerController = ReaderController(chapter: chapterData); - _isBookmarked = chapterData.isBookmarked!; - } - return Stack( - children: [ - _isVerticalContinous() - ? PhotoViewGallery.builder( - itemCount: 1, - builder: (_, __) => - PhotoViewGalleryPageOptions.customChild( - controller: _photoViewController, - scaleStateController: - _photoViewScaleStateController, - basePosition: _scalePosition, - onScaleEnd: _onScaleEnd, - child: ListViewObserver( - controller: _observerController, - onObserve: (result) { - _currentIndex = result.firstChild?.index ?? 0; - - if (_chapterId != - _uChapDataPreload[_currentIndex ?? 0] - .chapter! - .id) { - if (mounted) { - setState(() { - _chapterUrlModel = - _uChapDataPreload[_currentIndex ?? 0] - .chapterUrlModel!; - _chapterId = - _uChapDataPreload[_currentIndex ?? 0] - .chapter! - .id; - }); - } - } - ref - .read( - currentIndexProvider(chapter).notifier) - .setCurrentIndex( - _uChapDataPreload[_currentIndex ?? 0] - .index!, - ); - }, - child: ListView.separated( - cacheExtent: 15 * mediaHeight(context, 1), - itemCount: _uChapDataPreload.length, - controller: _scrollController, - itemBuilder: (context, index) { - _scrollController.addListener(() { - if (_scrollController.position.pixels == - _scrollController - .position.maxScrollExtent) { - try { - bool hasNextChapter = _readerController - .getChapterIndex() != - 0; - final chapter = hasNextChapter - ? _readerController.getNextChapter() - : null; - if (chapter != null) { - ref - .watch(getChapterUrlProvider( - chapter: chapter, - ).future) - .then((value) { - _preloadNextChapter(value, chapter); - }); - } - } catch (_) {} - } - }); - - return GestureDetector( - behavior: HitTestBehavior.translucent, - onDoubleTapDown: (TapDownDetails details) { - _toggleScale(details.globalPosition); - }, - onDoubleTap: () {}, - child: ImageViewVertical( - archiveImage: - _cropImagesList.isNotEmpty && - cropBorders == true - ? _cropImagesList[index] - : _uChapDataPreload[index] - .archiveImage, - titleManga: - _readerController.getMangaName(), - source: _readerController.getSourceName(), - index: _uChapDataPreload[index].index!, - url: _uChapDataPreload[index].url!, - path: _uChapDataPreload[index].path!, - chapter: - _readerController.getChapterTitle(), - length: _readerController.getPageLength( - _chapterUrlModel.pageUrls), - isLocale: _cropImagesList.isNotEmpty && - cropBorders == true - ? true - : _uChapDataPreload[index].isLocale!, - lang: _uChapDataPreload[index] - .chapter! - .manga - .value! - .lang!, - ), - ); - }, - separatorBuilder: (_, __) => Divider( - color: Colors.black, - height: _selectedValue == ReaderMode.webtoon - ? 0 - : 6), - ), + child: Stack( + children: [ + _isVerticalContinous() + ? PhotoViewGallery.builder( + itemCount: 1, + builder: (_, __) => PhotoViewGalleryPageOptions.customChild( + controller: _photoViewController, + scaleStateController: _photoViewScaleStateController, + basePosition: _scalePosition, + onScaleEnd: _onScaleEnd, + child: ScrollablePositionedList.separated( + // scrollOffsetController: _scrollController, + physics: const ClampingScrollPhysics(), + minCacheExtent: 15 * mediaHeight(context, 1), + initialScrollIndex: _currentIndex!, + itemCount: _uChapDataPreload.length, + itemScrollController: _itemScrollController, + itemPositionsListener: _itemPositionsListener, + itemBuilder: (context, index) { + return GestureDetector( + behavior: HitTestBehavior.translucent, + onDoubleTapDown: (TapDownDetails details) { + _toggleScale(details.globalPosition); + }, + onDoubleTap: () {}, + child: ImageViewVertical( + archiveImage: _cropImagesList.isNotEmpty && + cropBorders == true + ? _cropImagesList[index] + : _uChapDataPreload[index].archiveImage, + source: _readerController.getSourceName(), + index: _uChapDataPreload[index].index!, + url: _uChapDataPreload[index].url!, + path: _uChapDataPreload[index].path!, + isLocale: _cropImagesList.isNotEmpty && + cropBorders == true + ? true + : _uChapDataPreload[index].isLocale!, + lang: _uChapDataPreload[index] + .chapter! + .manga + .value! + .lang!, ), - ), - ) - : Material( - color: Colors.black, - shadowColor: Colors.black, - child: ExtendedImageGesturePageView.builder( - controller: _extendedController, - scrollDirection: _scrollDirection, - reverse: _isReversHorizontal, - physics: const ClampingScrollPhysics(), - preloadPagesCount: _isZoom ? 0 : 6, - canScrollPage: (GestureDetails? gestureDetails) { - return gestureDetails != null - ? !(gestureDetails.totalScale! > 1.0) - : true; - }, - itemBuilder: (BuildContext context, int index) { - return ImageViewCenter( - archiveImage: _cropImagesList.isNotEmpty && - cropBorders == true - ? _cropImagesList[index] - : _uChapDataPreload[index].archiveImage, - titleManga: _readerController.getMangaName(), - source: _readerController.getSourceName(), - index: _uChapDataPreload[index].index!, - url: _uChapDataPreload[index].url!, - path: _uChapDataPreload[index].path!, - chapter: _readerController.getChapterTitle(), - length: _readerController - .getPageLength(_chapterUrlModel.pageUrls), - loadStateChanged: (ExtendedImageState state) { - if (state.extendedImageLoadState == - LoadState.loading) { - final ImageChunkEvent? loadingProgress = - state.loadingProgress; - final double progress = - loadingProgress?.expectedTotalBytes != - null - ? loadingProgress! - .cumulativeBytesLoaded / - loadingProgress - .expectedTotalBytes! - : 0; - return Container( - color: Colors.black, - height: mediaHeight(context, 0.8), - child: - CircularProgressIndicatorAnimateRotate( - progress: progress), - ); - } - if (state.extendedImageLoadState == - LoadState.completed) { - return StreamBuilder( - builder: (BuildContext context, - AsyncSnapshot data) { - return ExtendedImageGesture( - state, - canScaleImage: (_) => - _imageDetailY == 0, - imageBuilder: (Widget image) { - return Stack( - children: [ - Positioned.fill( - top: _imageDetailY, - bottom: -_imageDetailY, - child: image, - ), - ], - ); - }, - ); - }, - initialData: _imageDetailY, - stream: _rebuildDetail.stream, - ); - } - if (state.extendedImageLoadState == - LoadState.failed) { - return Container( - color: Colors.black, - height: mediaHeight(context, 0.8), - child: Column( - mainAxisAlignment: - MainAxisAlignment.center, - children: [ - ElevatedButton( - onPressed: () { - state.reLoadImage(); - }, - child: const Icon( - Icons.replay_outlined, - size: 30, - )), - ], - )); - } - return Container(); - }, - initGestureConfigHandler: - (ExtendedImageState state) { - double? initialScale = 1.0; - final size = MediaQuery.of(context).size; - if (state.extendedImageInfo != null) { - initialScale = initScale( - size: size, - initialScale: initialScale, - imageSize: Size( - state.extendedImageInfo!.image - .width - .toDouble(), - state.extendedImageInfo!.image - .height - .toDouble())); - } - return GestureConfig( - inertialSpeed: 200, - inPageView: true, - initialScale: initialScale!, - maxScale: 8, - animationMaxScale: 8, - initialAlignment: InitialAlignment.center, - cacheGesture: true, - hitTestBehavior: - HitTestBehavior.translucent, + ); + }, + separatorBuilder: (_, __) => Divider( + color: Colors.black, + height: + _selectedValue == ReaderMode.webtoon ? 0 : 6), + ), + ), + ) + : Material( + color: Colors.black, + shadowColor: Colors.black, + child: ExtendedImageGesturePageView.builder( + controller: _extendedController, + scrollDirection: _scrollDirection, + reverse: _isReversHorizontal, + physics: const ClampingScrollPhysics(), + canScrollPage: (GestureDetails? gestureDetails) { + return gestureDetails != null + ? !(gestureDetails.totalScale! > 1.0) + : true; + }, + itemBuilder: (BuildContext context, int index) { + return ImageViewCenter( + archiveImage: _cropImagesList.isNotEmpty && + cropBorders == true + ? _cropImagesList[index] + : _uChapDataPreload[index].archiveImage, + source: _readerController.getSourceName(), + index: _uChapDataPreload[index].index!, + url: _uChapDataPreload[index].url!, + path: _uChapDataPreload[index].path!, + loadStateChanged: (ExtendedImageState state) { + if (state.extendedImageLoadState == + LoadState.loading) { + final ImageChunkEvent? loadingProgress = + state.loadingProgress; + final double progress = + loadingProgress?.expectedTotalBytes != null + ? loadingProgress! + .cumulativeBytesLoaded / + loadingProgress.expectedTotalBytes! + : 0; + return Container( + color: Colors.black, + height: mediaHeight(context, 0.8), + child: CircularProgressIndicatorAnimateRotate( + progress: progress), + ); + } + if (state.extendedImageLoadState == + LoadState.completed) { + return StreamBuilder( + builder: (BuildContext context, + AsyncSnapshot data) { + return ExtendedImageGesture( + state, + canScaleImage: (_) => _imageDetailY == 0, + imageBuilder: (Widget image) { + return Stack( + children: [ + Positioned.fill( + top: _imageDetailY, + bottom: -_imageDetailY, + child: image, + ), + ], + ); + }, ); }, - onDoubleTap: - (ExtendedImageGestureState state) { - final Offset? pointerDownPosition = - state.pointerDownPosition; - final double? begin = - state.gestureDetails!.totalScale; - double end; - - //remove old - _doubleClickAnimation?.removeListener( - _doubleClickAnimationListener); - - //stop pre - _doubleClickAnimationController.stop(); - - //reset to use - _doubleClickAnimationController.reset(); - - if (begin == doubleTapScales[0]) { - setState(() { - _isZoom = true; - }); - end = doubleTapScales[1]; - } else { - setState(() { - _isZoom = false; - }); - end = doubleTapScales[0]; - } - - _doubleClickAnimationListener = () { - state.handleDoubleTap( - scale: _doubleClickAnimation!.value, - doubleTapPosition: - pointerDownPosition); - }; - - _doubleClickAnimation = Tween( - begin: begin, end: end) - .animate(CurvedAnimation( - curve: Curves.ease, - parent: - _doubleClickAnimationController)); - - _doubleClickAnimation!.addListener( - _doubleClickAnimationListener); - - _doubleClickAnimationController.forward(); - }, - isLocale: _cropImagesList.isNotEmpty && - cropBorders == true - ? true - : _uChapDataPreload[index].isLocale!, - lang: _uChapDataPreload[index] - .chapter! - .manga - .value! - .lang!, + initialData: _imageDetailY, + stream: _rebuildDetail.stream, ); - }, - itemCount: _uChapDataPreload.length, - onPageChanged: _onPageChanged)), - _gestureRightLeft(), - _gestureTopBottom(), - _showMore(), - _showPage(), - ], - ); - }), + } + if (state.extendedImageLoadState == + LoadState.failed) { + return Container( + color: Colors.black, + height: mediaHeight(context, 0.8), + child: Column( + mainAxisAlignment: + MainAxisAlignment.center, + children: [ + ElevatedButton( + onPressed: () { + state.reLoadImage(); + }, + child: const Icon( + Icons.replay_outlined, + size: 30, + )), + ], + )); + } + return Container(); + }, + initGestureConfigHandler: + (ExtendedImageState state) { + double? initialScale = 1.0; + final size = MediaQuery.of(context).size; + if (state.extendedImageInfo != null) { + initialScale = initScale( + size: size, + initialScale: initialScale, + imageSize: Size( + state.extendedImageInfo!.image.width + .toDouble(), + state.extendedImageInfo!.image.height + .toDouble())); + } + return GestureConfig( + inertialSpeed: 200, + inPageView: true, + initialScale: initialScale!, + maxScale: 8, + animationMaxScale: 8, + initialAlignment: InitialAlignment.center, + cacheGesture: true, + hitTestBehavior: HitTestBehavior.translucent, + ); + }, + onDoubleTap: (ExtendedImageGestureState state) { + final Offset? pointerDownPosition = + state.pointerDownPosition; + final double? begin = + state.gestureDetails!.totalScale; + double end; + + //remove old + _doubleClickAnimation?.removeListener( + _doubleClickAnimationListener); + + //stop pre + _doubleClickAnimationController.stop(); + + //reset to use + _doubleClickAnimationController.reset(); + + if (begin == doubleTapScales[0]) { + end = doubleTapScales[1]; + } else { + end = doubleTapScales[0]; + } + + _doubleClickAnimationListener = () { + state.handleDoubleTap( + scale: _doubleClickAnimation!.value, + doubleTapPosition: pointerDownPosition); + }; + + _doubleClickAnimation = Tween( + begin: begin, end: end) + .animate(CurvedAnimation( + curve: Curves.ease, + parent: _doubleClickAnimationController)); + + _doubleClickAnimation! + .addListener(_doubleClickAnimationListener); + + _doubleClickAnimationController.forward(); + }, + isLocale: _cropImagesList.isNotEmpty && + cropBorders == true + ? true + : _uChapDataPreload[index].isLocale!, + lang: _uChapDataPreload[index] + .chapter! + .manga + .value! + .lang!, + ); + }, + itemCount: _uChapDataPreload.length, + onPageChanged: _onPageChanged)), + _gestureRightLeft(), + _gestureTopBottom(), + _showMore(), + _showPage(), + ], + ), ), ); } @@ -1361,14 +1308,10 @@ class _MangaChapterPageGalleryState context, DraggableMenu( ui: ClassicDraggableMenu(barItem: Container()), - levels: [ - DraggableMenuLevel.ratio(ratio: 0.4), - ], fastDrag: false, minimizeBeforeFastDrag: false, child: StatefulBuilder( builder: (context, setState) { - final l10n = l10nLocalizations(context)!; return Scaffold( body: Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -1376,11 +1319,11 @@ class _MangaChapterPageGalleryState const SizedBox( height: 10, ), - Padding( - padding: const EdgeInsets.all(8.0), + const Padding( + padding: EdgeInsets.all(8.0), child: Text( - l10n.settings, - style: const TextStyle( + 'Settings', + style: TextStyle( fontSize: 17, fontWeight: FontWeight.bold), ), ), @@ -1391,7 +1334,7 @@ class _MangaChapterPageGalleryState children: [ SwitchListTile( dense: true, - title: Text(l10n.show_page_number), + title: const Text('Show Page Number'), value: _showPagesNumber, onChanged: (value) { setState(() { @@ -1412,14 +1355,14 @@ class _MangaChapterPageGalleryState } class UChapDataPreload { - Chapter? chapter; - Directory? path; - String? url; - bool? isLocale; - Uint8List? archiveImage; - int? index; - GetChapterUrlModel? chapterUrlModel; - int? pageIndex; + final Chapter? chapter; + final Directory? path; + final String? url; + final bool? isLocale; + final Uint8List? archiveImage; + final int? index; + final GetChapterUrlModel? chapterUrlModel; + final int? pageIndex; UChapDataPreload( this.chapter, this.path, diff --git a/pubspec.lock b/pubspec.lock index 8c774e7..f903053 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -5,18 +5,18 @@ packages: dependency: transitive description: name: _fe_analyzer_shared - sha256: "405666cd3cf0ee0a48d21ec67e65406aad2c726d9fa58840d3375e7bdcd32a07" + sha256: ae92f5d747aee634b87f89d9946000c2de774be1d6ac3e58268224348cd0101a url: "https://pub.dev" source: hosted - version: "60.0.0" + version: "61.0.0" analyzer: dependency: transitive description: name: analyzer - sha256: "1952250bd005bacb895a01bf1b4dc00e3ba1c526cf47dca54dfe24979c65f5b3" + sha256: ea3d8652bda62982addfd92fdc2d0214e5f82e43325104990d4f4c4a2a313562 url: "https://pub.dev" source: hosted - version: "5.12.0" + version: "5.13.0" analyzer_plugin: dependency: transitive description: @@ -69,10 +69,10 @@ packages: dependency: "direct main" description: name: background_downloader - sha256: dca018b102a8c5efb09aadf587c07729d6cb2c9840e471e725c746c2195a1cd3 + sha256: "8edf16baa5fceb31cf103f6113ee01c0cbef17cdd8aabf6152fa0b1b89f6543b" url: "https://pub.dev" source: hosted - version: "7.9.0" + version: "7.9.1" boolean_selector: dependency: transitive description: @@ -229,10 +229,10 @@ packages: dependency: transitive description: name: collection - sha256: "4a07be6cb69c84d677a6c3096fcf960cc3285a8330b4603e0d463d15d9bd934c" + sha256: f092b211a4319e98e5ff58223576de6c2803db36221657b46c82574721240687 url: "https://pub.dev" source: hosted - version: "1.17.1" + version: "1.17.2" convert: dependency: transitive description: @@ -277,18 +277,18 @@ packages: dependency: transitive description: name: custom_lint - sha256: "3ce36c04d30c60cde295588c6185b3f9800e6c18f6670a7ffdb3d5eab39bb942" + sha256: ae3cf0f83a155bdfc50315d4a11c7b358ea1e201a57ab0bb2b397f1a9a2a9b80 url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.5.2" custom_lint_core: dependency: transitive description: name: custom_lint_core - sha256: "9170d9db2daf774aa2251a3bc98e4ba903c7702ab07aa438bc83bd3c9a0de57f" + sha256: a420aa57121a22b2a42e7e1dbbcaf7b91ef73b90adce07149419c16cf67d6fcc url: "https://pub.dev" source: hosted - version: "0.4.0" + version: "0.5.2" dart_eval: dependency: "direct main" description: @@ -389,18 +389,18 @@ packages: dependency: "direct main" description: name: extended_image - sha256: e77d18f956649ba6e5ecebd0cb68542120886336a75ee673788145bd4c3f0767 + sha256: d1b122d6f5cf5596ea61d703d116d89e2ece7e324db414cfeed12967b72b7aef url: "https://pub.dev" source: hosted - version: "8.0.2" + version: "8.1.0" extended_image_library: dependency: transitive description: name: extended_image_library - sha256: bb8d08c504ebc73d476ec1c99451a61f12e95538869e734fc4f55a3a2d5c98ec + sha256: "8bf87c0b14dcb59200c923a9a3952304e4732a0901e40811428834ef39018ee1" url: "https://pub.dev" source: hosted - version: "3.5.3" + version: "3.6.0" fake_async: dependency: transitive description: @@ -413,10 +413,10 @@ packages: dependency: transitive description: name: ffi - sha256: ed5337a5660c506388a9f012be0288fb38b49020ce2b45fe1f8b8323fe429f99 + sha256: "7bf0adc28a23d395f19f3f1eb21dd7cfd1dd9f8e1c50051c069122e6853bc878" url: "https://pub.dev" source: hosted - version: "2.0.2" + version: "2.1.0" file: dependency: transitive description: @@ -445,10 +445,10 @@ packages: dependency: "direct main" description: name: flex_color_scheme - sha256: "659cf59bd5ccaa1e7de9384342be8b666ff10b108ed57a7fd46c122fb8bf6aca" + sha256: "57feb7e5b783e843a43e7d2713b0b0a58941ac3abc0439501290661cad4183a5" url: "https://pub.dev" source: hosted - version: "7.2.0" + version: "7.3.0" flex_seed_scheme: dependency: transitive description: @@ -519,10 +519,10 @@ packages: dependency: "direct main" description: name: flutter_meedu_videoplayer - sha256: "5d687cca1681041b1ca078de3abd677b4e97d9a5b141009963927c43438b7ad9" + sha256: "8f4880ac0dbe1662ea8d0d03e35c86ea5696651600b59e9005f5607fbb9a8b6f" url: "https://pub.dev" source: hosted - version: "4.2.22" + version: "4.2.24" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -535,10 +535,10 @@ packages: dependency: "direct main" description: name: flutter_riverpod - sha256: b83ac5827baadefd331ea1d85110f34645827ea234ccabf53a655f41901a9bf4 + sha256: b6cb0041c6c11cefb2dcb97ef436eba43c6d41287ac6d8ca93e02a497f53a4f3 url: "https://pub.dev" source: hosted - version: "2.3.6" + version: "2.3.7" flutter_spinkit: dependency: transitive description: @@ -705,10 +705,10 @@ packages: dependency: "direct main" description: name: intl - sha256: a3715e3bc90294e971cb7dc063fbf3cd9ee0ebf8604ffeafabd9e6f16abbdbe6 + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" url: "https://pub.dev" source: hosted - version: "0.18.0" + version: "0.18.1" io: dependency: transitive description: @@ -809,18 +809,18 @@ packages: dependency: transitive description: name: matcher - sha256: "6501fbd55da300384b768785b83e5ce66991266cec21af89ab9ae7f5ce1c4cbb" + sha256: "1803e76e6653768d64ed8ff2e1e67bea3ad4b923eb5c56a295c3e634bad5960e" url: "https://pub.dev" source: hosted - version: "0.12.15" + version: "0.12.16" material_color_utilities: dependency: transitive description: name: material_color_utilities - sha256: d92141dc6fe1dad30722f9aa826c7fbc896d021d792f80678280601aff8cf724 + sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" url: "https://pub.dev" source: hosted - version: "0.2.0" + version: "0.5.0" maybe_just_nothing: dependency: transitive description: @@ -833,50 +833,50 @@ packages: dependency: transitive description: name: media_kit - sha256: eb47c2d51b7c06b319d8c776b47be912c5a4f53af7ab4814927a52a76442609e + sha256: "0a89e7037002a62701ec319c375586849f9ef8e681820e1dd4a4ff7b843f7542" url: "https://pub.dev" source: hosted - version: "1.1.2+1" + version: "1.1.4+1" media_kit_libs_android_video: dependency: "direct main" description: name: media_kit_libs_android_video - sha256: ddb0d26ecba72bf7117e37e29b6a50f4ba198bbccb4e47246cae1812087dc721 + sha256: "142d389bf3efcf8469594a9c7a06a92fc25843fc6c0c3247f76cdcf70b3b29de" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.3.2" media_kit_libs_ios_video: dependency: "direct main" description: name: media_kit_libs_ios_video - sha256: b65d1f22442e6074948f501e7156c310fbf133cd63aa914c84d0d4db1c683ee0 + sha256: fed403dc9d54462e51ee80e0cb23c12a53fadea9a8fa18aca2de9054176d1159 url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.3" media_kit_libs_linux: dependency: transitive description: name: media_kit_libs_linux - sha256: "838b9e8041d376873cc938872c75812989d0feb247ad93afd8dbc92bf052680a" + sha256: "570bf18ebbd1221caec082657468be05d180510385d3515ec38e0be44fdcc859" url: "https://pub.dev" source: hosted - version: "1.1.0" + version: "1.1.1" media_kit_libs_macos_video: dependency: transitive description: name: media_kit_libs_macos_video - sha256: dcabf2731b6b7dee143c18617fd32a063146303e7388f87dd4e974e03c9c795a + sha256: c06e831f3c22a45296d375788d9bc07871b448f8e9ec98d77b11e5e118a83fb2 url: "https://pub.dev" source: hosted - version: "1.1.1" + version: "1.1.3" media_kit_libs_windows_video: dependency: transitive description: name: media_kit_libs_windows_video - sha256: b343e644927982a2ef3db63877b36d84bdda8173d8318ca0d1c68c1ea8a35982 + sha256: f33aabd8414470d99e2c91dd98d605e6a5f1c4b8082dd933c10951bc961b9124 url: "https://pub.dev" source: hosted - version: "1.0.5" + version: "1.0.7" media_kit_native_event_loop: dependency: transitive description: @@ -889,10 +889,10 @@ packages: dependency: transitive description: name: media_kit_video - sha256: "4b627683ef9e7f5cd049fd01be4b5deb5f31effc878503f108c81b19fd745040" + sha256: e7fcbe426d42a78ad6696f8f557adb9cbdc012177829026d04992cc106a1c815 url: "https://pub.dev" source: hosted - version: "1.1.2" + version: "1.1.5" meedu: dependency: transitive description: @@ -969,10 +969,10 @@ packages: dependency: "direct main" description: name: path_provider - sha256: "3087813781ab814e4157b172f1a11c46be20179fcc9bea043e0fba36bc0acaa2" + sha256: "909b84830485dbcd0308edf6f7368bc8fd76afa26a270420f34cabea2a6467a0" url: "https://pub.dev" source: hosted - version: "2.0.15" + version: "2.1.0" path_provider_android: dependency: transitive description: @@ -1073,10 +1073,10 @@ packages: dependency: transitive description: name: platform - sha256: "4a451831508d7d6ca779f7ac6e212b4023dd5a7d08a27a63da33756410e32b76" + sha256: "57c07bf82207aee366dfaa3867b3164e4f03a238a461a11b0e8a3a510d51203d" url: "https://pub.dev" source: hosted - version: "3.1.0" + version: "3.1.1" plugin_platform_interface: dependency: transitive description: @@ -1153,34 +1153,34 @@ packages: dependency: transitive description: name: riverpod - sha256: "80e48bebc83010d5e67a11c9514af6b44bbac1ec77b4333c8ea65dbc79e2d8ef" + sha256: b0657b5b30c81a3184bdaab353045f0a403ebd60bb381591a8b7ad77dcade793 url: "https://pub.dev" source: hosted - version: "2.3.6" + version: "2.3.7" riverpod_analyzer_utils: dependency: transitive description: name: riverpod_analyzer_utils - sha256: "1b2632a6fc0b659c923a4dcc7cd5da42476f5b3294c70c86c971e63bdd443384" + sha256: aa216069d72f5478126029fa555874b4b38119f17e3f0f6c93fd63365f74502d url: "https://pub.dev" source: hosted - version: "0.3.1" + version: "0.3.3" riverpod_annotation: dependency: "direct main" description: name: riverpod_annotation - sha256: cedd6a54b6f5764ffd5c05df57b6676bfc8c01978e14ee60a2c16891038820fe + sha256: "8b3f7a54ddd5d53d6ea04bfb4ff77ee1b0816a1b563c0d9d43e73ce94bf2016d" url: "https://pub.dev" source: hosted - version: "2.1.1" + version: "2.1.2" riverpod_generator: dependency: "direct dev" description: name: riverpod_generator - sha256: "691180275664a5420c87d72c1ed26ef8404d32b823807540172bfd1660425376" + sha256: f668015d7b719c413c6001d4790689ea4a7bf76d5109118a1a98d5c23b20160d url: "https://pub.dev" source: hosted - version: "2.2.4" + version: "2.2.6" rxdart: dependency: transitive description: @@ -1253,14 +1253,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.1.6" - scrollview_observer: + scrollable_positioned_list: dependency: "direct main" description: - name: scrollview_observer - sha256: "6bdd5c0a38690f0f0fcb9a839db9f404a5f10c9c002f6592ca33056c4a7c886c" + name: scrollable_positioned_list + sha256: "1b54d5f1329a1e263269abc9e2543d90806131aa14fe7c6062a8054d57249287" url: "https://pub.dev" source: hosted - version: "1.15.0" + version: "0.3.8" share_plus: dependency: "direct main" description: @@ -1297,10 +1297,10 @@ packages: dependency: transitive description: name: shared_preferences_foundation - sha256: f39696b83e844923b642ce9dd4bd31736c17e697f6731a5adf445b1274cf3cd4 + sha256: d29753996d8eb8f7619a1f13df6ce65e34bc107bef6330739ed76f18b22310ef url: "https://pub.dev" source: hosted - version: "2.3.2" + version: "2.3.3" shared_preferences_linux: dependency: transitive description: @@ -1366,10 +1366,10 @@ packages: dependency: transitive description: name: source_span - sha256: dd904f795d4b4f3b870833847c461801f6750a9fa8e61ea5ac53f9422b31f250 + sha256: "53e943d4206a5e30df338fd4c6e7a077e02254531b138a15aec3bd143c1a8b3c" url: "https://pub.dev" source: hosted - version: "1.9.1" + version: "1.10.0" sqflite: dependency: transitive description: @@ -1398,10 +1398,10 @@ packages: dependency: transitive description: name: state_notifier - sha256: "8fe42610f179b843b12371e40db58c9444f8757f8b69d181c97e50787caed289" + sha256: b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb url: "https://pub.dev" source: hosted - version: "0.7.2+1" + version: "1.0.0" stream_channel: dependency: transitive description: @@ -1446,10 +1446,10 @@ packages: dependency: transitive description: name: test_api - sha256: eb6ac1540b26de412b3403a163d919ba86f6a973fe6cc50ae3541b80092fdcfb + sha256: "75760ffd7786fffdfb9597c35c5b27eaeec82be8edfb6d71d32651128ed7aab8" url: "https://pub.dev" source: hosted - version: "0.5.1" + version: "0.6.0" time: dependency: transitive description: @@ -1502,10 +1502,10 @@ packages: dependency: transitive description: name: url_launcher_android - sha256: "78cb6dea3e93148615109e58e42c35d1ffbf5ef66c44add673d0ab75f12ff3af" + sha256: "3dd2388cc0c42912eee04434531a26a82512b9cb1827e0214430c9bcbddfe025" url: "https://pub.dev" source: hosted - version: "6.0.37" + version: "6.0.38" url_launcher_ios: dependency: transitive description: @@ -1598,10 +1598,10 @@ packages: dependency: transitive description: name: video_player_media_kit - sha256: "7472fca414cfe372560d9328a3da9e57d9ba1de4af7ed8d887ce6a9868dc2430" + sha256: "5f52455b3dc7df286a50b40629e7662e87a1c4bf282fa771d10223618a7fac8b" url: "https://pub.dev" source: hosted - version: "0.0.22" + version: "0.0.23" video_player_platform_interface: dependency: transitive description: @@ -1650,6 +1650,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.1.0" + web: + dependency: transitive + description: + name: web + sha256: dc8ccd225a2005c1be616fe02951e2e342092edf968cf0844220383757ef8f10 + url: "https://pub.dev" + source: hosted + version: "0.1.4-beta" web_socket_channel: dependency: transitive description: @@ -1686,10 +1694,10 @@ packages: dependency: transitive description: name: xdg_directories - sha256: e0b1147eec179d3911f1f19b59206448f78195ca1d20514134e10641b7d7fbff + sha256: f0c26453a2d47aa4c2570c6a033246a3fc62da2fe23c7ffdd0a7495086dc0247 url: "https://pub.dev" source: hosted - version: "1.0.1" + version: "1.0.2" xml: dependency: transitive description: @@ -1731,5 +1739,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.0.6 <4.0.0" - flutter: ">=3.10.0" + dart: ">=3.1.0 <4.0.0" + flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index f9a267f..b512be5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -4,7 +4,7 @@ description: Free and open source manga reader multi plateform app inspired by T version: 0.0.26+7 environment: - sdk: '>=3.0.6 <4.0.0' + sdk: '>=3.1.0 <4.0.0' dependencies: @@ -13,46 +13,46 @@ dependencies: flutter_localizations: sdk: flutter go_router: ^10.0.0 - flutter_riverpod: ^2.3.6 + flutter_riverpod: ^2.3.7 cached_network_image: ^3.2.3 http: ^1.1.0 - riverpod_annotation: ^2.1.1 + riverpod_annotation: ^2.1.2 html: ^0.15.4 # flutter_js: ^0.8.0 font_awesome_flutter: ^10.5.0 expandable_text: ^2.3.0 - flex_color_scheme: ^7.2.0 - extended_image: ^8.0.2 + flex_color_scheme: ^7.3.0 + extended_image: ^8.1.0 photo_view: ^0.14.0 draggable_scrollbar: ^0.1.0 grouped_list: ^5.1.2 intl: ^0.18.0 google_fonts: ^5.1.0 url_launcher: ^6.1.12 - package_info_plus: ^4.0.2 - background_downloader: ^7.8.1 + package_info_plus: ^4.1.0 + background_downloader: ^7.9.1 permission_handler: ^10.4.3 flutter_inappwebview: ^5.7.2+3 draggable_menu: ^4.1.3 isar: 3.1.0+1 isar_flutter_libs: 3.1.0+1 - share_plus: ^7.0.2 + share_plus: ^7.1.0 xpath_selector_html_parser: ^3.0.1 - desktop_webview_window: ^0.2.0 + desktop_webview_window: ^0.2.1 archive: ^3.3.7 file_picker: ^5.3.3 - path_provider: ^2.0.15 + path_provider: ^2.1.0 # image: ^3.3.0 - scrollview_observer: ^1.15.0 + scrollable_positioned_list: ^0.3.5 dart_eval: ^0.6.0 json_path: ^0.6.2 bot_toast: ^4.0.4 flutter_web_auth_2: ^2.1.5 numberpicker: ^2.1.2 encrypt: ^5.0.1 - flutter_meedu_videoplayer: ^4.2.22 - media_kit_libs_android_video: ^1.3.0 - media_kit_libs_ios_video: ^1.1.1 + flutter_meedu_videoplayer: ^4.2.24 + media_kit_libs_android_video: ^1.3.2 + media_kit_libs_ios_video: ^1.1.3 js_packer: ^0.0.5 diff --git a/windows/runner/flutter_window.cpp b/windows/runner/flutter_window.cpp index b25e363..955ee30 100644 --- a/windows/runner/flutter_window.cpp +++ b/windows/runner/flutter_window.cpp @@ -31,6 +31,11 @@ bool FlutterWindow::OnCreate() { this->Show(); }); + // Flutter can complete the first frame before the "show window" callback is + // registered. The following call ensures a frame is pending to ensure the + // window is shown. It is a no-op if the first frame hasn't completed yet. + flutter_controller_->ForceRedraw(); + return true; }