From 9c51033973b7ae262cc6e5828353a6a0328f7778 Mon Sep 17 00:00:00 2001 From: niuhuan Date: Thu, 30 Jun 2022 19:16:10 +0800 Subject: [PATCH] knight list --- android/gradle.properties | 2 + lib/screens/DownloadExportGroupScreen.dart | 177 ++++++++++++++++++ lib/screens/DownloadExportToFileScreen.dart | 2 +- lib/screens/DownloadExportingGroupScreen.dart | 126 +++++++++++++ lib/screens/DownloadListScreen.dart | 30 +++ lib/screens/PkzComicInfoScreen.dart | 3 +- lib/screens/RankingsScreen.dart | 134 ++++++++++++- 7 files changed, 470 insertions(+), 4 deletions(-) create mode 100644 lib/screens/DownloadExportGroupScreen.dart create mode 100644 lib/screens/DownloadExportingGroupScreen.dart diff --git a/android/gradle.properties b/android/gradle.properties index 94adc3a..c20dc70 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,3 +1,5 @@ org.gradle.jvmargs=-Xmx1536M android.useAndroidX=true android.enableJetifier=true + +android.jetifier.blacklist=bcprov-jdk15on diff --git a/lib/screens/DownloadExportGroupScreen.dart b/lib/screens/DownloadExportGroupScreen.dart new file mode 100644 index 0000000..7d47acf --- /dev/null +++ b/lib/screens/DownloadExportGroupScreen.dart @@ -0,0 +1,177 @@ +import 'package:flutter/material.dart'; +import 'package:pikapika/basic/Common.dart'; + +import '../basic/Entities.dart'; +import '../basic/Method.dart'; +import 'DownloadExportingGroupScreen.dart'; +import 'components/ContentLoading.dart'; +import 'components/DownloadInfoCard.dart'; + +class DownloadExportGroupScreen extends StatefulWidget { + const DownloadExportGroupScreen({Key? key}) : super(key: key); + + @override + State createState() => _DownloadExportGroupScreenState(); +} + +class _DownloadExportGroupScreenState extends State { + late Future> _f = method.allDownloads(); + + @override + Widget build(BuildContext context) { + return FutureBuilder( + future: _f, + builder: + (BuildContext context, AsyncSnapshot> snapshot) { + if (snapshot.connectionState != ConnectionState.done) { + return Scaffold( + appBar: AppBar( + title: const Text("批量导出"), + ), + body: const ContentLoading(label: '加载中'), + ); + } + + if (snapshot.hasError) { + print("${snapshot.error}"); + print("${snapshot.stackTrace}"); + return Scaffold( + appBar: AppBar( + title: const Text("批量导出"), + ), + body: const Center(child: Text('加载失败')), + ); + } + + var data = snapshot.data!; + + List ws = []; + List exportable = []; + List exportableIds = []; + for (var value in data) { + if (!value.deleting && value.downloadFinished) { + ws.add(downloadWidget(value)); + exportable.add(value); + exportableIds.add(value.id); + } + } + + return Scaffold( + appBar: AppBar( + title: const Text("批量导出"), + actions: [ + _selectAllButton(exportableIds), + _goToExport(), + ], + ), + body: RefreshIndicator( + onRefresh: () async { + setState(() { + selected.clear(); + _f = method.allDownloads(); + }); + }, + child: ListView( + children: ws, + ), + ), + ); + }, + ); + } + + List selected = []; + + Widget downloadWidget(DownloadComic e) { + return InkWell( + onTap: () { + if (selected.contains(e.id)) { + selected.remove(e.id); + } else { + selected.add(e.id); + } + setState(() {}); + }, + child: Stack(children: [ + DownloadInfoCard( + task: e, + ), + Row(children: [ + Expanded(child: Container()), + Padding( + padding: const EdgeInsets.all(5), + child: Icon( + selected.contains(e.id) + ? Icons.check_circle_sharp + : Icons.circle_outlined, + color: Theme.of(context).colorScheme.secondary, + ), + ), + ]), + ]), + ); + } + + Widget _selectAllButton(List exportableIds) { + return MaterialButton( + minWidth: 0, + onPressed: () async { + setState(() { + if (selected.length >= exportableIds.length) { + selected.clear(); + } else { + selected.clear(); + selected.addAll(exportableIds); + } + }); + }, + child: Column( + children: [ + Expanded(child: Container()), + const Icon( + Icons.select_all, + size: 18, + color: Colors.white, + ), + const Text( + '全选', + style: TextStyle(fontSize: 14, color: Colors.white), + ), + Expanded(child: Container()), + ], + )); + } + + Widget _goToExport() { + return MaterialButton( + minWidth: 0, + onPressed: () async { + if (selected.isEmpty) { + defaultToast(context, "请选择导出的内容"); + return; + } + final exported = await Navigator.of(context).push( + MaterialPageRoute( + builder: (context) => DownloadExportingGroupScreen( + idList: selected, + ), + ), + ); + }, + child: Column( + children: [ + Expanded(child: Container()), + const Icon( + Icons.check, + size: 18, + color: Colors.white, + ), + const Text( + '确认', + style: TextStyle(fontSize: 14, color: Colors.white), + ), + Expanded(child: Container()), + ], + )); + } +} diff --git a/lib/screens/DownloadExportToFileScreen.dart b/lib/screens/DownloadExportToFileScreen.dart index 05f7dd4..b0f3583 100644 --- a/lib/screens/DownloadExportToFileScreen.dart +++ b/lib/screens/DownloadExportToFileScreen.dart @@ -234,7 +234,7 @@ class _DownloadExportToFileScreenState } }, child: - _buildButtonInner('导出到xxx.pkz\n(可直接打开观看的格式,不支持导入,可以躲避BD网盘或者TX的检测)'), + _buildButtonInner('导出到xxx.pkz\n(可直接打开观看的格式,不支持导入)\n(可以躲避网盘或者聊天软件的扫描)'), )); widgets.add(Container(height: 10)); ///////////////////// diff --git a/lib/screens/DownloadExportingGroupScreen.dart b/lib/screens/DownloadExportingGroupScreen.dart new file mode 100644 index 0000000..8b055f2 --- /dev/null +++ b/lib/screens/DownloadExportingGroupScreen.dart @@ -0,0 +1,126 @@ +import 'package:flutter/material.dart'; +import 'package:pikapika/basic/Common.dart'; + +import '../basic/Channels.dart'; +import '../basic/Cross.dart'; +import '../basic/Method.dart'; +import '../basic/config/ExportRename.dart'; +import 'components/ContentLoading.dart'; + +class DownloadExportingGroupScreen extends StatefulWidget { + final List idList; + + const DownloadExportingGroupScreen({Key? key, required this.idList}) + : super(key: key); + + @override + State createState() => _DownloadExportingGroupScreenState(); +} + +class _DownloadExportingGroupScreenState + extends State { + bool exporting = false; + bool exported = false; + bool exportFail = false; + dynamic e; + String exportMessage = "正在导出"; + + @override + void initState() { + registerEvent(_onMessageChange, "EXPORT"); + super.initState(); + } + + @override + void dispose() { + unregisterEvent(_onMessageChange); + super.dispose(); + } + + void _onMessageChange(event) { + setState(() { + exportMessage = event; + }); + } + + Widget _body() { + if (exporting) { + return ContentLoading(label: exportMessage); + } + if (exportFail) { + return Center(child: Text("导出失败\n$e")); + } + if (exported) { + return Center(child: Text("导出成功")); + } + return Center( + child: MaterialButton( + onPressed: _export, + child: const Text("选择导出位置"), + ), + ); + } + + _export() async { + late String? path; + try { + path = await chooseFolder(context); + } catch (e) { + defaultToast(context, "$e"); + return; + } + var name = ""; + if (currentExportRename()) { + var rename = await inputString( + context, + "请输入保存后的名称", + defaultValue: "${DateTime.now().millisecondsSinceEpoch}.pkz", + ); + if (rename != null && rename.isNotEmpty) { + name = rename; + } else { + return; + } + } + print("path $path"); + if (path != null) { + try { + setState(() { + exporting = true; + }); + await method.exportComicDownloadToPkz( + widget.idList, + path, + name, + ); + exported = true; + } catch (err) { + e = err; + exportFail = true; + } finally { + setState(() { + exporting = false; + }); + } + } + } + + @override + Widget build(BuildContext context) { + return WillPopScope( + child: Scaffold( + appBar: AppBar( + title: const Text("批量导出"), + ), + body: _body(), + ), + onWillPop: () async { + if (exporting) { + defaultToast(context, "导出中, 请稍后"); + return false; + } + return true; + }, + ); + } +} diff --git a/lib/screens/DownloadListScreen.dart b/lib/screens/DownloadListScreen.dart index 6438650..dfeb7b0 100644 --- a/lib/screens/DownloadListScreen.dart +++ b/lib/screens/DownloadListScreen.dart @@ -6,6 +6,7 @@ import 'package:pikapika/basic/Channels.dart'; import 'package:pikapika/basic/Common.dart'; import 'package:pikapika/basic/Entities.dart'; import 'package:pikapika/basic/Method.dart'; +import 'package:pikapika/screens/DownloadExportGroupScreen.dart'; import 'DownloadImportScreen.dart'; import 'DownloadInfoScreen.dart'; import 'components/ContentLoading.dart'; @@ -59,6 +60,7 @@ class _DownloadListScreenState extends State { appBar: AppBar( title: const Text('下载列表'), actions: [ + exportButton(), importButton(), pauseButton(), resetFailedButton(), @@ -144,6 +146,34 @@ class _DownloadListScreenState extends State { ); } + Widget exportButton() { + return MaterialButton( + minWidth: 0, + onPressed: () async { + await Navigator.push( + context, + MaterialPageRoute( + builder: (context) => const DownloadExportGroupScreen(), + ), + ); + }, + child: Column( + children: [ + Expanded(child: Container()), + const Icon( + Icons.send_to_mobile, + size: 18, + color: Colors.white, + ), + const Text( + '导出', + style: TextStyle(fontSize: 14, color: Colors.white), + ), + Expanded(child: Container()), + ], + )); + } + Widget importButton() { return MaterialButton( minWidth: 0, diff --git a/lib/screens/PkzComicInfoScreen.dart b/lib/screens/PkzComicInfoScreen.dart index 9d8fed9..f3d4d73 100644 --- a/lib/screens/PkzComicInfoScreen.dart +++ b/lib/screens/PkzComicInfoScreen.dart @@ -179,14 +179,13 @@ class _PkzComicInfoScreenState extends State chapters[c.id] = (c); } } - print("chapters : ${chapters}"); if (chapters.isEmpty) { return Container(); } final width = constraints.maxWidth; return Container( padding: const EdgeInsets.only(left: 10, right: 10), - margin: const EdgeInsets.only(bottom: 10), + margin: const EdgeInsets.only(top: 10, bottom: 10), width: width, child: MaterialButton( onPressed: () { diff --git a/lib/screens/RankingsScreen.dart b/lib/screens/RankingsScreen.dart index c1075eb..742145d 100644 --- a/lib/screens/RankingsScreen.dart +++ b/lib/screens/RankingsScreen.dart @@ -3,8 +3,14 @@ import 'package:pikapika/basic/Entities.dart'; import 'package:pikapika/basic/Method.dart'; import 'package:pikapika/basic/config/ListLayout.dart'; import 'package:pikapika/basic/config/ShadowCategories.dart'; +import 'package:pikapika/screens/components/Avatar.dart'; +import 'package:pikapika/screens/components/ContentBuilder.dart'; +import '../basic/Cross.dart'; +import '../basic/Navigator.dart'; +import 'ComicsScreen.dart'; import 'components/ComicListBuilder.dart'; +import 'components/FitButton.dart'; import 'components/RightClickPop.dart'; // 排行榜 @@ -31,7 +37,7 @@ class RankingsScreen extends StatelessWidget { ], ), body: DefaultTabController( - length: 3, + length: 4, child: Column( children: [ Container( @@ -44,6 +50,7 @@ class RankingsScreen extends StatelessWidget { Tab(text: '天'), Tab(text: '周'), Tab(text: '月'), + Tab(text: '骑'), ], ), ), @@ -53,6 +60,7 @@ class RankingsScreen extends StatelessWidget { _Leaderboard("H24"), _Leaderboard("D7"), _Leaderboard("D30"), + _KnightLeaderBoard(), ], ), ), @@ -86,3 +94,127 @@ class _LeaderboardState extends State<_Leaderboard> { return ComicListBuilder(_future, _reload); } } + +class _KnightLeaderBoard extends StatefulWidget { + const _KnightLeaderBoard(); + + @override + State createState() => _KnightLeaderBoardState(); +} + +class _KnightLeaderBoardState extends State<_KnightLeaderBoard> { + Future> _future = method.leaderboardOfKnight(); + + @override + Widget build(BuildContext context) { + return ContentBuilder( + future: _future, + onRefresh: () async { + setState(() { + _future = method.leaderboardOfKnight(); + }); + }, + successBuilder: ( + BuildContext context, + AsyncSnapshot> snapshot, + ) { + return RefreshIndicator( + onRefresh: () async { + setState(() { + _future = method.leaderboardOfKnight(); + }); + }, + child: ListView(children: [ + ...snapshot.requireData.map(_knightCard).toList(), + SizedBox( + height: 80, + child: FitButton( + text: '刷新', + onPressed: () async { + setState(() { + _future = method.leaderboardOfKnight(); + }); + }, + ), + ), + ]), + ); + }, + ); + } + + Widget _knightCard(Knight e) { + final theme = Theme.of(context); + var nameStyle = const TextStyle(fontWeight: FontWeight.bold); + var levelStyle = TextStyle( + fontSize: 12, color: theme.colorScheme.secondary.withOpacity(.8)); + var connectStyle = + TextStyle(color: theme.textTheme.bodyText1?.color?.withOpacity(.8)); + var datetimeStyle = TextStyle( + color: theme.textTheme.bodyText1?.color?.withOpacity(.6), fontSize: 12); + + final card = Container( + padding: const EdgeInsets.all(5), + decoration: BoxDecoration( + border: Border( + top: BorderSide( + width: .25, + style: BorderStyle.solid, + color: Colors.grey.shade500.withOpacity(.5), + ), + bottom: BorderSide( + width: .25, + style: BorderStyle.solid, + color: Colors.grey.shade500.withOpacity(.5), + ), + ), + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Avatar(e.avatar), + Container(width: 5), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + Text(e.name, style: nameStyle), + Expanded(child: Container()), + Text( + "${e.comicsUploaded} 本", + style: datetimeStyle, + ), + ], + ), + Text("Lv. ${e.level} (${e.title})", style: levelStyle), + Text(e.slogan ?? "", style: connectStyle), + ], + ), + ), + ], + ), + ); + + return InkWell( + onTap: () { + navPushOrReplace( + context, + (context) => ComicsScreen( + creatorId: e.id, + creatorName: e.name, + ), + ); + }, + onLongPress: () { + confirmCopy( + context, + e.name, + ); + }, + child: card, + ); + } +}