refactor & multiple action feature for chapter
This commit is contained in:
parent
bd6a088d42
commit
758fed9c53
11 changed files with 723 additions and 446 deletions
|
|
@ -1,5 +1,4 @@
|
|||
import 'dart:convert';
|
||||
import 'dart:developer';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:mangayomi/models/comick/search_manga_cimick.dart';
|
||||
import 'package:mangayomi/services/get_popular_manga.dart';
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ import 'package:grouped_list/grouped_list.dart';
|
|||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:mangayomi/models/manga_history.dart';
|
||||
import 'package:mangayomi/models/manga_reader.dart';
|
||||
import 'package:mangayomi/models/model_manga.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/utils/cached_network.dart';
|
||||
import 'package:mangayomi/utils/date.dart';
|
||||
|
|
|
|||
|
|
@ -5,19 +5,16 @@ import 'package:draggable_scrollbar/draggable_scrollbar.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mangayomi/models/manga_reader.dart';
|
||||
import 'package:mangayomi/models/model_manga.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/utils/cached_network.dart';
|
||||
import 'package:mangayomi/utils/colors.dart';
|
||||
import 'package:mangayomi/utils/media_query.dart';
|
||||
import 'package:mangayomi/utils/utils.dart';
|
||||
import 'package:mangayomi/views/manga/detail/manga_details_view.dart';
|
||||
import 'package:mangayomi/views/manga/detail/providers/state_providers.dart';
|
||||
import 'package:mangayomi/views/manga/detail/readmore.dart';
|
||||
import 'package:mangayomi/views/manga/detail/widgets/chapter_listtile_widget.dart';
|
||||
import 'package:mangayomi/views/manga/download/download_page_widget.dart';
|
||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||
import 'package:mangayomi/views/manga/detail/widgets/chapter_list_tile_widget.dart';
|
||||
import 'package:mangayomi/views/manga/download/providers/download_provider.dart';
|
||||
|
||||
class MangaDetailView extends ConsumerStatefulWidget {
|
||||
final Function(bool) isExtended;
|
||||
|
|
@ -58,7 +55,10 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
ScrollController _scrollController = ScrollController();
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final chapterIndexList = ref.watch(chapterIndexListStateProvider);
|
||||
final isLongPressed = ref.watch(isLongPressedStateProvider);
|
||||
final reverse = ref.watch(reverseMangaStateProvider);
|
||||
final chapter = ref.watch(chapterModelStateProvider);
|
||||
return NotificationListener<UserScrollNotification>(
|
||||
onNotification: (notification) {
|
||||
if (notification.direction == ScrollDirection.forward) {
|
||||
|
|
@ -73,57 +73,96 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
extendBodyBehindAppBar: true,
|
||||
appBar: PreferredSize(
|
||||
preferredSize: Size.fromHeight(AppBar().preferredSize.height),
|
||||
child: Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final isLongPressed = ref.watch(isLongPressedStateProvider);
|
||||
final reverse = ref.watch(reverseMangaStateProvider);
|
||||
return isLongPressed
|
||||
? AppBar(
|
||||
backgroundColor: generalColor(context),
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(chapterIndexStateProvider.notifier)
|
||||
.update(-1);
|
||||
child: isLongPressed
|
||||
? Container(
|
||||
color: Theme.of(context).scaffoldBackgroundColor,
|
||||
child: AppBar(
|
||||
title: Text(chapterIndexList.length.toString()),
|
||||
backgroundColor: generalColor(context).withOpacity(0.2),
|
||||
leading: IconButton(
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(chapterIndexListStateProvider.notifier)
|
||||
.clear();
|
||||
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(!isLongPressed);
|
||||
},
|
||||
icon: const Icon(Icons.clear)),
|
||||
)
|
||||
: AppBar(
|
||||
title: ref.watch(offetProvider) > 200
|
||||
? Text(
|
||||
widget.modelManga!.name!,
|
||||
style: const TextStyle(fontSize: 17),
|
||||
)
|
||||
: null,
|
||||
backgroundColor: ref.watch(offetProvider) == 0.0
|
||||
? Colors.transparent
|
||||
: Theme.of(context).scaffoldBackgroundColor,
|
||||
actions: [
|
||||
// IconButton(
|
||||
// splashRadius: 20,
|
||||
// onPressed: () {},
|
||||
// icon: Icon(Icons.download_outlined,
|
||||
// color: Theme.of(context).hintColor)),
|
||||
IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(!isLongPressed);
|
||||
},
|
||||
icon: const Icon(Icons.clear)),
|
||||
actions: [
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
for (var i = 0;
|
||||
i < widget.modelManga!.chapters!.length;
|
||||
i++) {
|
||||
ref
|
||||
.read(reverseMangaStateProvider.notifier)
|
||||
.update(!reverse);
|
||||
},
|
||||
icon: Icon(
|
||||
reverse
|
||||
? Icons.arrow_downward_sharp
|
||||
: Icons.arrow_upward_sharp,
|
||||
color: Theme.of(context).hintColor)),
|
||||
],
|
||||
);
|
||||
},
|
||||
)),
|
||||
.read(chapterIndexListStateProvider
|
||||
.notifier)
|
||||
.selectAll(i);
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.select_all)),
|
||||
IconButton(
|
||||
onPressed: () {
|
||||
if (widget.modelManga!.chapters!.length ==
|
||||
chapterIndexList.length) {
|
||||
for (var i = 0;
|
||||
i < widget.modelManga!.chapters!.length;
|
||||
i++) {
|
||||
ref
|
||||
.read(chapterIndexListStateProvider
|
||||
.notifier)
|
||||
.selectSome(i);
|
||||
}
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
} else {
|
||||
for (var i = 0;
|
||||
i < widget.modelManga!.chapters!.length;
|
||||
i++) {
|
||||
ref
|
||||
.read(chapterIndexListStateProvider
|
||||
.notifier)
|
||||
.selectSome(i);
|
||||
}
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.flip_to_back_rounded)),
|
||||
],
|
||||
),
|
||||
)
|
||||
: AppBar(
|
||||
title: ref.watch(offetProvider) > 200
|
||||
? Text(
|
||||
widget.modelManga!.name!,
|
||||
style: const TextStyle(fontSize: 17),
|
||||
)
|
||||
: null,
|
||||
backgroundColor: ref.watch(offetProvider) == 0.0
|
||||
? Colors.transparent
|
||||
: Theme.of(context).scaffoldBackgroundColor,
|
||||
actions: [
|
||||
// IconButton(
|
||||
// splashRadius: 20,
|
||||
// onPressed: () {},
|
||||
// icon: Icon(Icons.download_outlined,
|
||||
// color: Theme.of(context).hintColor)),
|
||||
IconButton(
|
||||
splashRadius: 20,
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(reverseMangaStateProvider.notifier)
|
||||
.update(!reverse);
|
||||
},
|
||||
icon: Icon(
|
||||
reverse
|
||||
? Icons.arrow_downward_sharp
|
||||
: Icons.arrow_upward_sharp,
|
||||
color: Theme.of(context).hintColor)),
|
||||
],
|
||||
)),
|
||||
body: Stack(
|
||||
children: [
|
||||
Positioned(
|
||||
|
|
@ -150,186 +189,247 @@ class _MangaDetailViewState extends ConsumerState<MangaDetailView>
|
|||
)
|
||||
],
|
||||
)),
|
||||
SafeArea(child: Consumer(builder: (context, ref, child) {
|
||||
final reverse = ref.watch(reverseMangaStateProvider);
|
||||
return DraggableScrollbar(
|
||||
heightScrollThumb: 48.0,
|
||||
backgroundColor: generalColor(context),
|
||||
scrollThumbBuilder: (backgroundColor, thumbAnimation,
|
||||
labelAnimation, height,
|
||||
{labelConstraints, labelText}) {
|
||||
return FadeTransition(
|
||||
opacity: thumbAnimation,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor,
|
||||
borderRadius: BorderRadius.circular(20)),
|
||||
height: height,
|
||||
width: 10.0,
|
||||
),
|
||||
);
|
||||
},
|
||||
scrollbarTimeToFade: const Duration(seconds: 2),
|
||||
controller: _scrollController,
|
||||
child: ListView.builder(
|
||||
controller: _scrollController,
|
||||
padding: const EdgeInsets.only(top: 0),
|
||||
itemCount: widget.listLength,
|
||||
itemBuilder: (context, index) {
|
||||
int finalIndex = index - 1;
|
||||
if (index == 0) {
|
||||
return _bodyContainer();
|
||||
}
|
||||
SafeArea(
|
||||
child: DraggableScrollbar(
|
||||
heightScrollThumb: 48.0,
|
||||
backgroundColor: generalColor(context),
|
||||
scrollThumbBuilder: (backgroundColor, thumbAnimation,
|
||||
labelAnimation, height,
|
||||
{labelConstraints, labelText}) {
|
||||
return FadeTransition(
|
||||
opacity: thumbAnimation,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: backgroundColor,
|
||||
borderRadius: BorderRadius.circular(20)),
|
||||
height: height,
|
||||
width: 8.0,
|
||||
),
|
||||
);
|
||||
},
|
||||
scrollbarTimeToFade: const Duration(seconds: 2),
|
||||
controller: _scrollController,
|
||||
child: ListView.builder(
|
||||
controller: _scrollController,
|
||||
padding: const EdgeInsets.only(top: 0),
|
||||
itemCount: widget.listLength,
|
||||
itemBuilder: (context, index) {
|
||||
int finalIndex = index - 1;
|
||||
if (index == 0) {
|
||||
return _bodyContainer();
|
||||
}
|
||||
|
||||
int reverseIndex = widget
|
||||
.modelManga!.chapters!.length -
|
||||
widget.modelManga!.chapters!.reversed
|
||||
.toList()
|
||||
.indexOf(widget.modelManga!.chapters!.reversed
|
||||
.toList()[finalIndex]) -
|
||||
1;
|
||||
int reverseIndex = widget
|
||||
.modelManga!.chapters!.length -
|
||||
widget.modelManga!.chapters!.reversed
|
||||
.toList()
|
||||
.indexOf(widget
|
||||
.modelManga!.chapters!.reversed
|
||||
.toList()[finalIndex]) -
|
||||
1;
|
||||
|
||||
List<ModelChapters> chapters = reverse
|
||||
? widget.modelManga!.chapters!.reversed.toList()
|
||||
: widget.modelManga!.chapters!;
|
||||
List<ModelChapters> chapters = reverse
|
||||
? widget.modelManga!.chapters!.reversed.toList()
|
||||
: widget.modelManga!.chapters!;
|
||||
|
||||
return ChapterListTileWidget(
|
||||
chapters: chapters,
|
||||
modelManga: widget.modelManga!,
|
||||
reverse: reverse,
|
||||
reverseIndex: reverseIndex,
|
||||
finalIndex: finalIndex,
|
||||
isLongPressed: isLongPressed);
|
||||
}));
|
||||
})),
|
||||
return ChapterListTileWidget(
|
||||
chapters: chapters,
|
||||
modelManga: widget.modelManga!,
|
||||
reverse: reverse,
|
||||
reverseIndex: reverseIndex,
|
||||
finalIndex: finalIndex,
|
||||
isLongPressed: isLongPressed);
|
||||
}))),
|
||||
],
|
||||
),
|
||||
bottomNavigationBar: Consumer(
|
||||
builder: (context, ref, child) {
|
||||
final idx = ref.watch(chapterIndexStateProvider);
|
||||
final chapter = ref.watch(chapterModelStateProvider);
|
||||
return AnimatedContainer(
|
||||
curve: Curves.easeIn,
|
||||
decoration: BoxDecoration(
|
||||
color: generalColor(context).withOpacity(0.3),
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(20),
|
||||
topRight: Radius.circular(20))),
|
||||
duration: const Duration(milliseconds: 100),
|
||||
height: isLongPressed ? 70 : 0,
|
||||
width: mediaWidth(context, 1),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
IconButton(
|
||||
bottomNavigationBar: AnimatedContainer(
|
||||
curve: Curves.easeIn,
|
||||
decoration: BoxDecoration(
|
||||
color: generalColor(context).withOpacity(0.2),
|
||||
borderRadius: const BorderRadius.only(
|
||||
topLeft: Radius.circular(20),
|
||||
topRight: Radius.circular(20))),
|
||||
duration: const Duration(milliseconds: 100),
|
||||
height: isLongPressed ? 70 : 0,
|
||||
width: mediaWidth(context, 1),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceAround,
|
||||
children: [
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 70,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent),
|
||||
onPressed: () async {
|
||||
List<ModelChapters> chap = [];
|
||||
for (var i = 0;
|
||||
i < widget.modelManga!.chapters!.length;
|
||||
i++) {
|
||||
chap.add(ModelChapters(
|
||||
name: widget.modelManga!.chapters![i].name,
|
||||
url: widget.modelManga!.chapters![i].url,
|
||||
dateUpload:
|
||||
widget.modelManga!.chapters![i].dateUpload,
|
||||
isBookmarked: idx == i
|
||||
? widget.modelManga!.chapters![i]
|
||||
.isBookmarked
|
||||
? false
|
||||
: true
|
||||
: widget
|
||||
.modelManga!.chapters![i].isBookmarked,
|
||||
scanlator:
|
||||
widget.modelManga!.chapters![i].scanlator,
|
||||
isRead: widget.modelManga!.chapters![i].isRead,
|
||||
lastPageRead: widget
|
||||
.modelManga!.chapters![i].lastPageRead));
|
||||
}
|
||||
for (var idx in chapterIndexList) {
|
||||
List<ModelChapters> chap = [];
|
||||
for (var i = 0;
|
||||
i < widget.modelManga!.chapters!.length;
|
||||
i++) {
|
||||
final entries = ref
|
||||
.watch(hiveBoxManga)
|
||||
.values
|
||||
.where((element) =>
|
||||
'${element.lang}-${element.link}' ==
|
||||
'${widget.modelManga!.lang}-${widget.modelManga!.link}')
|
||||
.toList()
|
||||
.first;
|
||||
chap.add(ModelChapters(
|
||||
name: entries.chapters![i].name,
|
||||
url: entries.chapters![i].url,
|
||||
dateUpload: entries.chapters![i].dateUpload,
|
||||
isBookmarked: idx == i
|
||||
? entries.chapters![i].isBookmarked
|
||||
? false
|
||||
: true
|
||||
: entries.chapters![i].isBookmarked,
|
||||
scanlator: entries.chapters![i].scanlator,
|
||||
isRead: entries.chapters![i].isRead,
|
||||
lastPageRead:
|
||||
entries.chapters![i].lastPageRead));
|
||||
}
|
||||
|
||||
// print(idx);
|
||||
final model = ModelManga(
|
||||
imageUrl: widget.modelManga!.imageUrl,
|
||||
name: widget.modelManga!.name,
|
||||
genre: widget.modelManga!.genre,
|
||||
author: widget.modelManga!.author,
|
||||
description: widget.modelManga!.description,
|
||||
status: widget.modelManga!.status,
|
||||
favorite: widget.modelManga!.favorite,
|
||||
link: widget.modelManga!.link,
|
||||
source: widget.modelManga!.source,
|
||||
lang: widget.modelManga!.lang,
|
||||
dateAdded: widget.modelManga!.dateAdded,
|
||||
lastUpdate: widget.modelManga!.lastUpdate,
|
||||
chapters: chap,
|
||||
category: widget.modelManga!.category,
|
||||
lastRead: widget.modelManga!.lastRead);
|
||||
ref.watch(hiveBoxManga).put(
|
||||
'${widget.modelManga!.lang}-${widget.modelManga!.link}',
|
||||
model);
|
||||
ref
|
||||
.read(chapterModelStateProvider.notifier)
|
||||
.update(chap[idx]);
|
||||
// print(chapterIndexList);
|
||||
final model = ModelManga(
|
||||
imageUrl: widget.modelManga!.imageUrl,
|
||||
name: widget.modelManga!.name,
|
||||
genre: widget.modelManga!.genre,
|
||||
author: widget.modelManga!.author,
|
||||
description: widget.modelManga!.description,
|
||||
status: widget.modelManga!.status,
|
||||
favorite: widget.modelManga!.favorite,
|
||||
link: widget.modelManga!.link,
|
||||
source: widget.modelManga!.source,
|
||||
lang: widget.modelManga!.lang,
|
||||
dateAdded: widget.modelManga!.dateAdded,
|
||||
lastUpdate: widget.modelManga!.lastUpdate,
|
||||
chapters: chap,
|
||||
category: widget.modelManga!.category,
|
||||
lastRead: widget.modelManga!.lastRead);
|
||||
ref.watch(hiveBoxManga).put(
|
||||
'${widget.modelManga!.lang}-${widget.modelManga!.link}',
|
||||
model);
|
||||
ref
|
||||
.read(chapterIndexListStateProvider.notifier)
|
||||
.clear();
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
}
|
||||
},
|
||||
icon: Icon(chapter.isBookmarked
|
||||
child: Icon(chapter.isBookmarked
|
||||
? Icons.bookmark_remove
|
||||
: Icons.bookmark_add_outlined)),
|
||||
IconButton(
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 70,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent),
|
||||
onPressed: () {
|
||||
List<ModelChapters> chap = [];
|
||||
for (var i = 0;
|
||||
i < widget.modelManga!.chapters!.length;
|
||||
i++) {
|
||||
chap.add(ModelChapters(
|
||||
name: widget.modelManga!.chapters![i].name,
|
||||
url: widget.modelManga!.chapters![i].url,
|
||||
dateUpload:
|
||||
widget.modelManga!.chapters![i].dateUpload,
|
||||
isBookmarked: widget
|
||||
.modelManga!.chapters![i].isBookmarked,
|
||||
scanlator:
|
||||
widget.modelManga!.chapters![i].scanlator,
|
||||
isRead: idx == i
|
||||
? widget.modelManga!.chapters![i].isRead
|
||||
? false
|
||||
: true
|
||||
: widget.modelManga!.chapters![i].isRead,
|
||||
lastPageRead: widget
|
||||
.modelManga!.chapters![i].lastPageRead));
|
||||
}
|
||||
for (var idx in chapterIndexList) {
|
||||
List<ModelChapters> chap = [];
|
||||
for (var i = 0;
|
||||
i < widget.modelManga!.chapters!.length;
|
||||
i++) {
|
||||
final entries = ref
|
||||
.watch(hiveBoxManga)
|
||||
.values
|
||||
.where((element) =>
|
||||
'${element.lang}-${element.link}' ==
|
||||
'${widget.modelManga!.lang}-${widget.modelManga!.link}')
|
||||
.toList()
|
||||
.first;
|
||||
chap.add(ModelChapters(
|
||||
name: entries.chapters![i].name,
|
||||
url: entries.chapters![i].url,
|
||||
dateUpload: entries.chapters![i].dateUpload,
|
||||
isBookmarked:
|
||||
entries.chapters![i].isBookmarked,
|
||||
scanlator: entries.chapters![i].scanlator,
|
||||
isRead: idx == i
|
||||
? entries.chapters![i].isRead
|
||||
? false
|
||||
: true
|
||||
: entries.chapters![i].isRead,
|
||||
lastPageRead:
|
||||
entries.chapters![i].lastPageRead));
|
||||
}
|
||||
|
||||
final model = ModelManga(
|
||||
imageUrl: widget.modelManga!.imageUrl,
|
||||
name: widget.modelManga!.name,
|
||||
genre: widget.modelManga!.genre,
|
||||
author: widget.modelManga!.author,
|
||||
description: widget.modelManga!.description,
|
||||
status: widget.modelManga!.status,
|
||||
favorite: widget.modelManga!.favorite,
|
||||
link: widget.modelManga!.link,
|
||||
source: widget.modelManga!.source,
|
||||
lang: widget.modelManga!.lang,
|
||||
dateAdded: widget.modelManga!.dateAdded,
|
||||
lastUpdate: widget.modelManga!.lastUpdate,
|
||||
chapters: chap,
|
||||
category: widget.modelManga!.category,
|
||||
lastRead: widget.modelManga!.lastRead);
|
||||
ref.watch(hiveBoxManga).put(
|
||||
'${widget.modelManga!.lang}-${widget.modelManga!.link}',
|
||||
model);
|
||||
ref
|
||||
.read(chapterModelStateProvider.notifier)
|
||||
.update(chap[idx]);
|
||||
;
|
||||
final model = ModelManga(
|
||||
imageUrl: widget.modelManga!.imageUrl,
|
||||
name: widget.modelManga!.name,
|
||||
genre: widget.modelManga!.genre,
|
||||
author: widget.modelManga!.author,
|
||||
description: widget.modelManga!.description,
|
||||
status: widget.modelManga!.status,
|
||||
favorite: widget.modelManga!.favorite,
|
||||
link: widget.modelManga!.link,
|
||||
source: widget.modelManga!.source,
|
||||
lang: widget.modelManga!.lang,
|
||||
dateAdded: widget.modelManga!.dateAdded,
|
||||
lastUpdate: widget.modelManga!.lastUpdate,
|
||||
chapters: chap,
|
||||
category: widget.modelManga!.category,
|
||||
lastRead: widget.modelManga!.lastRead);
|
||||
ref.watch(hiveBoxManga).put(
|
||||
'${widget.modelManga!.lang}-${widget.modelManga!.link}',
|
||||
model);
|
||||
ref
|
||||
.read(chapterIndexListStateProvider.notifier)
|
||||
.clear();
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
}
|
||||
},
|
||||
icon: Icon(chapter.isRead
|
||||
child: Icon(chapter.isRead
|
||||
? Icons.remove_done_sharp
|
||||
: Icons.done_all_sharp)),
|
||||
IconButton(
|
||||
onPressed: () {}, icon: const Icon(Icons.download))
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
Expanded(
|
||||
child: SizedBox(
|
||||
height: 70,
|
||||
child: ElevatedButton(
|
||||
style: ElevatedButton.styleFrom(
|
||||
backgroundColor: Colors.transparent),
|
||||
onPressed: () {
|
||||
for (var idx in chapterIndexList) {
|
||||
final entries = ref
|
||||
.watch(hiveBoxMangaDownloads)
|
||||
.values
|
||||
.where((element) =>
|
||||
element.modelManga.chapters![element.index]
|
||||
.name ==
|
||||
widget.modelManga!.chapters![idx].name)
|
||||
.toList();
|
||||
if (entries.isEmpty) {
|
||||
ref.watch(downloadChapterProvider(
|
||||
modelManga: widget.modelManga!, index: idx));
|
||||
} else {
|
||||
if (!entries.first.isDownload) {
|
||||
ref.watch(downloadChapterProvider(
|
||||
modelManga: widget.modelManga!,
|
||||
index: idx));
|
||||
}
|
||||
}
|
||||
}
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(false);
|
||||
ref
|
||||
.read(chapterIndexListStateProvider.notifier)
|
||||
.clear();
|
||||
},
|
||||
child: const Icon(Icons.download_outlined)),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -64,8 +64,8 @@ class _MangaReaderDetailState extends ConsumerState<MangaReaderDetail> {
|
|||
dateAdded: widget.modelManga.dateAdded,
|
||||
lastUpdate: DateTime.now().microsecondsSinceEpoch,
|
||||
chapters: value.chapters,
|
||||
category: null,
|
||||
lastRead: '');
|
||||
category: widget.modelManga.category,
|
||||
lastRead: widget.modelManga.lastRead);
|
||||
ref.watch(hiveBoxManga).put(
|
||||
'${widget.modelManga.lang}-${widget.modelManga.link}',
|
||||
model);
|
||||
|
|
|
|||
|
|
@ -1,14 +1,8 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'dart:developer';
|
||||
|
||||
import 'package:mangayomi/models/model_manga.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'state_providers.g.dart';
|
||||
// final reverseMangaStateProvider = StateProvider.autoDispose<bool>(
|
||||
// (ref) => false,
|
||||
// );
|
||||
|
||||
// final sortedMangaValueStateProvider = StateProvider.autoDispose<String>(
|
||||
// (ref) => 'By source',
|
||||
// );
|
||||
|
||||
@riverpod
|
||||
class ChapterModelState extends _$ChapterModelState {
|
||||
|
|
@ -30,14 +24,46 @@ class ChapterModelState extends _$ChapterModelState {
|
|||
}
|
||||
|
||||
@riverpod
|
||||
class ChapterIndexState extends _$ChapterIndexState {
|
||||
class ChapterIndexListState extends _$ChapterIndexListState {
|
||||
@override
|
||||
int build() {
|
||||
return -1;
|
||||
List<int> build() {
|
||||
return [];
|
||||
}
|
||||
|
||||
void update(int value) {
|
||||
state = value;
|
||||
var newList = state.reversed.toList();
|
||||
if (newList.contains(value)) {
|
||||
newList.remove(value);
|
||||
} else {
|
||||
newList.add(value);
|
||||
}
|
||||
if (newList.isEmpty) {
|
||||
ref.read(isLongPressedStateProvider.notifier).update(false);
|
||||
}
|
||||
state = newList;
|
||||
}
|
||||
|
||||
void selectAll(int value) {
|
||||
var newList = state.reversed.toList();
|
||||
if (!newList.contains(value)) {
|
||||
newList.add(value);
|
||||
}
|
||||
|
||||
state = newList;
|
||||
}
|
||||
|
||||
void selectSome(int value) {
|
||||
var newList = state.reversed.toList();
|
||||
if (newList.contains(value)) {
|
||||
newList.remove(value);
|
||||
} else {
|
||||
newList.add(value);
|
||||
}
|
||||
state = newList;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
state = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -22,22 +22,23 @@ final chapterModelStateProvider =
|
|||
);
|
||||
|
||||
typedef _$ChapterModelState = AutoDisposeNotifier<ModelChapters>;
|
||||
String _$chapterIndexStateHash() => r'db4ba6cb07f0bb8e388e518179a0b5f35b58e48b';
|
||||
String _$chapterIndexListStateHash() =>
|
||||
r'cef615a9638df5a2a72c6087f479824cc169a70e';
|
||||
|
||||
/// See also [ChapterIndexState].
|
||||
@ProviderFor(ChapterIndexState)
|
||||
final chapterIndexStateProvider =
|
||||
AutoDisposeNotifierProvider<ChapterIndexState, int>.internal(
|
||||
ChapterIndexState.new,
|
||||
name: r'chapterIndexStateProvider',
|
||||
/// See also [ChapterIndexListState].
|
||||
@ProviderFor(ChapterIndexListState)
|
||||
final chapterIndexListStateProvider =
|
||||
AutoDisposeNotifierProvider<ChapterIndexListState, List<int>>.internal(
|
||||
ChapterIndexListState.new,
|
||||
name: r'chapterIndexListStateProvider',
|
||||
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$chapterIndexStateHash,
|
||||
: _$chapterIndexListStateHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$ChapterIndexState = AutoDisposeNotifier<int>;
|
||||
typedef _$ChapterIndexListState = AutoDisposeNotifier<List<int>>;
|
||||
String _$isLongPressedStateHash() =>
|
||||
r'26fe435e8381046a30e3f6c4495303946aa3aaa7';
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:developer';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:mangayomi/models/manga_reader.dart';
|
||||
|
|
@ -26,10 +28,12 @@ class ChapterListTileWidget extends ConsumerWidget {
|
|||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final idx = reverse ? reverseIndex : finalIndex;
|
||||
final chapterIndex = ref.watch(chapterIndexStateProvider);
|
||||
final chapterIndexList = ref.watch(chapterIndexListStateProvider);
|
||||
|
||||
return Container(
|
||||
color:
|
||||
chapterIndex == idx ? generalColor(context).withOpacity(0.4) : null,
|
||||
color: chapterIndexList.contains(idx)
|
||||
? generalColor(context).withOpacity(0.4)
|
||||
: null,
|
||||
child: ListTile(
|
||||
textColor: chapters[finalIndex].isRead
|
||||
? isLight(context)
|
||||
|
|
@ -41,27 +45,26 @@ class ChapterListTileWidget extends ConsumerWidget {
|
|||
: Colors.white,
|
||||
onLongPress: () {
|
||||
if (!isLongPressed) {
|
||||
ref.read(chapterIndexStateProvider.notifier).update(idx);
|
||||
ref.read(chapterIndexListStateProvider.notifier).update(idx);
|
||||
ref
|
||||
.read(chapterModelStateProvider.notifier)
|
||||
.update(chapters[finalIndex]);
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(!isLongPressed);
|
||||
} else {
|
||||
ref.read(chapterIndexStateProvider.notifier).update(-1);
|
||||
}
|
||||
ref.read(isLongPressedStateProvider.notifier).update(!isLongPressed);
|
||||
},
|
||||
onTap: () {
|
||||
if (isLongPressed) {
|
||||
ref.read(chapterIndexStateProvider.notifier).update(idx);
|
||||
ref.read(chapterIndexListStateProvider.notifier).update(idx);
|
||||
ref
|
||||
.read(chapterModelStateProvider.notifier)
|
||||
.update(chapters[finalIndex]);
|
||||
}
|
||||
},
|
||||
onTap: () async {
|
||||
if (isLongPressed) {
|
||||
ref.read(chapterIndexListStateProvider.notifier).update(idx);
|
||||
ref
|
||||
.read(chapterModelStateProvider.notifier)
|
||||
.update(chapters[finalIndex]);
|
||||
if (chapterIndex == idx) {
|
||||
ref.read(chapterIndexStateProvider.notifier).update(-1);
|
||||
ref
|
||||
.read(isLongPressedStateProvider.notifier)
|
||||
.update(!isLongPressed);
|
||||
}
|
||||
} else {
|
||||
pushMangaReaderView(
|
||||
context: context,
|
||||
|
|
@ -13,6 +13,7 @@ import 'package:mangayomi/utils/constant.dart';
|
|||
import 'package:mangayomi/utils/headers.dart';
|
||||
import 'package:mangayomi/utils/reg_exp_matcher.dart';
|
||||
import 'package:mangayomi/views/manga/download/download_model.dart';
|
||||
import 'package:mangayomi/views/manga/download/providers/download_provider.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'download_page_widget.g.dart';
|
||||
|
||||
|
|
@ -42,170 +43,16 @@ class ChapterPageDownload extends ConsumerStatefulWidget {
|
|||
class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
|
||||
with AutomaticKeepAliveClientMixin<ChapterPageDownload> {
|
||||
List _urll = [];
|
||||
List<DownloadTask> tasks = [];
|
||||
|
||||
final StorageProvider _storageProvider = StorageProvider();
|
||||
_startDownload() async {
|
||||
await _storageProvider.requestPermission();
|
||||
Directory? path;
|
||||
bool isOk = false;
|
||||
final path1 = await _storageProvider.getDirectory();
|
||||
|
||||
final finalPath =
|
||||
"downloads/${widget.modelManga.source} (${widget.modelManga.lang!.toUpperCase()})/${widget.modelManga.name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/${widget.modelManga.chapters![widget.index].name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}";
|
||||
path = Directory(
|
||||
"${path1!.path}downloads/${widget.modelManga.source} (${widget.modelManga.lang!.toUpperCase()})/${widget.modelManga.name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/${widget.modelManga.chapters![widget.index].name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/");
|
||||
ref
|
||||
.read(getMangaChapterUrlProvider(
|
||||
modelManga: widget.modelManga,
|
||||
index: widget.index,
|
||||
).future)
|
||||
.then((value) {
|
||||
if (value.urll.isNotEmpty) {
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_urll = value.urll;
|
||||
isOk = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (_urll.isNotEmpty) {
|
||||
for (var index = 0; index < _urll.length; index++) {
|
||||
final path2 = Directory("${path1.path}downloads/");
|
||||
final path4 = Directory(
|
||||
"${path2.path}${widget.modelManga.source} (${widget.modelManga.lang!.toUpperCase()})/");
|
||||
final path3 = Directory(
|
||||
"${path2.path}${widget.modelManga.source} (${widget.modelManga.lang!.toUpperCase()})/${widget.modelManga.name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/");
|
||||
final path5 = Directory(
|
||||
"${path2.path}${widget.modelManga.source} (${widget.modelManga.lang!.toUpperCase()})/${widget.modelManga.name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/${widget.modelManga.chapters![widget.index].name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}");
|
||||
|
||||
if (!(await path1.exists())) {
|
||||
path1.create();
|
||||
}
|
||||
if (Platform.isAndroid) {
|
||||
if (!(await File("${path1.path}" ".nomedia").exists())) {
|
||||
File("${path1.path}" ".nomedia").create();
|
||||
}
|
||||
}
|
||||
|
||||
if (!(await path2.exists())) {
|
||||
path2.create();
|
||||
}
|
||||
if (!(await path4.exists())) {
|
||||
path4.create();
|
||||
}
|
||||
if (!(await path3.exists())) {
|
||||
path3.create();
|
||||
}
|
||||
if (!(await path5.exists())) {
|
||||
path5.create();
|
||||
}
|
||||
if ((await path.exists())) {
|
||||
if (await File("${path.path}" "${padIndex(index + 1)}.jpg")
|
||||
.exists()) {
|
||||
} else {
|
||||
tasks.add(DownloadTask(
|
||||
taskId: _urll[index],
|
||||
headers: headers(widget.modelManga.source!),
|
||||
url: _urll[index],
|
||||
filename: "${padIndex(index + 1)}.jpg",
|
||||
baseDirectory:
|
||||
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
||||
? BaseDirectory.applicationDocuments
|
||||
: BaseDirectory.temporary,
|
||||
directory:
|
||||
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
||||
? 'Mangayomi/$finalPath'
|
||||
: finalPath,
|
||||
updates: Updates.statusAndProgress,
|
||||
allowPause: true,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
path.create();
|
||||
if (await File("${path.path}" "${padIndex(index + 1)}.jpg")
|
||||
.exists()) {
|
||||
} else {
|
||||
tasks.add(DownloadTask(
|
||||
taskId: _urll[index],
|
||||
headers: headers(widget.modelManga.source!),
|
||||
url: _urll[index],
|
||||
filename: "${padIndex(index + 1)}.jpg",
|
||||
baseDirectory:
|
||||
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
||||
? BaseDirectory.applicationDocuments
|
||||
: BaseDirectory.temporary,
|
||||
directory:
|
||||
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
||||
? 'Mangayomi/$finalPath'
|
||||
: finalPath,
|
||||
updates: Updates.statusAndProgress,
|
||||
allowPause: true,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tasks.isEmpty && _urll.isNotEmpty) {
|
||||
final model = DownloadModel(
|
||||
modelManga: widget.modelManga,
|
||||
succeeded: 0,
|
||||
failed: 0,
|
||||
index: widget.index,
|
||||
total: 0,
|
||||
isDownload: true,
|
||||
taskIds: _urll,
|
||||
isStartDownload: false);
|
||||
|
||||
ref
|
||||
.watch(hiveBoxMangaDownloads)
|
||||
.put(widget.modelManga.chapters![widget.index].name!, model);
|
||||
} else {
|
||||
await FileDownloader().downloadBatch(
|
||||
tasks,
|
||||
batchProgressCallback: (succeeded, failed) {
|
||||
final model = DownloadModel(
|
||||
modelManga: widget.modelManga,
|
||||
succeeded: succeeded,
|
||||
failed: failed,
|
||||
index: widget.index,
|
||||
total: tasks.length,
|
||||
isDownload: (succeeded == tasks.length) ? true : false,
|
||||
taskIds: _urll,
|
||||
isStartDownload: true);
|
||||
|
||||
Hive.box<DownloadModel>(HiveConstant.hiveBoxDownloads)
|
||||
.put(widget.modelManga.chapters![widget.index].name!, model);
|
||||
},
|
||||
taskProgressCallback: (task, progress) async {
|
||||
if (progress == 1.0) {
|
||||
final downloadTask = DownloadTask(
|
||||
creationTime: task.creationTime,
|
||||
taskId: task.taskId,
|
||||
headers: task.headers,
|
||||
url: task.url,
|
||||
filename: task.filename,
|
||||
baseDirectory: task.baseDirectory,
|
||||
directory: task.directory,
|
||||
updates: task.updates,
|
||||
allowPause: task.allowPause,
|
||||
);
|
||||
if (Platform.isAndroid || Platform.isIOS) {
|
||||
await FileDownloader().moveToSharedStorage(
|
||||
downloadTask, SharedStorage.external,
|
||||
directory: finalPath);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
final data = await ref.watch(downloadChapterProvider(
|
||||
modelManga: widget.modelManga, index: widget.index)
|
||||
.future);
|
||||
if (mounted) {
|
||||
setState(() {
|
||||
_urll = data;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -439,7 +286,8 @@ class _ChapterPageDownloadState extends ConsumerState<ChapterPageDownload>
|
|||
.then((value) async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
ref.watch(hiveBoxMangaDownloads).delete(
|
||||
widget.modelManga.chapters![widget.index].name!,
|
||||
widget
|
||||
.modelManga.chapters![widget.index].name!,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
|
|
|||
179
lib/views/manga/download/providers/download_provider.dart
Normal file
179
lib/views/manga/download/providers/download_provider.dart
Normal file
|
|
@ -0,0 +1,179 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:background_downloader/background_downloader.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:mangayomi/models/model_manga.dart';
|
||||
import 'package:mangayomi/providers/hive_provider.dart';
|
||||
import 'package:mangayomi/providers/storage_provider.dart';
|
||||
import 'package:mangayomi/services/get_manga_chapter_url.dart';
|
||||
import 'package:mangayomi/utils/constant.dart';
|
||||
import 'package:mangayomi/utils/headers.dart';
|
||||
import 'package:mangayomi/utils/reg_exp_matcher.dart';
|
||||
import 'package:mangayomi/views/manga/download/download_model.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
part 'download_provider.g.dart';
|
||||
|
||||
@riverpod
|
||||
Future<List<dynamic>> downloadChapter(DownloadChapterRef ref,
|
||||
{required ModelManga modelManga, required int index}) async {
|
||||
List urll = [];
|
||||
List<DownloadTask> tasks = [];
|
||||
final StorageProvider storageProvider = StorageProvider();
|
||||
await storageProvider.requestPermission();
|
||||
Directory? path;
|
||||
bool isOk = false;
|
||||
final path1 = await storageProvider.getDirectory();
|
||||
|
||||
final finalPath =
|
||||
"downloads/${modelManga.source} (${modelManga.lang!.toUpperCase()})/${modelManga.name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/${modelManga.chapters![index].name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}";
|
||||
path = Directory(
|
||||
"${path1!.path}downloads/${modelManga.source} (${modelManga.lang!.toUpperCase()})/${modelManga.name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/${modelManga.chapters![index].name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/");
|
||||
ref
|
||||
.read(getMangaChapterUrlProvider(
|
||||
modelManga: modelManga,
|
||||
index: index,
|
||||
).future)
|
||||
.then((value) {
|
||||
if (value.urll.isNotEmpty) {
|
||||
urll = value.urll;
|
||||
isOk = true;
|
||||
}
|
||||
});
|
||||
await Future.doWhile(() async {
|
||||
await Future.delayed(const Duration(seconds: 1));
|
||||
if (isOk == true) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
if (urll.isNotEmpty) {
|
||||
for (var index = 0; index < urll.length; index++) {
|
||||
final path2 = Directory("${path1.path}downloads/");
|
||||
final path4 = Directory(
|
||||
"${path2.path}${modelManga.source} (${modelManga.lang!.toUpperCase()})/");
|
||||
final path3 = Directory(
|
||||
"${path2.path}${modelManga.source} (${modelManga.lang!.toUpperCase()})/${modelManga.name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/");
|
||||
final path5 = Directory(
|
||||
"${path2.path}${modelManga.source} (${modelManga.lang!.toUpperCase()})/${modelManga.name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}/${modelManga.chapters![index].name!.replaceAll(RegExp(r'[^a-zA-Z0-9 .()\-\s]'), '_')}");
|
||||
|
||||
if (!(await path1.exists())) {
|
||||
path1.create();
|
||||
}
|
||||
if (Platform.isAndroid) {
|
||||
if (!(await File("${path1.path}" ".nomedia").exists())) {
|
||||
File("${path1.path}" ".nomedia").create();
|
||||
}
|
||||
}
|
||||
|
||||
if (!(await path2.exists())) {
|
||||
path2.create();
|
||||
}
|
||||
if (!(await path4.exists())) {
|
||||
path4.create();
|
||||
}
|
||||
if (!(await path3.exists())) {
|
||||
path3.create();
|
||||
}
|
||||
if (!(await path5.exists())) {
|
||||
path5.create();
|
||||
}
|
||||
if ((await path.exists())) {
|
||||
if (await File("${path.path}" "${padIndex(index + 1)}.jpg").exists()) {
|
||||
} else {
|
||||
tasks.add(DownloadTask(
|
||||
taskId: urll[index],
|
||||
headers: headers(modelManga.source!),
|
||||
url: urll[index],
|
||||
filename: "${padIndex(index + 1)}.jpg",
|
||||
baseDirectory:
|
||||
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
||||
? BaseDirectory.applicationDocuments
|
||||
: BaseDirectory.temporary,
|
||||
directory:
|
||||
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
||||
? 'Mangayomi/$finalPath'
|
||||
: finalPath,
|
||||
updates: Updates.statusAndProgress,
|
||||
allowPause: true,
|
||||
));
|
||||
}
|
||||
} else {
|
||||
path.create();
|
||||
if (await File("${path.path}" "${padIndex(index + 1)}.jpg").exists()) {
|
||||
} else {
|
||||
tasks.add(DownloadTask(
|
||||
taskId: urll[index],
|
||||
headers: headers(modelManga.source!),
|
||||
url: urll[index],
|
||||
filename: "${padIndex(index + 1)}.jpg",
|
||||
baseDirectory:
|
||||
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
||||
? BaseDirectory.applicationDocuments
|
||||
: BaseDirectory.temporary,
|
||||
directory:
|
||||
Platform.isWindows || Platform.isMacOS || Platform.isLinux
|
||||
? 'Mangayomi/$finalPath'
|
||||
: finalPath,
|
||||
updates: Updates.statusAndProgress,
|
||||
allowPause: true,
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (tasks.isEmpty && urll.isNotEmpty) {
|
||||
final model = DownloadModel(
|
||||
modelManga: modelManga,
|
||||
succeeded: 0,
|
||||
failed: 0,
|
||||
index: index,
|
||||
total: 0,
|
||||
isDownload: true,
|
||||
taskIds: urll,
|
||||
isStartDownload: false);
|
||||
|
||||
ref
|
||||
.watch(hiveBoxMangaDownloads)
|
||||
.put(modelManga.chapters![index].name!, model);
|
||||
} else {
|
||||
await FileDownloader().downloadBatch(
|
||||
tasks,
|
||||
batchProgressCallback: (succeeded, failed) {
|
||||
final model = DownloadModel(
|
||||
modelManga: modelManga,
|
||||
succeeded: succeeded,
|
||||
failed: failed,
|
||||
index: index,
|
||||
total: tasks.length,
|
||||
isDownload: (succeeded == tasks.length) ? true : false,
|
||||
taskIds: urll,
|
||||
isStartDownload: true);
|
||||
|
||||
Hive.box<DownloadModel>(HiveConstant.hiveBoxDownloads)
|
||||
.put(modelManga.chapters![index].name!, model);
|
||||
},
|
||||
taskProgressCallback: (task, progress) async {
|
||||
if (progress == 1.0) {
|
||||
final downloadTask = DownloadTask(
|
||||
creationTime: task.creationTime,
|
||||
taskId: task.taskId,
|
||||
headers: task.headers,
|
||||
url: task.url,
|
||||
filename: task.filename,
|
||||
baseDirectory: task.baseDirectory,
|
||||
directory: task.directory,
|
||||
updates: task.updates,
|
||||
allowPause: task.allowPause,
|
||||
);
|
||||
if (Platform.isAndroid || Platform.isIOS) {
|
||||
await FileDownloader().moveToSharedStorage(
|
||||
downloadTask, SharedStorage.external,
|
||||
directory: finalPath);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
return urll;
|
||||
}
|
||||
121
lib/views/manga/download/providers/download_provider.g.dart
Normal file
121
lib/views/manga/download/providers/download_provider.g.dart
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'download_provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$downloadChapterHash() => r'39625ed8cba923709fe7c76788e334bec1d8bcc3';
|
||||
|
||||
/// Copied from Dart SDK
|
||||
class _SystemHash {
|
||||
_SystemHash._();
|
||||
|
||||
static int combine(int hash, int value) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + value);
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
|
||||
return hash ^ (hash >> 6);
|
||||
}
|
||||
|
||||
static int finish(int hash) {
|
||||
// ignore: parameter_assignments
|
||||
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
|
||||
// ignore: parameter_assignments
|
||||
hash = hash ^ (hash >> 11);
|
||||
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
|
||||
}
|
||||
}
|
||||
|
||||
typedef DownloadChapterRef = AutoDisposeFutureProviderRef<List<dynamic>>;
|
||||
|
||||
/// See also [downloadChapter].
|
||||
@ProviderFor(downloadChapter)
|
||||
const downloadChapterProvider = DownloadChapterFamily();
|
||||
|
||||
/// See also [downloadChapter].
|
||||
class DownloadChapterFamily extends Family<AsyncValue<List<dynamic>>> {
|
||||
/// See also [downloadChapter].
|
||||
const DownloadChapterFamily();
|
||||
|
||||
/// See also [downloadChapter].
|
||||
DownloadChapterProvider call({
|
||||
required ModelManga modelManga,
|
||||
required int index,
|
||||
}) {
|
||||
return DownloadChapterProvider(
|
||||
modelManga: modelManga,
|
||||
index: index,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
DownloadChapterProvider getProviderOverride(
|
||||
covariant DownloadChapterProvider provider,
|
||||
) {
|
||||
return call(
|
||||
modelManga: provider.modelManga,
|
||||
index: provider.index,
|
||||
);
|
||||
}
|
||||
|
||||
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'downloadChapterProvider';
|
||||
}
|
||||
|
||||
/// See also [downloadChapter].
|
||||
class DownloadChapterProvider extends AutoDisposeFutureProvider<List<dynamic>> {
|
||||
/// See also [downloadChapter].
|
||||
DownloadChapterProvider({
|
||||
required this.modelManga,
|
||||
required this.index,
|
||||
}) : super.internal(
|
||||
(ref) => downloadChapter(
|
||||
ref,
|
||||
modelManga: modelManga,
|
||||
index: index,
|
||||
),
|
||||
from: downloadChapterProvider,
|
||||
name: r'downloadChapterProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product')
|
||||
? null
|
||||
: _$downloadChapterHash,
|
||||
dependencies: DownloadChapterFamily._dependencies,
|
||||
allTransitiveDependencies:
|
||||
DownloadChapterFamily._allTransitiveDependencies,
|
||||
);
|
||||
|
||||
final ModelManga modelManga;
|
||||
final int index;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is DownloadChapterProvider &&
|
||||
other.modelManga == modelManga &&
|
||||
other.index == index;
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode {
|
||||
var hash = _SystemHash.combine(0, runtimeType.hashCode);
|
||||
hash = _SystemHash.combine(hash, modelManga.hashCode);
|
||||
hash = _SystemHash.combine(hash, index.hashCode);
|
||||
|
||||
return _SystemHash.finish(hash);
|
||||
}
|
||||
}
|
||||
// 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
|
||||
|
|
@ -146,29 +146,30 @@ class _ImageViewVerticalState extends ConsumerState<ImageViewVertical>
|
|||
return null;
|
||||
}),
|
||||
if (widget.index + 1 == widget.length)
|
||||
Column(
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
Text(
|
||||
'${widget.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,
|
||||
),
|
||||
],
|
||||
SizedBox(
|
||||
height: mediaHeight(context, 0.3),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Text(
|
||||
'${widget.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,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
|
|||
Loading…
Reference in a new issue