mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-08-06 02:30:12 +08:00
opt download (#1755)
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -1,21 +1,24 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/common/widgets/appbar/appbar.dart';
|
||||
import 'package:PiliPlus/common/widgets/badge.dart';
|
||||
import 'package:PiliPlus/common/widgets/dialog/dialog.dart';
|
||||
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
||||
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
|
||||
import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart';
|
||||
import 'package:PiliPlus/common/widgets/select_mask.dart';
|
||||
import 'package:PiliPlus/models/common/badge_type.dart';
|
||||
import 'package:PiliPlus/models_new/download/download_info.dart';
|
||||
import 'package:PiliPlus/pages/download/controller.dart';
|
||||
import 'package:PiliPlus/pages/download/detail/view.dart';
|
||||
import 'package:PiliPlus/pages/download/detail/widgets/item.dart';
|
||||
import 'package:PiliPlus/pages/download/search/view.dart';
|
||||
import 'package:PiliPlus/services/download/download_service.dart';
|
||||
import 'package:PiliPlus/utils/grid.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/material.dart'
|
||||
hide SliverGridDelegateWithMaxCrossAxisExtent;
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
|
||||
@@ -26,7 +29,7 @@ class DownloadPage extends StatefulWidget {
|
||||
State<DownloadPage> createState() => _DownloadPageState();
|
||||
}
|
||||
|
||||
class _DownloadPageState extends State<DownloadPage> with GridMixin {
|
||||
class _DownloadPageState extends State<DownloadPage> {
|
||||
final _downloadService = Get.find<DownloadService>();
|
||||
final _controller = Get.put(DownloadPageController());
|
||||
final _progress = ValueNotifier(null);
|
||||
@@ -40,123 +43,232 @@ class _DownloadPageState extends State<DownloadPage> with GridMixin {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(title: const Text('离线缓存')),
|
||||
body: CustomScrollView(
|
||||
slivers: [
|
||||
ViewSliverSafeArea(
|
||||
sliver: Obx(() {
|
||||
if (_controller.pages.isNotEmpty) {
|
||||
return SliverGrid.builder(
|
||||
gridDelegate: gridDelegate,
|
||||
itemBuilder: (context, index) {
|
||||
final item = _controller.pages[index];
|
||||
if (item.entrys.length == 1) {
|
||||
final entry = item.entrys.first;
|
||||
return DetailItem(
|
||||
entry: entry,
|
||||
progress: _progress,
|
||||
downloadService: _downloadService,
|
||||
showTitle: true,
|
||||
onDelete: () {
|
||||
_downloadService.deleteDownload(entry: entry);
|
||||
GStorage.watchProgress.delete(entry.cid.toString());
|
||||
},
|
||||
);
|
||||
}
|
||||
return _buildItem(theme, item);
|
||||
final padding = MediaQuery.viewPaddingOf(context);
|
||||
return Obx(() {
|
||||
final enableMultiSelect = _controller.enableMultiSelect.value;
|
||||
return PopScope(
|
||||
canPop: !enableMultiSelect,
|
||||
onPopInvokedWithResult: (didPop, result) {
|
||||
if (enableMultiSelect) {
|
||||
_controller.handleSelect();
|
||||
}
|
||||
},
|
||||
child: Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: MultiSelectAppBarWidget(
|
||||
ctr: _controller,
|
||||
child: AppBar(
|
||||
title: const Text('离线缓存'),
|
||||
actions: [
|
||||
IconButton(
|
||||
tooltip: '搜索',
|
||||
onPressed: () async {
|
||||
await _downloadService.waitForInitialization;
|
||||
if (!mounted) return;
|
||||
Get.to(DownloadSearchPage(progress: _progress));
|
||||
},
|
||||
itemCount: _controller.pages.length,
|
||||
);
|
||||
}
|
||||
return const HttpError();
|
||||
}),
|
||||
icon: const Icon(Icons.search),
|
||||
),
|
||||
IconButton(
|
||||
tooltip: '多选',
|
||||
onPressed: () {
|
||||
if (enableMultiSelect) {
|
||||
_controller.handleSelect();
|
||||
} else {
|
||||
_controller.enableMultiSelect.value = true;
|
||||
}
|
||||
},
|
||||
icon: const Icon(Icons.edit_note),
|
||||
),
|
||||
const SizedBox(width: 6),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
body: Padding(
|
||||
padding: EdgeInsets.only(left: padding.left, right: padding.right),
|
||||
child: CustomScrollView(
|
||||
slivers: [
|
||||
Obx(() {
|
||||
final entry =
|
||||
_downloadService.waitDownloadQueue.firstWhereOrNull(
|
||||
(e) => e.cid == _downloadService.curCid,
|
||||
) ??
|
||||
_downloadService.waitDownloadQueue.firstOrNull;
|
||||
if (entry != null) {
|
||||
return SliverMainAxisGroup(
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: const EdgeInsets.only(left: 12, bottom: 7),
|
||||
sliver: SliverToBoxAdapter(
|
||||
child: Text(
|
||||
'正在缓存 (${_downloadService.waitDownloadQueue.length})',
|
||||
),
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
child: SizedBox(
|
||||
height: 100,
|
||||
child: DetailItem(
|
||||
entry: entry,
|
||||
progress: _progress,
|
||||
downloadService: _downloadService,
|
||||
showTitle: true,
|
||||
isCurr: true,
|
||||
controller: _controller,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
return const SliverToBoxAdapter();
|
||||
}),
|
||||
Obx(() {
|
||||
if (_controller.pages.isNotEmpty) {
|
||||
return SliverMainAxisGroup(
|
||||
slivers: [
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 12,
|
||||
bottom: 7,
|
||||
top: _downloadService.waitDownloadQueue.isEmpty
|
||||
? 0
|
||||
: 7,
|
||||
),
|
||||
sliver: const SliverToBoxAdapter(
|
||||
child: Text('已缓存视频'),
|
||||
),
|
||||
),
|
||||
SliverGrid.builder(
|
||||
gridDelegate:
|
||||
SliverGridDelegateWithMaxCrossAxisExtent(
|
||||
mainAxisSpacing: 2,
|
||||
mainAxisExtent: 100,
|
||||
maxCrossAxisExtent: Grid.smallCardWidth * 2,
|
||||
),
|
||||
itemBuilder: (context, index) {
|
||||
final item = _controller.pages[index];
|
||||
if (item.entrys.length == 1) {
|
||||
final entry = item.entrys.first;
|
||||
return DetailItem(
|
||||
entry: entry,
|
||||
progress: _progress,
|
||||
downloadService: _downloadService,
|
||||
showTitle: true,
|
||||
onDelete: () {
|
||||
_downloadService.deleteDownload(
|
||||
entry: entry,
|
||||
removeList: true,
|
||||
);
|
||||
GStorage.watchProgress.delete(
|
||||
entry.cid.toString(),
|
||||
);
|
||||
},
|
||||
checked: item.checked ?? false,
|
||||
onSelect: (_) => _controller.onSelect(item),
|
||||
controller: _controller,
|
||||
);
|
||||
}
|
||||
return _buildItem(theme, item);
|
||||
},
|
||||
itemCount: _controller.pages.length,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
if (_downloadService.waitDownloadQueue.isNotEmpty) {
|
||||
return const SliverToBoxAdapter();
|
||||
}
|
||||
return const HttpError();
|
||||
}),
|
||||
SliverToBoxAdapter(
|
||||
child: SizedBox(height: padding.bottom + 100),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildItem(ThemeData theme, DownloadPageInfo pageInfo) {
|
||||
final outline = theme.colorScheme.outline;
|
||||
final entry = pageInfo.entry;
|
||||
final isCompleted = entry == null;
|
||||
void onLongPress() => isCompleted
|
||||
? showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ListTile(
|
||||
onTap: () {
|
||||
Get.back();
|
||||
showConfirmDialog(
|
||||
context: context,
|
||||
title: '确定删除?',
|
||||
onConfirm: () async {
|
||||
final watchProgress = GStorage.watchProgress;
|
||||
await Future.wait(
|
||||
pageInfo.entrys.map((e) {
|
||||
final cid = e.pageData?.cid ?? e.source?.cid;
|
||||
return watchProgress.delete(cid.toString());
|
||||
}),
|
||||
);
|
||||
_downloadService.deletePage(
|
||||
pageDirPath: pageInfo.dirPath,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
dense: true,
|
||||
title: const Text(
|
||||
'删除',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () async {
|
||||
Get.back();
|
||||
final res = await Future.wait(
|
||||
pageInfo.entrys.map(
|
||||
(e) => _downloadService.downloadDanmaku(
|
||||
entry: e,
|
||||
isUpdate: true,
|
||||
),
|
||||
),
|
||||
);
|
||||
if (res.every((e) => e)) {
|
||||
SmartDialog.showToast('更新成功');
|
||||
} else {
|
||||
SmartDialog.showToast('更新失败');
|
||||
}
|
||||
},
|
||||
dense: true,
|
||||
title: const Text(
|
||||
'更新弹幕',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
),
|
||||
],
|
||||
void onLongPress() => showDialog(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return AlertDialog(
|
||||
clipBehavior: Clip.hardEdge,
|
||||
contentPadding: const EdgeInsets.symmetric(vertical: 12),
|
||||
content: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
ListTile(
|
||||
onTap: () {
|
||||
Get.back();
|
||||
showConfirmDialog(
|
||||
context: context,
|
||||
title: '确定删除?',
|
||||
onConfirm: () async {
|
||||
await GStorage.watchProgress.deleteAll(
|
||||
pageInfo.entrys.map((e) => e.cid.toString()),
|
||||
);
|
||||
_downloadService.deletePage(
|
||||
pageDirPath: pageInfo.dirPath,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
dense: true,
|
||||
title: const Text(
|
||||
'删除',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
);
|
||||
},
|
||||
)
|
||||
: null;
|
||||
),
|
||||
ListTile(
|
||||
onTap: () async {
|
||||
Get.back();
|
||||
final res = await Future.wait(
|
||||
pageInfo.entrys.map(
|
||||
(e) => _downloadService.downloadDanmaku(
|
||||
entry: e,
|
||||
isUpdate: true,
|
||||
),
|
||||
),
|
||||
);
|
||||
if (res.every((e) => e)) {
|
||||
SmartDialog.showToast('更新成功');
|
||||
} else {
|
||||
SmartDialog.showToast('更新失败');
|
||||
}
|
||||
},
|
||||
dense: true,
|
||||
title: const Text(
|
||||
'更新弹幕',
|
||||
style: TextStyle(fontSize: 14),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
final first = pageInfo.entrys.first;
|
||||
return Material(
|
||||
type: MaterialType.transparency,
|
||||
child: InkWell(
|
||||
onTap: () => Get.to(
|
||||
DownloadDetailPage(
|
||||
pageId: pageInfo.pageId,
|
||||
title: pageInfo.title,
|
||||
progress: _progress,
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
if (_controller.enableMultiSelect.value) {
|
||||
_controller.onSelect(pageInfo);
|
||||
return;
|
||||
}
|
||||
Get.to(
|
||||
DownloadDetailPage(
|
||||
pageId: pageInfo.pageId,
|
||||
title: pageInfo.title,
|
||||
progress: _progress,
|
||||
),
|
||||
);
|
||||
},
|
||||
onLongPress: onLongPress,
|
||||
onSecondaryTap: Utils.isMobile ? null : onLongPress,
|
||||
child: Padding(
|
||||
@@ -202,6 +314,9 @@ class _DownloadPageState extends State<DownloadPage> with GridMixin {
|
||||
right: 6.0,
|
||||
top: 6.0,
|
||||
),
|
||||
Positioned.fill(
|
||||
child: selectMask(theme, pageInfo.checked ?? false),
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
@@ -222,22 +337,24 @@ class _DownloadPageState extends State<DownloadPage> with GridMixin {
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
if (isCompleted)
|
||||
Text(
|
||||
'已完成',
|
||||
maxLines: 1,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
height: 1,
|
||||
color: outline,
|
||||
),
|
||||
)
|
||||
else
|
||||
entry.progressWidget(
|
||||
theme: theme,
|
||||
downloadService: _downloadService,
|
||||
isPage: true,
|
||||
),
|
||||
Row(
|
||||
crossAxisAlignment: .end,
|
||||
mainAxisAlignment: .spaceBetween,
|
||||
children: [
|
||||
if (first.ownerName case final ownerName?)
|
||||
Text(
|
||||
ownerName,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
height: 1.6,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
)
|
||||
else
|
||||
const Spacer(),
|
||||
pageInfo.entrys.first.moreBtn(theme),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user