v1.0.1
This commit is contained in:
@@ -0,0 +1,147 @@
|
||||
import 'package:flutter_dmzj/app/controller/base_controller.dart';
|
||||
import 'package:flutter_dmzj/models/comic/detail_info.dart';
|
||||
import 'package:flutter_dmzj/requests/comic_request.dart';
|
||||
import 'package:flutter_dmzj/routes/app_navigator.dart';
|
||||
import 'package:flutter_dmzj/services/comic_download_service.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class ComicSelectChapterController extends BaseController {
|
||||
final int comicId;
|
||||
ComicSelectChapterController(this.comicId);
|
||||
final ComicRequest request = ComicRequest();
|
||||
|
||||
RxList<ComicDetailVolume> volumes = RxList<ComicDetailVolume>();
|
||||
|
||||
RxSet<int> chapterIds = RxSet<int>();
|
||||
|
||||
String comicTitle = "";
|
||||
String comicCover = "";
|
||||
bool islong = false;
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
loadDetail();
|
||||
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
void refreshV1() async {
|
||||
try {
|
||||
var result =
|
||||
await request.comicDetail(comicId: comicId, priorityV1: true);
|
||||
if (result.volumes.isEmpty) {
|
||||
SmartDialog.showToast("没有找到任何章节");
|
||||
return;
|
||||
}
|
||||
comicTitle = result.title;
|
||||
comicCover = result.cover;
|
||||
islong = result.isLong;
|
||||
for (var volume in result.volumes) {
|
||||
volume.sortType.value = 1;
|
||||
volume.sort();
|
||||
}
|
||||
volumes.value = result.volumes;
|
||||
} catch (e) {
|
||||
SmartDialog.showToast("无法获取章节");
|
||||
}
|
||||
}
|
||||
|
||||
/// 加载信息
|
||||
void loadDetail() async {
|
||||
try {
|
||||
pageLoadding.value = true;
|
||||
pageError.value = false;
|
||||
var result = await request.comicDetail(comicId: comicId);
|
||||
comicTitle = result.title;
|
||||
comicCover = result.cover;
|
||||
islong = result.isLong;
|
||||
if (result.volumes.isEmpty && !result.isHide) {
|
||||
refreshV1();
|
||||
} else {
|
||||
for (var volume in result.volumes) {
|
||||
volume.sortType.value = 1;
|
||||
volume.sort();
|
||||
}
|
||||
volumes.value = result.volumes;
|
||||
}
|
||||
} catch (e) {
|
||||
pageError.value = true;
|
||||
errorMsg.value = e.toString();
|
||||
} finally {
|
||||
pageLoadding.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
void selectItem(ComicDetailChapterItem item) {
|
||||
//禁止下载VIP章节
|
||||
if (item.isVip) {
|
||||
SmartDialog.showToast("请使用动漫之家官方APP下载VIP章节");
|
||||
return;
|
||||
}
|
||||
if (chapterIds.contains(item.chapterId)) {
|
||||
chapterIds.remove(item.chapterId);
|
||||
} else {
|
||||
chapterIds.add(item.chapterId);
|
||||
}
|
||||
}
|
||||
|
||||
void selectAll() {
|
||||
for (var volume in volumes) {
|
||||
for (var chapter in volume.chapters) {
|
||||
if (chapter.isVip) {
|
||||
continue;
|
||||
}
|
||||
var id = "${comicId}_${chapter.chapterId}";
|
||||
if (!ComicDownloadService.instance.downloadIds.contains(id)) {
|
||||
chapterIds.add(chapter.chapterId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void cleanAll() {
|
||||
chapterIds.clear();
|
||||
}
|
||||
|
||||
void toDownloadManage() {
|
||||
AppNavigator.toComicDownloadManage(1);
|
||||
}
|
||||
|
||||
void startDownload() {
|
||||
if (chapterIds.isEmpty) {
|
||||
SmartDialog.showToast("请选择需要下载的章节");
|
||||
return;
|
||||
}
|
||||
for (var id in chapterIds) {
|
||||
//搜索章节
|
||||
ComicDetailVolume? volume;
|
||||
ComicDetailChapterItem? chapter;
|
||||
for (var item in volumes) {
|
||||
var chapterItem =
|
||||
item.chapters.firstWhereOrNull((y) => y.chapterId == id);
|
||||
if (chapterItem != null) {
|
||||
volume = item;
|
||||
chapter = chapterItem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (volume == null || chapter == null) {
|
||||
continue;
|
||||
}
|
||||
ComicDownloadService.instance.addTask(
|
||||
comicId: comicId,
|
||||
chapterId: chapter.chapterId,
|
||||
chapterSort: chapter.chapterOrder,
|
||||
volumeName: volume.title,
|
||||
comicTitle: comicTitle,
|
||||
comicCover: comicCover,
|
||||
chapterName: chapter.chapterTitle,
|
||||
isVip: chapter.isVip,
|
||||
isLongComic: islong,
|
||||
);
|
||||
}
|
||||
chapterIds.clear();
|
||||
SmartDialog.showToast("已添加到下载列表,下载过程中请保持APP在前台运行");
|
||||
}
|
||||
}
|
||||
259
lib/modules/comic/select_chapter/comic_select_chapter_page.dart
Normal file
259
lib/modules/comic/select_chapter/comic_select_chapter_page.dart
Normal file
@@ -0,0 +1,259 @@
|
||||
import 'package:easy_refresh/easy_refresh.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_dmzj/app/app_style.dart';
|
||||
import 'package:flutter_dmzj/models/comic/detail_info.dart';
|
||||
import 'package:flutter_dmzj/modules/comic/select_chapter/comic_select_chapter_controller.dart';
|
||||
import 'package:flutter_dmzj/services/comic_download_service.dart';
|
||||
import 'package:flutter_dmzj/widgets/status/app_error_widget.dart';
|
||||
import 'package:flutter_dmzj/widgets/status/app_loadding_widget.dart';
|
||||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:remixicon/remixicon.dart';
|
||||
|
||||
class ComicSelectChapterPage extends StatelessWidget {
|
||||
final int comicId;
|
||||
final ComicSelectChapterController controller;
|
||||
ComicSelectChapterPage(this.comicId, {super.key})
|
||||
: controller = Get.put(
|
||||
ComicSelectChapterController(comicId),
|
||||
tag: DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: const Text("选择下载章节"),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: controller.toDownloadManage,
|
||||
child: const Text("下载管理"),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: Stack(
|
||||
children: [
|
||||
EasyRefresh(
|
||||
header: const MaterialHeader(),
|
||||
onRefresh: controller.loadDetail,
|
||||
child: _buildVolumes(),
|
||||
),
|
||||
Obx(
|
||||
() => Offstage(
|
||||
offstage: !controller.pageLoadding.value,
|
||||
child: const AppLoaddingWidget(),
|
||||
),
|
||||
),
|
||||
Obx(
|
||||
() => Offstage(
|
||||
offstage: !controller.pageError.value,
|
||||
child: AppErrorWidget(
|
||||
errorMsg: controller.errorMsg.value,
|
||||
onRefresh: () => controller.loadDetail(),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
bottomNavigationBar: BottomAppBar(
|
||||
child: SizedBox(
|
||||
height: 48,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextButton.icon(
|
||||
style: TextButton.styleFrom(
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
),
|
||||
onPressed: controller.selectAll,
|
||||
icon: const Icon(
|
||||
Remix.checkbox_line,
|
||||
size: 20,
|
||||
),
|
||||
label: const Text("全选"),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextButton.icon(
|
||||
style: TextButton.styleFrom(
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
),
|
||||
onPressed: controller.cleanAll,
|
||||
icon: const Icon(
|
||||
Remix.checkbox_blank_line,
|
||||
size: 20,
|
||||
),
|
||||
label: const Text("取消选中"),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextButton.icon(
|
||||
style: TextButton.styleFrom(
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
),
|
||||
onPressed: controller.startDownload,
|
||||
icon: const Icon(
|
||||
Remix.download_line,
|
||||
size: 20,
|
||||
),
|
||||
label:
|
||||
Obx(() => Text("下载选中(${controller.chapterIds.length})")),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildVolumes() {
|
||||
return Obx(
|
||||
() => ListView.builder(
|
||||
padding: AppStyle.edgeInsetsA12,
|
||||
itemCount: controller.volumes.length,
|
||||
itemBuilder: (_, i) {
|
||||
var item = controller.volumes[i];
|
||||
return _buildChapters(item);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildChapters(ComicDetailVolume item) {
|
||||
return Obx(
|
||||
() => Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Padding(
|
||||
padding: AppStyle.edgeInsetsV8,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
"${item.title}(共${item.chapters.length}话)",
|
||||
style: Get.textTheme.titleSmall,
|
||||
),
|
||||
),
|
||||
item.sortType.value == 1
|
||||
? TextButton.icon(
|
||||
style: TextButton.styleFrom(
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
onPressed: () {
|
||||
item.sortType.value = 0;
|
||||
item.sort();
|
||||
},
|
||||
icon: const Icon(
|
||||
Remix.sort_asc,
|
||||
size: 20,
|
||||
),
|
||||
label: const Text("升序"),
|
||||
)
|
||||
: TextButton.icon(
|
||||
style: TextButton.styleFrom(
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
),
|
||||
onPressed: () {
|
||||
item.sortType.value = 1;
|
||||
item.sort();
|
||||
},
|
||||
icon: const Icon(
|
||||
Remix.sort_desc,
|
||||
size: 20,
|
||||
),
|
||||
label: const Text("倒序"),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
LayoutBuilder(builder: (ctx, constraints) {
|
||||
var count = constraints.maxWidth ~/ 160;
|
||||
if (count < 3) count = 3;
|
||||
|
||||
return Obx(
|
||||
() => MasonryGridView.count(
|
||||
shrinkWrap: true,
|
||||
padding: EdgeInsets.zero,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
itemCount: (item.showMoreButton && !item.showAll.value)
|
||||
? 15
|
||||
: item.chapters.length,
|
||||
itemBuilder: (_, i) {
|
||||
if (item.showMoreButton && !item.showAll.value && i == 14) {
|
||||
return Tooltip(
|
||||
message: "展开全部章节",
|
||||
child: OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: Colors.grey,
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
minimumSize: const Size.fromHeight(40),
|
||||
),
|
||||
onPressed: () {
|
||||
item.showAll.value = true;
|
||||
},
|
||||
child: const Icon(Icons.arrow_drop_down),
|
||||
),
|
||||
);
|
||||
}
|
||||
var chapter = item.chapters[i];
|
||||
|
||||
return Tooltip(
|
||||
message: chapter.chapterTitle,
|
||||
child: Obx(
|
||||
() => Stack(
|
||||
children: [
|
||||
OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: controller.chapterIds
|
||||
.contains(chapter.chapterId)
|
||||
? Get.theme.colorScheme.primary
|
||||
: Get.textTheme.bodyMedium!.color,
|
||||
side: controller.chapterIds
|
||||
.contains(chapter.chapterId)
|
||||
? BorderSide(color: Get.theme.colorScheme.primary)
|
||||
: null,
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
minimumSize: const Size.fromHeight(40),
|
||||
),
|
||||
onPressed: ComicDownloadService.instance.downloadIds
|
||||
.contains("${comicId}_${chapter.chapterId}")
|
||||
? null
|
||||
: () => controller.selectItem(chapter),
|
||||
child: Text(
|
||||
item.chapters[i].chapterTitle,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
left: -2,
|
||||
top: 0,
|
||||
child: Offstage(
|
||||
offstage: !item.chapters[i].isVip,
|
||||
child: Image.asset(
|
||||
"assets/images/vip_chapter.png",
|
||||
height: 16,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
crossAxisCount: count,
|
||||
crossAxisSpacing: 8,
|
||||
mainAxisSpacing: 8,
|
||||
),
|
||||
);
|
||||
})
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user