mirror of
https://github.com/kodjodevf/mangayomi.git
synced 2026-05-12 01:00:34 +00:00
feature: fix reader & add preloaded chapter
This commit is contained in:
parent
4fddc658a9
commit
4f68505a9b
13 changed files with 666 additions and 1848 deletions
|
|
@ -1,207 +0,0 @@
|
|||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mangayomi/modules/archive_reader/models/models.dart';
|
||||
import 'package:mangayomi/modules/archive_reader/providers/archive_reader_providers.dart';
|
||||
import 'package:mangayomi/modules/widgets/progress_center.dart';
|
||||
import 'package:mangayomi/utils/media_query.dart';
|
||||
|
||||
class LocalReaderScreen extends ConsumerStatefulWidget {
|
||||
const LocalReaderScreen({super.key});
|
||||
|
||||
@override
|
||||
ConsumerState createState() => _LocalReaderScreenState();
|
||||
}
|
||||
|
||||
class _LocalReaderScreenState extends ConsumerState<LocalReaderScreen> {
|
||||
List<LocalArchive> images = [];
|
||||
bool isLoading = false;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Stack(
|
||||
children: [
|
||||
Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text('Archive Reader'),
|
||||
),
|
||||
body: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
ElevatedButton.icon(
|
||||
onPressed: () async {
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
//File
|
||||
FilePickerResult? result = await FilePicker.platform
|
||||
.pickFiles(
|
||||
type: FileType.custom,
|
||||
allowedExtensions: [
|
||||
'cbz',
|
||||
'zip',
|
||||
'cbt',
|
||||
'tar'
|
||||
]);
|
||||
if (result != null) {
|
||||
//File
|
||||
final ddd = await ref.watch(
|
||||
getArchiveDataFromFileProvider(
|
||||
result.files.first.path!)
|
||||
.future);
|
||||
|
||||
setState(() {
|
||||
images.add(ddd);
|
||||
isLoading = false;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
label: const Text("Load cbz file"),
|
||||
icon: const Icon(Icons.archive_rounded)),
|
||||
ElevatedButton.icon(
|
||||
onPressed: () async {
|
||||
setState(() {
|
||||
isLoading = true;
|
||||
});
|
||||
//Directory
|
||||
String? result =
|
||||
await FilePicker.platform.getDirectoryPath();
|
||||
|
||||
if (result != null) {
|
||||
//Directory
|
||||
final ddd = await ref.watch(
|
||||
getArchiveDataFromDirectoryProvider(result)
|
||||
.future);
|
||||
setState(() {
|
||||
images = ddd;
|
||||
isLoading = false;
|
||||
});
|
||||
} else {
|
||||
setState(() {
|
||||
isLoading = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
label: const Text("Load from directory"),
|
||||
icon: const Icon(Icons.create_new_folder_rounded)),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: GridView.builder(
|
||||
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
|
||||
childAspectRatio: 0.68, crossAxisCount: 3),
|
||||
itemCount: images.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Material(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
clipBehavior: Clip.antiAliasWithSaveLayer,
|
||||
child: InkWell(
|
||||
onTap: () {
|
||||
context.push("/archiveReaderReaderView",
|
||||
extra: images[index]);
|
||||
},
|
||||
child: Ink.image(
|
||||
height: 200,
|
||||
fit: BoxFit.cover,
|
||||
image: MemoryImage(images[index].coverImage!),
|
||||
child: Container(
|
||||
height: 70,
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
Theme.of(context).scaffoldBackgroundColor,
|
||||
gradient: LinearGradient(
|
||||
begin: Alignment.topCenter,
|
||||
end: Alignment.bottomCenter,
|
||||
colors: [
|
||||
Colors.transparent,
|
||||
Colors.black.withOpacity(0.6)
|
||||
],
|
||||
stops: const [0, 1],
|
||||
),
|
||||
),
|
||||
child: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
bottom: 0,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
images[index].name!,
|
||||
style: const TextStyle(
|
||||
fontSize: 12,
|
||||
color: Colors.white,
|
||||
shadows: <Shadow>[
|
||||
Shadow(
|
||||
offset: Offset(0.5, 0.9),
|
||||
blurRadius: 3.0)
|
||||
],
|
||||
),
|
||||
maxLines: 2,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
textAlign: TextAlign.start,
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(5),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white,
|
||||
borderRadius:
|
||||
BorderRadius.circular(5)),
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(2),
|
||||
child: Text(
|
||||
getTypeExtension(images[index]
|
||||
.extensionType!)
|
||||
.toUpperCase(),
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 10),
|
||||
),
|
||||
)),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
if (isLoading)
|
||||
Container(
|
||||
width: mediaWidth(context, 1),
|
||||
height: mediaHeight(context, 1),
|
||||
color: Colors.black45,
|
||||
child: UnconstrainedBox(
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(20),
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
),
|
||||
height: 200,
|
||||
width: 200,
|
||||
child: const Center(child: ProgressCenter())),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,938 +0,0 @@
|
|||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
import 'package:draggable_menu/draggable_menu.dart';
|
||||
import 'package:extended_image/extended_image.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:mangayomi/main.dart';
|
||||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/modules/archive_reader/models/models.dart';
|
||||
import 'package:mangayomi/utils/image_detail_info.dart';
|
||||
import 'package:mangayomi/utils/media_query.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/widgets/circular_progress_indicator_animate_rotate.dart';
|
||||
import 'package:mangayomi/modules/more/settings/reader/reader_screen.dart';
|
||||
import 'package:photo_view/photo_view.dart';
|
||||
import 'package:photo_view/photo_view_gallery.dart';
|
||||
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
|
||||
|
||||
typedef DoubleClickAnimationListener = void Function();
|
||||
|
||||
class ArchiveReaderReaderView extends ConsumerWidget {
|
||||
final LocalArchive localArchive;
|
||||
const ArchiveReaderReaderView({
|
||||
super.key,
|
||||
required this.localArchive,
|
||||
});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky,
|
||||
overlays: []);
|
||||
|
||||
return MangaChapterPageGallery(localArchive: localArchive);
|
||||
}
|
||||
}
|
||||
|
||||
class MangaChapterPageGallery extends ConsumerStatefulWidget {
|
||||
const MangaChapterPageGallery({super.key, required this.localArchive});
|
||||
final LocalArchive localArchive;
|
||||
|
||||
@override
|
||||
ConsumerState createState() {
|
||||
return _MangaChapterPageGalleryState();
|
||||
}
|
||||
}
|
||||
|
||||
class _MangaChapterPageGalleryState
|
||||
extends ConsumerState<MangaChapterPageGallery>
|
||||
with TickerProviderStateMixin {
|
||||
late final ItemScrollController _itemScrollController =
|
||||
ItemScrollController();
|
||||
late AnimationController _scaleAnimationController;
|
||||
late Animation<double> _animation;
|
||||
late int _currentIndex = 0;
|
||||
@override
|
||||
void dispose() {
|
||||
_rebuildDetail.close();
|
||||
_doubleClickAnimationController.dispose();
|
||||
clearGestureDetailsCache();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
bool animatePageTransitions =
|
||||
isar.settings.getSync(227)!.animatePageTransitions!;
|
||||
Duration? _doubleTapAnimationDuration() {
|
||||
int doubleTapAnimationValue =
|
||||
isar.settings.getSync(227)!.doubleTapAnimationSpeed!;
|
||||
if (doubleTapAnimationValue == 0) {
|
||||
return const Duration(milliseconds: 10);
|
||||
} else if (doubleTapAnimationValue == 1) {
|
||||
return const Duration(milliseconds: 800);
|
||||
}
|
||||
return const Duration(milliseconds: 200);
|
||||
}
|
||||
|
||||
Future setIndex(int index) async {
|
||||
setState(() {
|
||||
_currentIndex = index;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_doubleClickAnimationController = AnimationController(
|
||||
duration: _doubleTapAnimationDuration(), vsync: this);
|
||||
|
||||
_scaleAnimationController = AnimationController(
|
||||
duration: _doubleTapAnimationDuration(), vsync: this);
|
||||
_animation = Tween(begin: 1.0, end: 2.0).animate(
|
||||
CurvedAnimation(curve: Curves.ease, parent: _scaleAnimationController));
|
||||
_animation.addListener(() => _photoViewController.scale = _animation.value);
|
||||
_initCurrentIndex();
|
||||
_itemPositionsListener.itemPositions.addListener(_readProgressListener);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
_readProgressListener() {
|
||||
var posIndex = _itemPositionsListener.itemPositions.value.first.index;
|
||||
if (posIndex >= 0 && posIndex < widget.localArchive.images!.length) {
|
||||
if (_currentIndex != posIndex) {
|
||||
setState(() {
|
||||
_currentIndex = posIndex;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_initCurrentIndex() async {
|
||||
await Future.delayed(const Duration(milliseconds: 1));
|
||||
_selectedValue = ReaderMode.vertical;
|
||||
_(_selectedValue!, true);
|
||||
}
|
||||
|
||||
void _onPageChanged(int index) {
|
||||
setState(() {
|
||||
_currentIndex = index;
|
||||
});
|
||||
if (_imageDetailY != 0) {
|
||||
_imageDetailY = 0;
|
||||
_rebuildDetail.sink.add(_imageDetailY);
|
||||
}
|
||||
}
|
||||
|
||||
void _onBtnTapped(int index, bool isPrev, {bool isSlide = false}) {
|
||||
if (isPrev) {
|
||||
if (_selectedValue == ReaderMode.verticalContinuous ||
|
||||
_selectedValue == ReaderMode.webtoon) {
|
||||
if (index != -1) {
|
||||
if (isSlide) {
|
||||
_itemScrollController.jumpTo(
|
||||
index: index,
|
||||
);
|
||||
} else {
|
||||
animatePageTransitions
|
||||
? _itemScrollController.scrollTo(
|
||||
curve: Curves.ease,
|
||||
index: index,
|
||||
duration: Duration(milliseconds: isSlide ? 2 : 150))
|
||||
: _itemScrollController.jumpTo(
|
||||
index: index,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (index != -1) {
|
||||
if (_extendedController.hasClients) {
|
||||
setState(() {
|
||||
_isZoom = false;
|
||||
});
|
||||
animatePageTransitions
|
||||
? _extendedController.animateToPage(index,
|
||||
duration: Duration(milliseconds: isSlide ? 2 : 150),
|
||||
curve: Curves.ease)
|
||||
: _extendedController.jumpToPage(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (_selectedValue == ReaderMode.verticalContinuous ||
|
||||
_selectedValue == ReaderMode.webtoon) {
|
||||
if (widget.localArchive.images!.length != index) {
|
||||
if (isSlide) {
|
||||
_itemScrollController.jumpTo(
|
||||
index: index,
|
||||
);
|
||||
} else {
|
||||
animatePageTransitions
|
||||
? _itemScrollController.scrollTo(
|
||||
curve: Curves.ease,
|
||||
index: index,
|
||||
duration: Duration(milliseconds: isSlide ? 2 : 150))
|
||||
: _itemScrollController.jumpTo(
|
||||
index: index,
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (widget.localArchive.images!.length != index) {
|
||||
if (_extendedController.hasClients) {
|
||||
setState(() {
|
||||
_isZoom = false;
|
||||
});
|
||||
animatePageTransitions
|
||||
? _extendedController.animateToPage(index,
|
||||
duration: Duration(milliseconds: isSlide ? 2 : 150),
|
||||
curve: Curves.ease)
|
||||
: _extendedController.jumpToPage(index);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReaderMode? _selectedValue;
|
||||
bool _isView = false;
|
||||
Alignment _scalePosition = Alignment.center;
|
||||
final PhotoViewController _photoViewController = PhotoViewController();
|
||||
final PhotoViewScaleStateController _photoViewScaleStateController =
|
||||
PhotoViewScaleStateController();
|
||||
|
||||
final ItemPositionsListener _itemPositionsListener =
|
||||
ItemPositionsListener.create();
|
||||
void _onScaleEnd(BuildContext context, ScaleEndDetails details,
|
||||
PhotoViewControllerValue controllerValue) {
|
||||
if (controllerValue.scale! < 1) {
|
||||
_photoViewScaleStateController.reset();
|
||||
}
|
||||
}
|
||||
|
||||
late final _extendedController = ExtendedPageController(
|
||||
initialPage: _currentIndex,
|
||||
shouldIgnorePointerWhenScrolling: false,
|
||||
);
|
||||
|
||||
double get pixelRatio => View.of(context).devicePixelRatio;
|
||||
|
||||
Size get size => View.of(context).physicalSize / pixelRatio;
|
||||
Alignment _computeAlignmentByTapOffset(Offset offset) {
|
||||
return Alignment((offset.dx - size.width / 2) / (size.width / 2),
|
||||
(offset.dy - size.height / 2) / (size.height / 2));
|
||||
}
|
||||
|
||||
void _toggleScale(Offset tapPosition) {
|
||||
setState(() {
|
||||
if (_scaleAnimationController.isAnimating) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (_photoViewController.scale == 1.0) {
|
||||
_scalePosition = _computeAlignmentByTapOffset(tapPosition);
|
||||
|
||||
if (_scaleAnimationController.isCompleted) {
|
||||
_scaleAnimationController.reset();
|
||||
}
|
||||
|
||||
_scaleAnimationController.forward();
|
||||
return;
|
||||
}
|
||||
|
||||
if (_photoViewController.scale == 2.0) {
|
||||
_scaleAnimationController.reverse();
|
||||
return;
|
||||
}
|
||||
|
||||
_photoViewScaleStateController.reset();
|
||||
});
|
||||
}
|
||||
|
||||
Axis _scrollDirection = Axis.vertical;
|
||||
bool _isReversHorizontal = false;
|
||||
|
||||
late bool _showPagesNumber = true;
|
||||
_(ReaderMode value, bool isInit) async {
|
||||
if (value == ReaderMode.vertical) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_selectedValue = value;
|
||||
_scrollDirection = Axis.vertical;
|
||||
_isReversHorizontal = false;
|
||||
});
|
||||
if (isInit) {
|
||||
await Future.delayed(const Duration(milliseconds: 30));
|
||||
}
|
||||
_extendedController.jumpToPage(_currentIndex);
|
||||
}
|
||||
} else if (value == ReaderMode.ltr || value == ReaderMode.rtl) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
if (value == ReaderMode.rtl) {
|
||||
_isReversHorizontal = true;
|
||||
} else {
|
||||
_isReversHorizontal = false;
|
||||
}
|
||||
_selectedValue = value;
|
||||
_scrollDirection = Axis.horizontal;
|
||||
});
|
||||
if (isInit) {
|
||||
await Future.delayed(const Duration(milliseconds: 30));
|
||||
}
|
||||
_extendedController.jumpToPage(_currentIndex);
|
||||
}
|
||||
} else {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_selectedValue = value;
|
||||
_isReversHorizontal = false;
|
||||
});
|
||||
if (isInit) {
|
||||
await Future.delayed(const Duration(milliseconds: 30));
|
||||
}
|
||||
_itemScrollController.scrollTo(
|
||||
index: _currentIndex, duration: const Duration(milliseconds: 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Color _backgroundColor(BuildContext context) =>
|
||||
Theme.of(context).scaffoldBackgroundColor.withOpacity(0.9);
|
||||
|
||||
Widget _showMore() {
|
||||
return Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final currentIndex = _currentIndex;
|
||||
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
AnimatedContainer(
|
||||
height: _isView ? 80 : 0,
|
||||
curve: Curves.ease,
|
||||
duration: const Duration(milliseconds: 200),
|
||||
child: PreferredSize(
|
||||
preferredSize: Size.fromHeight(_isView ? 80 : 0),
|
||||
child: AppBar(
|
||||
centerTitle: false,
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: 0,
|
||||
leading: BackButton(
|
||||
onPressed: () {
|
||||
Navigator.pop(context);
|
||||
},
|
||||
),
|
||||
title: ListTile(
|
||||
dense: true,
|
||||
title: SizedBox(
|
||||
width: mediaWidth(context, 0.8),
|
||||
child: Text(
|
||||
'${widget.localArchive.name} ',
|
||||
style: const TextStyle(fontWeight: FontWeight.bold),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
subtitle: SizedBox(
|
||||
width: mediaWidth(context, 0.8),
|
||||
child: const Text(
|
||||
"",
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.w400,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
backgroundColor: _backgroundColor(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
AnimatedContainer(
|
||||
curve: Curves.ease,
|
||||
duration: const Duration(milliseconds: 300),
|
||||
width: mediaWidth(context, 1),
|
||||
height: _isView ? 130 : 0,
|
||||
child: Column(
|
||||
children: [
|
||||
Flexible(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Transform.scale(
|
||||
scaleX: !_isReversHorizontal ? 1 : -1,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 10),
|
||||
child: Container(
|
||||
height: 70,
|
||||
decoration: BoxDecoration(
|
||||
color: _backgroundColor(context),
|
||||
borderRadius: BorderRadius.circular(25)),
|
||||
child: Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 12),
|
||||
child: Transform.scale(
|
||||
scaleX: !_isReversHorizontal ? 1 : -1,
|
||||
child: SizedBox(
|
||||
width: 25,
|
||||
child: Text(
|
||||
"${currentIndex + 1} ",
|
||||
style: const TextStyle(
|
||||
fontSize: 15.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Slider(
|
||||
onChanged: (newValue) {
|
||||
_onBtnTapped(newValue.toInt(), true,
|
||||
isSlide: true);
|
||||
},
|
||||
divisions: max(
|
||||
widget.localArchive.images!.length -
|
||||
1,
|
||||
1),
|
||||
value: min(
|
||||
_currentIndex.toDouble(),
|
||||
widget.localArchive.images!.length
|
||||
.toDouble()),
|
||||
min: 0,
|
||||
max: (widget.localArchive.images!
|
||||
.length -
|
||||
1)
|
||||
.toDouble(),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(right: 12),
|
||||
child: Transform.scale(
|
||||
scaleX: !_isReversHorizontal ? 1 : -1,
|
||||
child: SizedBox(
|
||||
width: 25,
|
||||
child: Text(
|
||||
"${widget.localArchive.images!.length}",
|
||||
style: const TextStyle(
|
||||
fontSize: 15.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: Container(
|
||||
height: 65,
|
||||
color: _backgroundColor(context),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
PopupMenuButton(
|
||||
color: Colors.black,
|
||||
child: const Icon(
|
||||
Icons.app_settings_alt_outlined,
|
||||
),
|
||||
onSelected: (value) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_selectedValue = value;
|
||||
});
|
||||
}
|
||||
_(value, true);
|
||||
},
|
||||
itemBuilder: (context) => [
|
||||
for (var readerMode in ReaderMode.values)
|
||||
PopupMenuItem(
|
||||
value: readerMode,
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
Icons.check,
|
||||
color: _selectedValue == readerMode
|
||||
? Colors.white
|
||||
: Colors.transparent,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 7,
|
||||
),
|
||||
Text(
|
||||
getReaderModeName(readerMode),
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
],
|
||||
)),
|
||||
],
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
icon: const Icon(
|
||||
Icons.screen_rotation,
|
||||
),
|
||||
),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
_showModalSettings();
|
||||
},
|
||||
icon: const Icon(
|
||||
Icons.settings_rounded,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _showPage() {
|
||||
return Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final currentIndex = _currentIndex;
|
||||
return _isView
|
||||
? Container()
|
||||
: _showPagesNumber
|
||||
? Align(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Text(
|
||||
'${currentIndex + 1} / ${widget.localArchive.images!.length}',
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 12.0,
|
||||
shadows: <Shadow>[
|
||||
Shadow(offset: Offset(0.0, 0.0), blurRadius: 10.0)
|
||||
],
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
)
|
||||
: Container();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
_isViewFunction() {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_isView = !_isView;
|
||||
});
|
||||
}
|
||||
if (_isView) {
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
|
||||
overlays: SystemUiOverlay.values);
|
||||
} else {
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.immersiveSticky,
|
||||
overlays: []);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _gestureRightLeft() {
|
||||
return Consumer(
|
||||
builder: (context, ref, child) {
|
||||
return Row(
|
||||
children: [
|
||||
/// left region
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
if (_isReversHorizontal) {
|
||||
_onBtnTapped(_currentIndex + 1, false);
|
||||
} else {
|
||||
_onBtnTapped(_currentIndex - 1, true);
|
||||
}
|
||||
},
|
||||
onDoubleTapDown: _isVerticalContinous()
|
||||
? (TapDownDetails details) {
|
||||
_toggleScale(details.globalPosition);
|
||||
}
|
||||
: null,
|
||||
onDoubleTap: _isVerticalContinous() ? () {} : null,
|
||||
),
|
||||
),
|
||||
|
||||
/// center region
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
_isViewFunction();
|
||||
},
|
||||
onDoubleTapDown: _isVerticalContinous()
|
||||
? (TapDownDetails details) {
|
||||
_toggleScale(details.globalPosition);
|
||||
}
|
||||
: null,
|
||||
onDoubleTap: _isVerticalContinous() ? () {} : null,
|
||||
),
|
||||
),
|
||||
|
||||
/// right region
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
if (_isReversHorizontal) {
|
||||
_onBtnTapped(_currentIndex - 1, true);
|
||||
} else {
|
||||
_onBtnTapped(_currentIndex + 1, false);
|
||||
}
|
||||
},
|
||||
onDoubleTapDown: _isVerticalContinous()
|
||||
? (TapDownDetails details) {
|
||||
_toggleScale(details.globalPosition);
|
||||
}
|
||||
: null,
|
||||
onDoubleTap: _isVerticalContinous() ? () {} : null,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Widget _gestureTopBottom() {
|
||||
return Consumer(
|
||||
builder: (context, ref, child) {
|
||||
return Column(
|
||||
children: [
|
||||
/// top region
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
_onBtnTapped(_currentIndex - 1, true);
|
||||
},
|
||||
onDoubleTapDown: _isVerticalContinous()
|
||||
? (TapDownDetails details) {
|
||||
_toggleScale(details.globalPosition);
|
||||
}
|
||||
: null,
|
||||
onDoubleTap: _isVerticalContinous() ? () {} : null,
|
||||
),
|
||||
),
|
||||
|
||||
/// center region
|
||||
Expanded(flex: 5, child: Container()),
|
||||
|
||||
/// bottom region
|
||||
Expanded(
|
||||
flex: 2,
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: () {
|
||||
_onBtnTapped(_currentIndex + 1, false);
|
||||
},
|
||||
onDoubleTapDown: _isVerticalContinous()
|
||||
? (TapDownDetails details) {
|
||||
_toggleScale(details.globalPosition);
|
||||
}
|
||||
: null,
|
||||
onDoubleTap: _isVerticalContinous() ? () {} : null,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
bool _isZoom = false;
|
||||
bool _isVerticalContinous() {
|
||||
return _selectedValue == ReaderMode.verticalContinuous ||
|
||||
_selectedValue == ReaderMode.webtoon;
|
||||
}
|
||||
|
||||
final StreamController<double> _rebuildDetail =
|
||||
StreamController<double>.broadcast();
|
||||
final Map<int, ImageDetailInfo> detailKeys = <int, ImageDetailInfo>{};
|
||||
late AnimationController _doubleClickAnimationController;
|
||||
|
||||
Animation<double>? _doubleClickAnimation;
|
||||
late DoubleClickAnimationListener _doubleClickAnimationListener;
|
||||
List<double> doubleTapScales = <double>[1.0, 2.0];
|
||||
GlobalKey<ExtendedImageSlidePageState> slidePagekey =
|
||||
GlobalKey<ExtendedImageSlidePageState>();
|
||||
double _imageDetailY = 0;
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
|
||||
overlays: SystemUiOverlay.values);
|
||||
Navigator.pop(context);
|
||||
|
||||
return false;
|
||||
},
|
||||
child: Stack(
|
||||
children: [
|
||||
_isVerticalContinous()
|
||||
? PhotoViewGallery.builder(
|
||||
itemCount: 1,
|
||||
builder: (_, __) => PhotoViewGalleryPageOptions.customChild(
|
||||
controller: _photoViewController,
|
||||
scaleStateController: _photoViewScaleStateController,
|
||||
basePosition: _scalePosition,
|
||||
onScaleEnd: _onScaleEnd,
|
||||
child: ScrollablePositionedList.separated(
|
||||
physics: const ClampingScrollPhysics(),
|
||||
minCacheExtent: 8 * (MediaQuery.of(context).size.height),
|
||||
initialScrollIndex: _currentIndex,
|
||||
itemCount: widget.localArchive.images!.length,
|
||||
itemScrollController: _itemScrollController,
|
||||
itemPositionsListener: _itemPositionsListener,
|
||||
itemBuilder: (context, index) => GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onDoubleTapDown: (TapDownDetails details) {
|
||||
_toggleScale(details.globalPosition);
|
||||
},
|
||||
onDoubleTap: () {},
|
||||
child: Image.memory(
|
||||
widget.localArchive.images![index].image!)),
|
||||
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(),
|
||||
preloadPagesCount:
|
||||
_isZoom ? 0 : widget.localArchive.images!.length,
|
||||
canScrollPage: (GestureDetails? gestureDetails) {
|
||||
return gestureDetails != null
|
||||
? !(gestureDetails.totalScale! > 1.0)
|
||||
: true;
|
||||
},
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
return ExtendedImage.memory(
|
||||
widget.localArchive.images![index].image!,
|
||||
clearMemoryCacheWhenDispose: true,
|
||||
enableMemoryCache: false,
|
||||
mode: ExtendedImageMode.gesture,
|
||||
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<double>(
|
||||
builder: (BuildContext context,
|
||||
AsyncSnapshot<double> data) {
|
||||
return ExtendedImageGesture(
|
||||
state,
|
||||
canScaleImage: (_) => _imageDetailY == 0,
|
||||
imageBuilder: (Widget image) {
|
||||
return Stack(
|
||||
children: <Widget>[
|
||||
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,
|
||||
);
|
||||
},
|
||||
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();
|
||||
},
|
||||
);
|
||||
},
|
||||
itemCount: widget.localArchive.images!.length,
|
||||
onPageChanged: _onPageChanged)),
|
||||
_gestureRightLeft(),
|
||||
_gestureTopBottom(),
|
||||
_showMore(),
|
||||
_showPage(),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
_showModalSettings() {
|
||||
DraggableMenu.open(
|
||||
context,
|
||||
DraggableMenu(
|
||||
ui: ClassicDraggableMenu(barItem: Container()),
|
||||
expandable: false,
|
||||
maxHeight: mediaHeight(context, 0.4),
|
||||
fastDrag: false,
|
||||
minimizeBeforeFastDrag: false,
|
||||
child: StatefulBuilder(
|
||||
builder: (context, setState) {
|
||||
return Scaffold(
|
||||
body: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.all(8.0),
|
||||
child: Text(
|
||||
'Settings',
|
||||
style: TextStyle(
|
||||
fontSize: 17, fontWeight: FontWeight.bold),
|
||||
),
|
||||
),
|
||||
const Divider(),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
SwitchListTile(
|
||||
dense: true,
|
||||
title: const Text('Show Page Number'),
|
||||
value: _showPagesNumber,
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_showPagesNumber = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ class _MainScreenState extends State<MainScreen> {
|
|||
final route = GoRouter.of(context);
|
||||
int currentIndex = route.location == '/library'
|
||||
? 0
|
||||
: route.location == '/archiveReader'
|
||||
: route.location == '/updates'
|
||||
? 1
|
||||
: route.location == '/history'
|
||||
? 2
|
||||
|
|
@ -79,7 +79,7 @@ class _MainScreenState extends State<MainScreen> {
|
|||
width: isLongPressed
|
||||
? 0
|
||||
: route.location != '/library' &&
|
||||
route.location != '/archiveReader' &&
|
||||
route.location != '/updates' &&
|
||||
route.location != '/history' &&
|
||||
route.location != '/browse' &&
|
||||
route.location != '/more'
|
||||
|
|
@ -113,7 +113,7 @@ class _MainScreenState extends State<MainScreen> {
|
|||
),
|
||||
label: Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Text('A-Reader'))),
|
||||
child: Text('Updates'))),
|
||||
NavigationRailDestination(
|
||||
selectedIcon: Icon(
|
||||
Icons.history,
|
||||
|
|
@ -158,7 +158,7 @@ class _MainScreenState extends State<MainScreen> {
|
|||
if (newIndex == 0) {
|
||||
route.go('/library');
|
||||
} else if (newIndex == 1) {
|
||||
route.go('/archiveReader');
|
||||
route.go('/updates');
|
||||
} else if (newIndex == 2) {
|
||||
route.go('/history');
|
||||
} else if (newIndex == 3) {
|
||||
|
|
@ -186,7 +186,7 @@ class _MainScreenState extends State<MainScreen> {
|
|||
height: isLongPressed
|
||||
? 0
|
||||
: route.location != '/library' &&
|
||||
route.location != '/archiveReader' &&
|
||||
route.location != '/updates' &&
|
||||
route.location != '/history' &&
|
||||
route.location != '/browse' &&
|
||||
route.location != '/more'
|
||||
|
|
@ -212,12 +212,12 @@ class _MainScreenState extends State<MainScreen> {
|
|||
label: 'Library'),
|
||||
NavigationDestination(
|
||||
selectedIcon: Icon(
|
||||
Icons.library_books,
|
||||
Icons.new_releases,
|
||||
),
|
||||
icon: Icon(
|
||||
Icons.library_books_outlined,
|
||||
Icons.new_releases_outlined,
|
||||
),
|
||||
label: 'A-Reader'),
|
||||
label: 'Updates'),
|
||||
NavigationDestination(
|
||||
selectedIcon: Icon(
|
||||
Icons.history,
|
||||
|
|
@ -252,7 +252,7 @@ class _MainScreenState extends State<MainScreen> {
|
|||
if (newIndex == 0) {
|
||||
route.go('/library');
|
||||
} else if (newIndex == 1) {
|
||||
route.go('/archiveReader');
|
||||
route.go('/updates');
|
||||
} else if (newIndex == 2) {
|
||||
route.go('/history');
|
||||
} else if (newIndex == 3) {
|
||||
|
|
|
|||
150
lib/modules/manga/reader/chapter_interval_page_view.dart
Normal file
150
lib/modules/manga/reader/chapter_interval_page_view.dart
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/manga_reader_view.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/providers/reader_controller_provider.dart';
|
||||
import 'package:mangayomi/utils/media_query.dart';
|
||||
|
||||
class ChapterIntervalPageView extends ConsumerWidget {
|
||||
final bool hasPrevChapter;
|
||||
final bool hasNextChapter;
|
||||
final UChapDataPreload uChapDataPreload;
|
||||
|
||||
final VoidCallback onTap;
|
||||
const ChapterIntervalPageView(
|
||||
{super.key,
|
||||
required this.uChapDataPreload,
|
||||
required this.hasPrevChapter,
|
||||
required this.hasNextChapter,
|
||||
required this.onTap});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final readerController =
|
||||
ReaderController(chapter: uChapDataPreload.chapter!);
|
||||
|
||||
String text = uChapDataPreload.isPrevPrePage && hasPrevChapter
|
||||
? "Current:"
|
||||
: "Finished:";
|
||||
final noMoreChapter = uChapDataPreload.isNextPrePage && !hasNextChapter ||
|
||||
uChapDataPreload.isPrevPrePage && !hasPrevChapter;
|
||||
String noMore =
|
||||
uChapDataPreload.isNextPrePage && !hasNextChapter ? "Next" : "Previous";
|
||||
return SizedBox(
|
||||
height: mediaHeight(context, 0.27),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
if (uChapDataPreload.isPrevPrePage && hasPrevChapter)
|
||||
Column(
|
||||
children: [
|
||||
const Text(
|
||||
"Previous:",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
fontSize: 12),
|
||||
),
|
||||
Text(readerController.getPrevChapter().name!,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 12),
|
||||
textAlign: TextAlign.center),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
Column(
|
||||
children: [
|
||||
Text(
|
||||
text,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
fontSize: 12),
|
||||
),
|
||||
Wrap(
|
||||
children: [
|
||||
Text(
|
||||
uChapDataPreload.chapter!.name!,
|
||||
style: const TextStyle(
|
||||
color: Colors.white, fontSize: 12),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 3,
|
||||
),
|
||||
const Icon(
|
||||
FontAwesomeIcons.circleCheck,
|
||||
color: Colors.white,
|
||||
size: 17,
|
||||
),
|
||||
],
|
||||
),
|
||||
// ElevatedButton(onPressed: onTap, child: const Text("Retry")),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
if (noMoreChapter)
|
||||
Text(
|
||||
"There is no $noMore chapter",
|
||||
style: const TextStyle(color: Colors.white, fontSize: 14),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
if (uChapDataPreload.isNextPrePage && hasNextChapter)
|
||||
Column(
|
||||
children: [
|
||||
Column(
|
||||
children: [
|
||||
Text(
|
||||
text,
|
||||
style: const TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white,
|
||||
fontSize: 12),
|
||||
),
|
||||
Wrap(
|
||||
alignment: WrapAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
uChapDataPreload.chapter!.name!,
|
||||
style: const TextStyle(
|
||||
color: Colors.white, fontSize: 12),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(
|
||||
width: 3,
|
||||
),
|
||||
const Icon(
|
||||
FontAwesomeIcons.circleCheck,
|
||||
color: Colors.white,
|
||||
size: 16,
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const Text(
|
||||
"Next:",
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold, color: Colors.white),
|
||||
),
|
||||
Text(
|
||||
readerController.getNextChapter().name!,
|
||||
style: const TextStyle(color: Colors.white, fontSize: 12),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 30,
|
||||
),
|
||||
// ElevatedButton(
|
||||
// onPressed: onTap,
|
||||
// child: const Text("Load Next chapter")),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -3,7 +3,6 @@ import 'dart:typed_data';
|
|||
import 'package:extended_image/extended_image.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:font_awesome_flutter/font_awesome_flutter.dart';
|
||||
import 'package:mangayomi/utils/headers.dart';
|
||||
import 'package:mangayomi/utils/media_query.dart';
|
||||
import 'package:mangayomi/utils/reg_exp_matcher.dart';
|
||||
|
|
@ -46,17 +45,31 @@ class ImageViewVertical extends ConsumerWidget {
|
|||
),
|
||||
isLocale
|
||||
? archiveImage != null
|
||||
? ExtendedImage.memory(
|
||||
archiveImage!,
|
||||
? ExtendedImage.memory(archiveImage!,
|
||||
fit: BoxFit.contain,
|
||||
clearMemoryCacheWhenDispose: true,
|
||||
enableMemoryCache: false,
|
||||
)
|
||||
loadStateChanged: (ExtendedImageState state) {
|
||||
if (state.extendedImageLoadState == LoadState.loading) {
|
||||
return Container(
|
||||
color: Colors.black,
|
||||
height: mediaHeight(context, 0.8),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})
|
||||
: ExtendedImage.file(
|
||||
fit: BoxFit.contain,
|
||||
clearMemoryCacheWhenDispose: true,
|
||||
enableMemoryCache: false,
|
||||
File('${path.path}${padIndex(index + 1)}.jpg'))
|
||||
File('${path.path}${padIndex(index + 1)}.jpg'),
|
||||
loadStateChanged: (ExtendedImageState state) {
|
||||
if (state.extendedImageLoadState == LoadState.loading) {
|
||||
return Container(
|
||||
color: Colors.black,
|
||||
height: mediaHeight(context, 0.8),
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})
|
||||
: ExtendedImage.network(url,
|
||||
headers: ref.watch(headersProvider(source: source)),
|
||||
handleLoadingProgress: true,
|
||||
|
|
@ -99,32 +112,6 @@ class ImageViewVertical extends ConsumerWidget {
|
|||
}
|
||||
return null;
|
||||
}),
|
||||
if (index + 1 == length)
|
||||
SizedBox(
|
||||
height: mediaHeight(context, 0.3),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'$chapter finished',
|
||||
style: const TextStyle(
|
||||
fontSize: 17.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.white),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
const Icon(
|
||||
FontAwesomeIcons.circleCheck,
|
||||
color: Colors.white,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -14,9 +14,7 @@ class CurrentIndex extends _$CurrentIndex {
|
|||
int build(Chapter chapter) {
|
||||
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
||||
if (!incognitoMode) {
|
||||
return ref
|
||||
.read(readerControllerProvider(chapter: chapter).notifier)
|
||||
.getPageIndex();
|
||||
return ReaderController(chapter: chapter).getPageIndex();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -28,235 +26,9 @@ class CurrentIndex extends _$CurrentIndex {
|
|||
}
|
||||
}
|
||||
|
||||
@riverpod
|
||||
class ReaderController extends _$ReaderController {
|
||||
@override
|
||||
void build({required Chapter chapter}) {}
|
||||
|
||||
Manga getManga() {
|
||||
return chapter.manga.value!;
|
||||
}
|
||||
|
||||
Chapter geChapter() {
|
||||
return chapter;
|
||||
}
|
||||
|
||||
ReaderMode getReaderMode() {
|
||||
final personalReaderModeList =
|
||||
getIsarSetting().personalReaderModeList ?? [];
|
||||
final personalReaderMode = personalReaderModeList
|
||||
.where((element) => element.mangaId == getManga().id);
|
||||
if (personalReaderMode.isNotEmpty) {
|
||||
return personalReaderMode.first.readerMode;
|
||||
}
|
||||
return isar.settings.getSync(227)!.defaultReaderMode;
|
||||
}
|
||||
|
||||
void setReaderMode(ReaderMode newReaderMode) {
|
||||
List<PersonalReaderMode>? personalReaderModeLists = [];
|
||||
for (var personalReaderMode
|
||||
in getIsarSetting().personalReaderModeList ?? []) {
|
||||
if (personalReaderMode.mangaId != getManga().id) {
|
||||
personalReaderModeLists.add(personalReaderMode);
|
||||
}
|
||||
}
|
||||
personalReaderModeLists.add(PersonalReaderMode()
|
||||
..mangaId = getManga().id
|
||||
..readerMode = newReaderMode);
|
||||
isar.writeTxnSync(() => isar.settings.putSync(
|
||||
getIsarSetting()..personalReaderModeList = personalReaderModeLists));
|
||||
}
|
||||
|
||||
void setShowPageNumber(bool value) {
|
||||
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
||||
if (!incognitoMode) {
|
||||
isar.writeTxnSync(() =>
|
||||
isar.settings.putSync(getIsarSetting()..showPagesNumber = value));
|
||||
}
|
||||
}
|
||||
|
||||
Settings getIsarSetting() {
|
||||
return isar.settings.getSync(227)!;
|
||||
}
|
||||
|
||||
bool getShowPageNumber() {
|
||||
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
||||
if (!incognitoMode) {
|
||||
return getIsarSetting().showPagesNumber!;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void setMangaHistoryUpdate() {
|
||||
// log("message");
|
||||
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
||||
if (!incognitoMode) {
|
||||
isar.writeTxnSync(() {
|
||||
Manga? manga = chapter.manga.value;
|
||||
manga!.lastRead = DateTime.now().millisecondsSinceEpoch;
|
||||
isar.mangas.putSync(manga);
|
||||
});
|
||||
History? history;
|
||||
|
||||
final empty =
|
||||
isar.historys.filter().mangaIdEqualTo(getManga().id).isEmptySync();
|
||||
|
||||
if (empty) {
|
||||
history = History(
|
||||
mangaId: getManga().id,
|
||||
date: DateTime.now().millisecondsSinceEpoch.toString())
|
||||
..chapter.value = chapter;
|
||||
} else {
|
||||
history = (isar.historys
|
||||
.filter()
|
||||
.mangaIdEqualTo(getManga().id)
|
||||
.findFirstSync())!
|
||||
..chapter.value = chapter
|
||||
..date = DateTime.now().millisecondsSinceEpoch.toString();
|
||||
}
|
||||
isar.writeTxnSync(() {
|
||||
isar.historys.putSync(history!);
|
||||
history.chapter.saveSync();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void setChapterPageLastRead(int pageIndex) {
|
||||
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
||||
if (!incognitoMode) {
|
||||
final chap = chapter;
|
||||
isar.writeTxnSync(() {
|
||||
chap.isRead = (pageIndex + 1) == getPageLength([]);
|
||||
chap.lastPageRead = (pageIndex + 1).toString();
|
||||
isar.chapters.putSync(chap);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void setChapterBookmarked() {
|
||||
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
||||
if (!incognitoMode) {
|
||||
final isBookmarked = getChapterBookmarked();
|
||||
final chap = chapter;
|
||||
isar.writeTxnSync(() {
|
||||
chap.isBookmarked = !isBookmarked;
|
||||
isar.chapters.putSync(chap);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
bool getChapterBookmarked() {
|
||||
return isar.chapters.getSync(chapter.id!)!.isBookmarked!;
|
||||
}
|
||||
|
||||
int getNextChapterIndex() {
|
||||
final chapters = getManga().chapters.toList();
|
||||
int? index;
|
||||
for (var i = 0; i < chapters.length; i++) {
|
||||
if (chapters[i].id == chapter.id) {
|
||||
index = i + 1;
|
||||
}
|
||||
}
|
||||
return index!;
|
||||
}
|
||||
|
||||
int getPrevChapterIndex() {
|
||||
final chapters = getManga().chapters.toList();
|
||||
int? index;
|
||||
for (var i = 0; i < chapters.length; i++) {
|
||||
if (chapters[i].id == chapter.id) {
|
||||
index = i - 1;
|
||||
}
|
||||
}
|
||||
return index!;
|
||||
}
|
||||
|
||||
int getChapterIndex() {
|
||||
final chapters = getManga().chapters.toList();
|
||||
int? index;
|
||||
for (var i = 0; i < chapters.length; i++) {
|
||||
if (chapters[i].id == chapter.id) {
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
return index!;
|
||||
}
|
||||
|
||||
Chapter getNextChapter() {
|
||||
return getManga().chapters.toList()[getNextChapterIndex()];
|
||||
}
|
||||
|
||||
Chapter getPrevChapter() {
|
||||
return getManga().chapters.toList()[getPrevChapterIndex()];
|
||||
}
|
||||
|
||||
int getChaptersLength() {
|
||||
return getManga().chapters.length;
|
||||
}
|
||||
|
||||
int getPageIndex() {
|
||||
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
||||
final chapterPageIndexList = getIsarSetting().chapterPageIndexList ?? [];
|
||||
final index = chapterPageIndexList
|
||||
.where((element) => element.chapterId == chapter.id);
|
||||
if (!incognitoMode) {
|
||||
return chapter.isRead!
|
||||
? 0
|
||||
: index.isNotEmpty
|
||||
? index.first.index!
|
||||
: 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int getPageLength(List incognitoPageLength) {
|
||||
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
||||
if (!incognitoMode) {
|
||||
return getIsarSetting()
|
||||
.chapterPageUrlsList!
|
||||
.where((element) => element.chapterId == chapter.id)
|
||||
.first
|
||||
.urls!
|
||||
.length;
|
||||
}
|
||||
return incognitoPageLength.length;
|
||||
}
|
||||
|
||||
void setPageIndex(int newIndex) {
|
||||
final incognitoMode = ref.watch(incognitoModeStateProvider);
|
||||
if (!incognitoMode) {
|
||||
List<ChapterPageIndex>? chapterPageIndexs = [];
|
||||
for (var chapterPageIndex
|
||||
in getIsarSetting().chapterPageIndexList ?? []) {
|
||||
if (chapterPageIndex.chapterId != chapter.id) {
|
||||
chapterPageIndexs.add(chapterPageIndex);
|
||||
}
|
||||
}
|
||||
chapterPageIndexs.add(ChapterPageIndex()
|
||||
..chapterId = chapter.id
|
||||
..index = newIndex);
|
||||
isar.writeTxnSync(() => isar.settings
|
||||
.putSync(getIsarSetting()..chapterPageIndexList = chapterPageIndexs));
|
||||
}
|
||||
}
|
||||
|
||||
String getMangaName() {
|
||||
return getManga().name!;
|
||||
}
|
||||
|
||||
String getSourceName() {
|
||||
return getManga().source!;
|
||||
}
|
||||
|
||||
String getChapterTitle() {
|
||||
return chapter.name!;
|
||||
}
|
||||
}
|
||||
|
||||
class ReaderControllerAA {
|
||||
class ReaderController {
|
||||
final Chapter chapter;
|
||||
bool incognitoMode;
|
||||
ReaderControllerAA({required this.chapter, required this.incognitoMode});
|
||||
ReaderController({required this.chapter});
|
||||
|
||||
Manga getManga() {
|
||||
return chapter.manga.value!;
|
||||
|
|
@ -266,6 +38,7 @@ class ReaderControllerAA {
|
|||
return chapter;
|
||||
}
|
||||
|
||||
final incognitoMode = isar.settings.getSync(227)!.incognitoMode!;
|
||||
ReaderMode getReaderMode() {
|
||||
final personalReaderModeList =
|
||||
getIsarSetting().personalReaderModeList ?? [];
|
||||
|
|
@ -311,8 +84,6 @@ class ReaderControllerAA {
|
|||
}
|
||||
|
||||
void setMangaHistoryUpdate() {
|
||||
// log("message");
|
||||
|
||||
if (!incognitoMode) {
|
||||
isar.writeTxnSync(() {
|
||||
Manga? manga = chapter.manga.value;
|
||||
|
|
@ -370,7 +141,7 @@ class ReaderControllerAA {
|
|||
return isar.chapters.getSync(chapter.id!)!.isBookmarked!;
|
||||
}
|
||||
|
||||
int getNextChapterIndex() {
|
||||
int getPrevChapterIndex() {
|
||||
final chapters = getManga().chapters.toList();
|
||||
int? index;
|
||||
for (var i = 0; i < chapters.length; i++) {
|
||||
|
|
@ -381,7 +152,7 @@ class ReaderControllerAA {
|
|||
return index!;
|
||||
}
|
||||
|
||||
int getPrevChapterIndex() {
|
||||
int getNextChapterIndex() {
|
||||
final chapters = getManga().chapters.toList();
|
||||
int? index;
|
||||
for (var i = 0; i < chapters.length; i++) {
|
||||
|
|
@ -403,14 +174,14 @@ class ReaderControllerAA {
|
|||
return index!;
|
||||
}
|
||||
|
||||
Chapter getNextChapter() {
|
||||
return getManga().chapters.toList()[getNextChapterIndex()];
|
||||
}
|
||||
|
||||
Chapter getPrevChapter() {
|
||||
return getManga().chapters.toList()[getPrevChapterIndex()];
|
||||
}
|
||||
|
||||
Chapter getNextChapter() {
|
||||
return getManga().chapters.toList()[getNextChapterIndex()];
|
||||
}
|
||||
|
||||
int getChaptersLength() {
|
||||
return getManga().chapters.length;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -122,100 +122,4 @@ class CurrentIndexProvider
|
|||
);
|
||||
}
|
||||
}
|
||||
|
||||
String _$readerControllerHash() => r'65ce80e436f72efffea6ba9b1b6f87be702b79cd';
|
||||
|
||||
abstract class _$ReaderController extends BuildlessAutoDisposeNotifier<void> {
|
||||
late final Chapter chapter;
|
||||
|
||||
void build({
|
||||
required Chapter chapter,
|
||||
});
|
||||
}
|
||||
|
||||
/// See also [ReaderController].
|
||||
@ProviderFor(ReaderController)
|
||||
const readerControllerProvider = ReaderControllerFamily();
|
||||
|
||||
/// See also [ReaderController].
|
||||
class ReaderControllerFamily extends Family<void> {
|
||||
/// See also [ReaderController].
|
||||
const ReaderControllerFamily();
|
||||
|
||||
/// See also [ReaderController].
|
||||
ReaderControllerProvider call({
|
||||
required Chapter chapter,
|
||||
}) {
|
||||
return ReaderControllerProvider(
|
||||
chapter: chapter,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
ReaderControllerProvider getProviderOverride(
|
||||
covariant ReaderControllerProvider provider,
|
||||
) {
|
||||
return call(
|
||||
chapter: provider.chapter,
|
||||
);
|
||||
}
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _dependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
|
||||
|
||||
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
|
||||
|
||||
@override
|
||||
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
|
||||
_allTransitiveDependencies;
|
||||
|
||||
@override
|
||||
String? get name => r'readerControllerProvider';
|
||||
}
|
||||
|
||||
/// See also [ReaderController].
|
||||
class ReaderControllerProvider
|
||||
extends AutoDisposeNotifierProviderImpl<ReaderController, void> {
|
||||
/// See also [ReaderController].
|
||||
ReaderControllerProvider({
|
||||
required this.chapter,
|
||||
}) : super.internal(
|
||||
() => ReaderController()..chapter = chapter,
|
||||
from: readerControllerProvider,
|
||||
name: r'readerControllerProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$readerControllerHash,
|
||||
dependencies: ReaderControllerFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
ReaderControllerFamily._allTransitiveDependencies,
|
||||
);
|
||||
|
||||
final Chapter chapter;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is ReaderControllerProvider && other.chapter == chapter;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, chapter.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
|
||||
@override
|
||||
void runNotifierBuild(
|
||||
covariant ReaderController notifier,
|
||||
) {
|
||||
return notifier.build(
|
||||
chapter: chapter,
|
||||
);
|
||||
}
|
||||
}
|
||||
// ignore_for_file: unnecessary_raw_strings, subtype_of_sealed_class, invalid_use_of_internal_member, do_not_use_environment, prefer_const_constructors, public_member_api_docs, avoid_private_typedef_functions
|
||||
|
|
|
|||
|
|
@ -3,10 +3,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:go_router/go_router.dart';
|
||||
import 'package:mangayomi/models/chapter.dart';
|
||||
import 'package:mangayomi/models/manga_type.dart';
|
||||
import 'package:mangayomi/modules/archive_reader/archive_reader_screen.dart';
|
||||
import 'package:mangayomi/modules/archive_reader/models/models.dart';
|
||||
import 'package:mangayomi/modules/archive_reader/reader/archive_reader_reader_view.dart';
|
||||
import 'package:mangayomi/modules/more/settings/downloads/downloads_screen.dart';
|
||||
import 'package:mangayomi/modules/updates/updates_screen.dart';
|
||||
import 'package:mangayomi/modules/webview/webview.dart';
|
||||
import 'package:mangayomi/modules/browse/browse_screen.dart';
|
||||
import 'package:mangayomi/modules/browse/extension/extension_lang.dart';
|
||||
|
|
@ -53,15 +51,6 @@ class AsyncRouterNotifier extends ChangeNotifier {
|
|||
child: const LibraryScreen(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
name: "archiveReader",
|
||||
path: '/archiveReader',
|
||||
builder: (context, state) => const LocalReaderScreen(),
|
||||
pageBuilder: (context, state) => CustomTransition(
|
||||
key: state.pageKey,
|
||||
child: const LocalReaderScreen(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
name: "history",
|
||||
path: '/history',
|
||||
|
|
@ -80,6 +69,15 @@ class AsyncRouterNotifier extends ChangeNotifier {
|
|||
child: const BrowseScreen(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
name: "updates",
|
||||
path: '/updates',
|
||||
builder: (context, state) => const UpdatesScreen(),
|
||||
pageBuilder: (context, state) => CustomTransition(
|
||||
key: state.pageKey,
|
||||
child: const UpdatesScreen(),
|
||||
),
|
||||
),
|
||||
GoRoute(
|
||||
name: "more",
|
||||
path: '/more',
|
||||
|
|
@ -335,25 +333,6 @@ class AsyncRouterNotifier extends ChangeNotifier {
|
|||
);
|
||||
},
|
||||
),
|
||||
GoRoute(
|
||||
path: "/archiveReaderReaderView",
|
||||
name: "archiveReaderReaderView",
|
||||
builder: (context, state) {
|
||||
final localArchive = state.extra as LocalArchive;
|
||||
return ArchiveReaderReaderView(
|
||||
localArchive: localArchive,
|
||||
);
|
||||
},
|
||||
pageBuilder: (context, state) {
|
||||
final localArchive = state.extra as LocalArchive;
|
||||
return CustomTransition(
|
||||
key: state.pageKey,
|
||||
child: ArchiveReaderReaderView(
|
||||
localArchive: localArchive,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import 'package:mangayomi/models/chapter.dart';
|
|||
import 'package:mangayomi/models/settings.dart';
|
||||
import 'package:mangayomi/models/source.dart';
|
||||
import 'package:mangayomi/modules/archive_reader/providers/archive_reader_providers.dart';
|
||||
import 'package:mangayomi/modules/manga/reader/manga_reader_view.dart';
|
||||
import 'package:mangayomi/providers/storage_provider.dart';
|
||||
import 'package:mangayomi/sources/multisrc/heancms/heancms.dart';
|
||||
import 'package:mangayomi/sources/multisrc/madara/src/madara.dart';
|
||||
|
|
@ -28,11 +29,13 @@ class GetChapterUrlModel {
|
|||
List<String> pageUrls = [];
|
||||
List<bool> isLocaleList = [];
|
||||
List<Uint8List> archiveImages = [];
|
||||
List<UChapDataPreload> uChapDataPreload;
|
||||
GetChapterUrlModel(
|
||||
{required this.path,
|
||||
required this.pageUrls,
|
||||
required this.isLocaleList,
|
||||
required this.archiveImages});
|
||||
required this.archiveImages,
|
||||
required this.uChapDataPreload});
|
||||
}
|
||||
|
||||
@riverpod
|
||||
|
|
@ -40,6 +43,7 @@ Future<GetChapterUrlModel> getChapterUrl(
|
|||
GetChapterUrlRef ref, {
|
||||
required Chapter chapter,
|
||||
}) async {
|
||||
List<UChapDataPreload> uChapDataPreloadp = [];
|
||||
Directory? path;
|
||||
List<String> pageUrls = [];
|
||||
final manga = chapter.manga.value!;
|
||||
|
|
@ -177,11 +181,29 @@ Future<GetChapterUrlModel> getChapterUrl(
|
|||
isar.writeTxnSync(() => isar.settings
|
||||
.putSync(settings..chapterPageUrlsList = chapterPageUrls));
|
||||
}
|
||||
for (var i = 0; i < pageUrls.length; i++) {
|
||||
uChapDataPreloadp.add(UChapDataPreload(
|
||||
chapter,
|
||||
path,
|
||||
pageUrls[i],
|
||||
isLocaleList[i],
|
||||
archiveImages[i],
|
||||
i,
|
||||
false,
|
||||
false,
|
||||
GetChapterUrlModel(
|
||||
path: path,
|
||||
pageUrls: pageUrls,
|
||||
isLocaleList: isLocaleList,
|
||||
archiveImages: archiveImages,
|
||||
uChapDataPreload: uChapDataPreloadp)));
|
||||
}
|
||||
}
|
||||
|
||||
return GetChapterUrlModel(
|
||||
path: path,
|
||||
pageUrls: pageUrls,
|
||||
isLocaleList: isLocaleList,
|
||||
archiveImages: archiveImages);
|
||||
archiveImages: archiveImages,
|
||||
uChapDataPreload: uChapDataPreloadp);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ part of 'get_chapter_url.dart';
|
|||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$getChapterUrlHash() => r'd34b2bbc9062d7675347ff44d57943ff135b0135';
|
||||
String _$getChapterUrlHash() => r'6e9e28c2d3775791f9c8544cf0f41bb07b5eaf81';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
|
|
|
|||
|
|
@ -957,6 +957,14 @@ packages:
|
|||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "0.3.5"
|
||||
scrollview_observer:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
name: scrollview_observer
|
||||
sha256: "459ab67e3b1680e660d3bff24b64c9de4fc6f22a49bd3ecbbafece8e83f0b973"
|
||||
url: "https://pub.dev"
|
||||
source: hosted
|
||||
version: "1.14.0"
|
||||
share_plus:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
|
|
|||
|
|
@ -64,6 +64,7 @@ dependencies:
|
|||
file_picker: ^5.3.0
|
||||
path_provider: ^2.0.15
|
||||
image: ^3.3.0
|
||||
scrollview_observer: ^1.14.0
|
||||
|
||||
|
||||
# The following adds the Cupertino Icons font to your application.
|
||||
|
|
|
|||
Loading…
Reference in a new issue