This commit is contained in:
2026-03-07 17:24:59 +08:00
parent 4418ebecac
commit b0ec8ab4bd
417 changed files with 42546 additions and 2 deletions

View File

@@ -0,0 +1,126 @@
import 'package:flutter_dmzj/app/controller/base_controller.dart';
import 'package:flutter_dmzj/models/novel/novel_detail_model.dart';
import 'package:flutter_dmzj/requests/novel_request.dart';
import 'package:flutter_dmzj/routes/app_navigator.dart';
import 'package:flutter_dmzj/services/novel_download_service.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
class NovelSelectChapterController extends BaseController {
final int novelId;
NovelSelectChapterController(this.novelId);
final NovelRequest request = NovelRequest();
RxList<NovelDetailVolume> volumes = RxList<NovelDetailVolume>();
String novelTitle = "";
String novelCover = "";
RxMap<int, RxSet<int>> selectIds = RxMap<int, RxSet<int>>();
@override
void onInit() {
loadDetail();
super.onInit();
}
/// 加载信息
void loadDetail() async {
try {
pageLoadding.value = true;
pageError.value = false;
var result = await request.novelDetail(novelId: novelId);
novelTitle = result.data.name;
novelCover = result.data.cover;
var chpaterResult = await request.novelChapter(novelId: novelId);
var ls = chpaterResult.map((e) => NovelDetailVolume.fromJson(e)).toList();
selectIds.value = {};
for (var item in ls) {
selectIds.addAll({
item.volumeId: RxSet<int>(),
});
}
volumes.value = ls;
} catch (e) {
pageError.value = true;
errorMsg.value = e.toString();
} finally {
pageLoadding.value = false;
}
}
void selectItem(NovelDetailChapter item) {
var chapterIds = selectIds[item.volumeId]!;
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) {
var chapterIds = selectIds[volume.volumeId]!;
var id = "${novelId}_${volume.volumeId}_${chapter.chapterId}";
if (!NovelDownloadService.instance.downloadIds.contains(id)) {
chapterIds.add(chapter.chapterId);
}
}
}
}
void cleanAll() {
for (var volume in selectIds.values) {
volume.clear();
}
}
void toDownloadManage() {
AppNavigator.toNovelDownloadManage(1);
}
void startDownload() {
var chapterIds = <int>[];
for (var item in selectIds.values) {
chapterIds.addAll(item);
}
if (chapterIds.isEmpty) {
SmartDialog.showToast("请选择需要下载的章节");
return;
}
for (var id in chapterIds) {
//搜索章节
NovelDetailVolume? volume;
NovelDetailChapter? 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;
}
NovelDownloadService.instance.addTask(
novelId: novelId,
chapterId: chapter.chapterId,
chapterSort: chapter.chapterOrder,
volumeName: volume.volumeName,
novelTitle: novelTitle,
novelCover: novelCover,
chapterName: chapter.chapterName,
isVip: false,
volumeId: volume.volumeId,
volumeOrder: volume.volumeOrder,
);
}
cleanAll();
SmartDialog.showToast("已添加到下载列表下载过程中请保持APP在前台运行");
}
}

View File

@@ -0,0 +1,175 @@
import 'package:easy_refresh/easy_refresh.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dmzj/models/novel/novel_detail_model.dart';
import 'package:flutter_dmzj/modules/novel/select_chapter/novel_select_chapter_controller.dart';
import 'package:flutter_dmzj/services/novel_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:get/get.dart';
import 'package:remixicon/remixicon.dart';
class NovelSelectChapterPage extends StatelessWidget {
final int novelId;
final NovelSelectChapterController controller;
NovelSelectChapterPage(this.novelId, {super.key})
: controller = Get.put(
NovelSelectChapterController(novelId),
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: const Text("下载选中"),
),
),
],
),
),
),
);
}
Widget _buildVolumes() {
return Obx(
() => ListView.builder(
padding: EdgeInsets.zero,
itemCount: controller.volumes.length,
itemBuilder: (_, i) {
var item = controller.volumes[i];
return _buildChapters(item);
},
),
);
}
Widget _buildChapters(NovelDetailVolume item) {
return Obx(
() {
var volume = controller.selectIds[item.volumeId]!;
return ExpansionTile(
title: Text("${item.volumeName}(共${item.chapters.length}话)"),
leading: SizedBox(
width: 40,
child: Checkbox(
value: volume.length == item.chapters.length,
onChanged: (e) {
if (e!) {
volume.addAll(
item.chapters
.where((x) => !NovelDownloadService.instance.downloadIds
.contains(
"${novelId}_${x.volumeId}_${x.chapterId}"))
.map((e) => e.chapterId),
);
} else {
volume.clear();
}
},
),
),
children: item.chapters
.map(
(chapter) => CheckboxListTile(
value: volume.contains(chapter.chapterId),
controlAffinity: ListTileControlAffinity.leading,
title: Text(
chapter.chapterName,
style: Get.textTheme.titleSmall,
),
enabled: !NovelDownloadService.instance.downloadIds.contains(
"${novelId}_${chapter.volumeId}_${chapter.chapterId}"),
subtitle: NovelDownloadService.instance.downloadIds.contains(
"${novelId}_${chapter.volumeId}_${chapter.chapterId}")
? const Text("已下载")
: null,
onChanged: (e) {
if (e!) {
volume.add(chapter.chapterId);
} else {
volume.remove(chapter.chapterId);
}
},
),
)
.toList(),
);
},
);
}
}