v1.0.1
This commit is contained in:
49
lib/modules/common/download/comic/comic_download_page.dart
Normal file
49
lib/modules/common/download/comic/comic_download_page.dart
Normal file
@@ -0,0 +1,49 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_dmzj/modules/common/download/comic/comic_downloaded_view.dart';
|
||||
import 'package:flutter_dmzj/modules/common/download/comic/comic_downloading_view.dart';
|
||||
import 'package:flutter_dmzj/services/comic_download_service.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class ComicDownloadPage extends StatelessWidget {
|
||||
final int type;
|
||||
const ComicDownloadPage(this.type, {super.key});
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return DefaultTabController(
|
||||
length: 2,
|
||||
initialIndex: type,
|
||||
child: Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Container(
|
||||
alignment: Alignment.center,
|
||||
padding: const EdgeInsets.only(right: 56),
|
||||
child: TabBar(
|
||||
isScrollable: true,
|
||||
tabAlignment: TabAlignment.start,
|
||||
indicatorSize: TabBarIndicatorSize.label,
|
||||
indicatorColor: Theme.of(context).colorScheme.primary,
|
||||
labelColor: Theme.of(context).colorScheme.primary,
|
||||
unselectedLabelColor:
|
||||
Get.isDarkMode ? Colors.white70 : Colors.black87,
|
||||
tabs: [
|
||||
const Tab(text: "已完成"),
|
||||
Obx(
|
||||
() => Tab(
|
||||
text: ComicDownloadService.instance.taskQueues.isEmpty
|
||||
? "下载中"
|
||||
: "下载中(${ComicDownloadService.instance.taskQueues.length})"),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
body: const TabBarView(
|
||||
children: [
|
||||
ComicDownloadedView(),
|
||||
ComicDownloadingView(),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,182 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:flutter_dmzj/app/event_bus.dart';
|
||||
import 'package:flutter_dmzj/models/comic/detail_info.dart';
|
||||
import 'package:flutter_dmzj/models/db/comic_history.dart';
|
||||
import 'package:flutter_dmzj/routes/app_navigator.dart';
|
||||
import 'package:flutter_dmzj/services/comic_download_service.dart';
|
||||
import 'package:flutter_dmzj/services/db_service.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class ComicDownloadedDetailController extends GetxController {
|
||||
final ComicDownloadedItem info;
|
||||
ComicDownloadedDetailController(this.info);
|
||||
|
||||
/// 阅读记录
|
||||
Rx<ComicHistory?> history = Rx<ComicHistory?>(null);
|
||||
|
||||
/// 更新漫画记录
|
||||
StreamSubscription<dynamic>? updateComicSubscription;
|
||||
|
||||
/// 编辑模式
|
||||
var editMode = false.obs;
|
||||
|
||||
RxSet<ComicDetailChapterItem> selectItems = RxSet<ComicDetailChapterItem>();
|
||||
|
||||
@override
|
||||
void onInit() {
|
||||
updateComicSubscription = EventBus.instance.listen(
|
||||
EventBus.kUpdatedComicHistory,
|
||||
(id) {
|
||||
if (id == info.comicId) {
|
||||
getHistory();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
getHistory();
|
||||
|
||||
super.onInit();
|
||||
}
|
||||
|
||||
@override
|
||||
void onClose() {
|
||||
updateComicSubscription?.cancel();
|
||||
super.onClose();
|
||||
}
|
||||
|
||||
void getHistory() {
|
||||
var comicHistory = DBService.instance.getComicHistory(info.comicId);
|
||||
if (comicHistory != null) {
|
||||
history.value = comicHistory;
|
||||
history.update((val) {});
|
||||
}
|
||||
}
|
||||
|
||||
/// 开始/继续阅读
|
||||
void read() {
|
||||
if (info.volumes.isEmpty) {
|
||||
SmartDialog.showToast("没有可阅读的章节");
|
||||
return;
|
||||
}
|
||||
if (info.volumes.first.chapters.isEmpty) {
|
||||
SmartDialog.showToast("没有可阅读的章节");
|
||||
return;
|
||||
}
|
||||
//查找记录
|
||||
if (history.value != null && history.value!.chapterId != 0) {
|
||||
ComicDetailVolume? volume;
|
||||
ComicDetailChapterItem? chapter;
|
||||
for (var volumeItem in info.volumes) {
|
||||
var chapterItem = volumeItem.chapters.firstWhereOrNull(
|
||||
(x) => x.chapterId == history.value!.chapterId,
|
||||
);
|
||||
if (chapterItem != null) {
|
||||
volume = volumeItem;
|
||||
chapter = chapterItem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (volume != null && chapter != null) {
|
||||
var chapters = List<ComicDetailChapterItem>.from(volume.chapters);
|
||||
//正序
|
||||
chapters.sort((a, b) => a.chapterOrder.compareTo(b.chapterOrder));
|
||||
AppNavigator.toComicReader(
|
||||
comicId: info.comicId,
|
||||
comicTitle: info.comicName,
|
||||
comicCover: info.comicCover,
|
||||
chapters: chapters,
|
||||
chapter: chapter,
|
||||
isLongComic: info.isLongComic,
|
||||
);
|
||||
} else {
|
||||
SmartDialog.showToast("未找到历史记录对应章节,将从头开始阅读");
|
||||
readStart();
|
||||
}
|
||||
} else {
|
||||
readStart();
|
||||
}
|
||||
}
|
||||
|
||||
void readStart() {
|
||||
//从头开始
|
||||
var volume = info.volumes.first;
|
||||
var chapters = List<ComicDetailChapterItem>.from(volume.chapters);
|
||||
//正序
|
||||
chapters.sort((a, b) => a.chapterOrder.compareTo(b.chapterOrder));
|
||||
var chapter = chapters.first;
|
||||
AppNavigator.toComicReader(
|
||||
comicId: info.comicId,
|
||||
comicCover: info.comicCover,
|
||||
comicTitle: info.comicName,
|
||||
chapters: chapters,
|
||||
chapter: chapter,
|
||||
isLongComic: info.isLongComic,
|
||||
);
|
||||
}
|
||||
|
||||
void readChapter(ComicDetailVolume volume, ComicDetailChapterItem item) {
|
||||
var chapters = List<ComicDetailChapterItem>.from(volume.chapters);
|
||||
//正序
|
||||
chapters.sort((a, b) => a.chapterOrder.compareTo(b.chapterOrder));
|
||||
AppNavigator.toComicReader(
|
||||
comicId: info.comicId,
|
||||
comicCover: info.comicCover,
|
||||
comicTitle: info.comicName,
|
||||
chapters: chapters,
|
||||
chapter: item,
|
||||
isLongComic: info.isLongComic,
|
||||
);
|
||||
}
|
||||
|
||||
void toDetail() {
|
||||
AppNavigator.toComicDetail(info.comicId);
|
||||
}
|
||||
|
||||
void toAddDownload() {
|
||||
AppNavigator.toComicDownloadSelect(info.comicId);
|
||||
}
|
||||
|
||||
void setEditMode() {
|
||||
selectItems.clear();
|
||||
editMode.value = true;
|
||||
}
|
||||
|
||||
void exitEditMode() {
|
||||
selectItems.clear();
|
||||
editMode.value = false;
|
||||
}
|
||||
|
||||
var isSelectAll = false;
|
||||
void selectAll() {
|
||||
if (isSelectAll) {
|
||||
selectItems.clear();
|
||||
isSelectAll = false;
|
||||
return;
|
||||
}
|
||||
for (var volume in info.volumes) {
|
||||
for (var chapter in volume.chapters) {
|
||||
selectItems.add(chapter);
|
||||
}
|
||||
}
|
||||
isSelectAll = true;
|
||||
}
|
||||
|
||||
void delete() {
|
||||
for (var item in selectItems) {
|
||||
ComicDownloadService.instance.deleteChapter(info.comicId, item.chapterId);
|
||||
}
|
||||
exitEditMode();
|
||||
SmartDialog.showToast("删除成功");
|
||||
AppNavigator.closePage();
|
||||
}
|
||||
|
||||
void selectItem(ComicDetailChapterItem item) {
|
||||
if (selectItems.contains(item)) {
|
||||
selectItems.remove(item.chapterId);
|
||||
} else {
|
||||
selectItems.add(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,292 @@
|
||||
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/common/download/comic/comic_downloaded_detail_controller.dart';
|
||||
|
||||
import 'package:flutter_dmzj/services/comic_download_service.dart';
|
||||
import 'package:flutter_staggered_grid_view/flutter_staggered_grid_view.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:remixicon/remixicon.dart';
|
||||
|
||||
class ComicDownloadedDetailPage extends StatelessWidget {
|
||||
final ComicDownloadedItem info;
|
||||
final ComicDownloadedDetailController controller;
|
||||
ComicDownloadedDetailPage(this.info, {super.key})
|
||||
: controller = Get.put(
|
||||
ComicDownloadedDetailController(info),
|
||||
tag: DateTime.now().millisecondsSinceEpoch.toString(),
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(info.comicName),
|
||||
),
|
||||
body: ListView.builder(
|
||||
padding: AppStyle.edgeInsetsA12,
|
||||
itemCount: info.volumes.length,
|
||||
itemBuilder: (_, i) {
|
||||
var item = info.volumes[i];
|
||||
return _buildChapters(item);
|
||||
},
|
||||
),
|
||||
bottomNavigationBar: BottomAppBar(
|
||||
child: SizedBox(
|
||||
height: 48,
|
||||
child: Obx(
|
||||
() => Column(
|
||||
children: [
|
||||
Visibility(
|
||||
visible: !controller.editMode.value,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextButton.icon(
|
||||
style: TextButton.styleFrom(
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
),
|
||||
onPressed: controller.setEditMode,
|
||||
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.toDetail,
|
||||
icon: const Icon(
|
||||
Remix.information_line,
|
||||
size: 20,
|
||||
),
|
||||
label: const Text("详情"),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextButton.icon(
|
||||
style: TextButton.styleFrom(
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
),
|
||||
onPressed: controller.toAddDownload,
|
||||
icon: const Icon(
|
||||
Remix.add_line,
|
||||
size: 20,
|
||||
),
|
||||
label: const Text("追加"),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextButton.icon(
|
||||
style: TextButton.styleFrom(
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
),
|
||||
onPressed: controller.read,
|
||||
icon: const Icon(
|
||||
Remix.play_line,
|
||||
size: 20,
|
||||
),
|
||||
label: const Text("阅读"),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Visibility(
|
||||
visible: controller.editMode.value,
|
||||
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.delete,
|
||||
icon: const Icon(
|
||||
Remix.delete_bin_line,
|
||||
size: 20,
|
||||
),
|
||||
label: const Text("删除"),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextButton.icon(
|
||||
style: TextButton.styleFrom(
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
),
|
||||
onPressed: controller.exitEditMode,
|
||||
icon: const Icon(
|
||||
Remix.close_line,
|
||||
size: 20,
|
||||
),
|
||||
label: const Text("取消"),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
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(
|
||||
() => controller.editMode.value
|
||||
? OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor:
|
||||
controller.selectItems.contains(chapter)
|
||||
? Get.theme.colorScheme.primary
|
||||
: Get.textTheme.bodyMedium!.color,
|
||||
side: controller.selectItems.contains(chapter)
|
||||
? BorderSide(color: Get.theme.colorScheme.primary)
|
||||
: null,
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
minimumSize: const Size.fromHeight(40),
|
||||
),
|
||||
onPressed: () {
|
||||
controller.selectItem(chapter);
|
||||
},
|
||||
child: Text(
|
||||
item.chapters[i].chapterTitle,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
)
|
||||
: OutlinedButton(
|
||||
style: OutlinedButton.styleFrom(
|
||||
foregroundColor: item.chapters[i].chapterId ==
|
||||
controller.history.value?.chapterId
|
||||
? Get.theme.colorScheme.primary
|
||||
: Get.textTheme.bodyMedium!.color,
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
minimumSize: const Size.fromHeight(40),
|
||||
),
|
||||
onPressed: () {
|
||||
controller.readChapter(item, chapter);
|
||||
},
|
||||
child: Text(
|
||||
item.chapters[i].chapterTitle,
|
||||
textAlign: TextAlign.center,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
crossAxisCount: count,
|
||||
crossAxisSpacing: 8,
|
||||
mainAxisSpacing: 8,
|
||||
),
|
||||
);
|
||||
})
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
89
lib/modules/common/download/comic/comic_downloaded_view.dart
Normal file
89
lib/modules/common/download/comic/comic_downloaded_view.dart
Normal file
@@ -0,0 +1,89 @@
|
||||
import 'package:easy_refresh/easy_refresh.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_dmzj/app/app_style.dart';
|
||||
import 'package:flutter_dmzj/routes/app_navigator.dart';
|
||||
|
||||
import 'package:flutter_dmzj/services/comic_download_service.dart';
|
||||
import 'package:flutter_dmzj/widgets/net_image.dart';
|
||||
import 'package:flutter_dmzj/widgets/status/app_empty_widget.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
class ComicDownloadedView extends StatelessWidget {
|
||||
const ComicDownloadedView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Obx(
|
||||
() => Stack(
|
||||
children: [
|
||||
EasyRefresh(
|
||||
header: const MaterialHeader(),
|
||||
onRefresh: () async {
|
||||
ComicDownloadService.instance.updateDownlaoded();
|
||||
},
|
||||
child: ListView.separated(
|
||||
itemCount: ComicDownloadService.instance.downloaded.length,
|
||||
separatorBuilder: (_, i) => Divider(
|
||||
endIndent: 12,
|
||||
indent: 12,
|
||||
color: Colors.grey.withOpacity(.2),
|
||||
height: 1,
|
||||
),
|
||||
itemBuilder: (_, i) {
|
||||
var item = ComicDownloadService.instance.downloaded[i];
|
||||
return buildItem(item);
|
||||
},
|
||||
),
|
||||
),
|
||||
Offstage(
|
||||
offstage: ComicDownloadService.instance.downloaded.isNotEmpty,
|
||||
child: AppEmptyWidget(
|
||||
onRefresh: () {
|
||||
ComicDownloadService.instance.updateDownlaoded();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildItem(ComicDownloadedItem item) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
AppNavigator.toComicDownloadDetail(item);
|
||||
},
|
||||
child: Container(
|
||||
padding: AppStyle.edgeInsetsA12,
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
NetImage(
|
||||
item.comicCover,
|
||||
width: 60,
|
||||
borderRadius: 4,
|
||||
),
|
||||
AppStyle.hGap12,
|
||||
Expanded(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
item.comicName,
|
||||
maxLines: 1,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
AppStyle.vGap4,
|
||||
Text(
|
||||
"已下载${item.chapterCount}章",
|
||||
style: const TextStyle(color: Colors.grey, fontSize: 14),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
225
lib/modules/common/download/comic/comic_downloading_view.dart
Normal file
225
lib/modules/common/download/comic/comic_downloading_view.dart
Normal file
@@ -0,0 +1,225 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_dmzj/app/app_style.dart';
|
||||
import 'package:flutter_dmzj/models/db/download_status.dart';
|
||||
import 'package:flutter_dmzj/services/comic_download_service.dart';
|
||||
import 'package:flutter_dmzj/services/download_task/comic_downloader.dart';
|
||||
import 'package:flutter_dmzj/widgets/status/app_empty_widget.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:remixicon/remixicon.dart';
|
||||
|
||||
class ComicDownloadingView extends StatelessWidget {
|
||||
const ComicDownloadingView({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Obx(
|
||||
() => Stack(
|
||||
children: [
|
||||
ListView.separated(
|
||||
itemCount: ComicDownloadService.instance.taskQueues.length,
|
||||
separatorBuilder: (_, i) => const Divider(
|
||||
height: 1,
|
||||
),
|
||||
itemBuilder: (_, i) {
|
||||
var task = ComicDownloadService.instance.taskQueues[i];
|
||||
return buildItem(task);
|
||||
},
|
||||
),
|
||||
Offstage(
|
||||
offstage: ComicDownloadService.instance.taskQueues.isNotEmpty,
|
||||
child: const AppEmptyWidget(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
BottomAppBar(
|
||||
child: SizedBox(
|
||||
height: 48,
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextButton.icon(
|
||||
style: TextButton.styleFrom(
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
),
|
||||
onPressed: ComicDownloadService.instance.pauseAll,
|
||||
icon: const Icon(
|
||||
Remix.pause_line,
|
||||
size: 20,
|
||||
),
|
||||
label: const Text("暂停全部"),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: TextButton.icon(
|
||||
style: TextButton.styleFrom(
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
),
|
||||
onPressed: ComicDownloadService.instance.resumeAll,
|
||||
icon: const Icon(
|
||||
Remix.download_line,
|
||||
size: 20,
|
||||
),
|
||||
label: const Text("开始全部"),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget buildItem(ComicDownloader task) {
|
||||
return Obx(
|
||||
() => Padding(
|
||||
padding: AppStyle.edgeInsetsA12,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
"${task.info.value.volumeName} - ${task.info.value.chapterName}",
|
||||
),
|
||||
Text(
|
||||
task.info.value.comicName,
|
||||
style: Get.textTheme.bodySmall,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: ClipRRect(
|
||||
borderRadius: AppStyle.radius4,
|
||||
child: LinearProgressIndicator(
|
||||
value: task.info.value.total > 0
|
||||
? (task.info.value.index + 1) / task.info.value.total
|
||||
: 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
AppStyle.hGap8,
|
||||
Text(
|
||||
"${task.info.value.index + 1}/${task.info.value.total}",
|
||||
style: Get.textTheme.bodySmall,
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
parseStatus(task.info.value.status),
|
||||
style: Get.textTheme.bodySmall,
|
||||
),
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
buildButton(
|
||||
icon: Icons.refresh_rounded,
|
||||
text: "重试",
|
||||
visible: task.status == DownloadStatus.error ||
|
||||
task.status == DownloadStatus.errorLoad,
|
||||
onPressed: () {
|
||||
task.retry();
|
||||
},
|
||||
),
|
||||
buildButton(
|
||||
icon: Icons.play_arrow_rounded,
|
||||
visible: task.status == DownloadStatus.wait ||
|
||||
task.status == DownloadStatus.pauseCellular,
|
||||
text: "开始",
|
||||
onPressed: () {
|
||||
task.start();
|
||||
},
|
||||
),
|
||||
buildButton(
|
||||
icon: Icons.play_arrow_rounded,
|
||||
visible: task.status == DownloadStatus.pause,
|
||||
text: "继续",
|
||||
onPressed: () {
|
||||
task.resume();
|
||||
},
|
||||
),
|
||||
buildButton(
|
||||
icon: Icons.pause_rounded,
|
||||
visible: task.status == DownloadStatus.downloading,
|
||||
text: "暂停",
|
||||
onPressed: () {
|
||||
task.pause();
|
||||
},
|
||||
),
|
||||
buildButton(
|
||||
icon: Icons.cancel_outlined,
|
||||
text: "取消",
|
||||
onPressed: () {
|
||||
task.cancel();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
String parseStatus(DownloadStatus status) {
|
||||
switch (status) {
|
||||
case DownloadStatus.cancel:
|
||||
return "已取消";
|
||||
case DownloadStatus.complete:
|
||||
return "已完成";
|
||||
case DownloadStatus.downloading:
|
||||
return "下载中";
|
||||
case DownloadStatus.error:
|
||||
return "下载失败";
|
||||
case DownloadStatus.errorLoad:
|
||||
return "无法读取信息";
|
||||
case DownloadStatus.loadding:
|
||||
return "读取信息中";
|
||||
case DownloadStatus.pause:
|
||||
return "暂停中";
|
||||
case DownloadStatus.pauseCellular:
|
||||
return "等待Wi-Fi";
|
||||
case DownloadStatus.wait:
|
||||
return "等待下载";
|
||||
case DownloadStatus.waitNetwork:
|
||||
return "等待网络连接";
|
||||
default:
|
||||
return status.toString();
|
||||
}
|
||||
}
|
||||
|
||||
Widget buildButton({
|
||||
required String text,
|
||||
required IconData icon,
|
||||
Function()? onPressed,
|
||||
bool visible = true,
|
||||
}) {
|
||||
return Visibility(
|
||||
visible: visible,
|
||||
child: Padding(
|
||||
padding: AppStyle.edgeInsetsL4,
|
||||
child: TextButton.icon(
|
||||
style: TextButton.styleFrom(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
textStyle: const TextStyle(fontSize: 14),
|
||||
),
|
||||
onPressed: onPressed,
|
||||
icon: Icon(
|
||||
icon,
|
||||
size: 16,
|
||||
),
|
||||
label: Text(text),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user