knight list
This commit is contained in:
parent
cc5b16ee33
commit
9c51033973
|
@ -1,3 +1,5 @@
|
|||
org.gradle.jvmargs=-Xmx1536M
|
||||
android.useAndroidX=true
|
||||
android.enableJetifier=true
|
||||
|
||||
android.jetifier.blacklist=bcprov-jdk15on
|
||||
|
|
|
@ -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<StatefulWidget> createState() => _DownloadExportGroupScreenState();
|
||||
}
|
||||
|
||||
class _DownloadExportGroupScreenState extends State<DownloadExportGroupScreen> {
|
||||
late Future<List<DownloadComic>> _f = method.allDownloads();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return FutureBuilder(
|
||||
future: _f,
|
||||
builder:
|
||||
(BuildContext context, AsyncSnapshot<List<DownloadComic>> 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<Widget> ws = [];
|
||||
List<DownloadComic> exportable = [];
|
||||
List<String> 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<String> 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<String> 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()),
|
||||
],
|
||||
));
|
||||
}
|
||||
}
|
|
@ -234,7 +234,7 @@ class _DownloadExportToFileScreenState
|
|||
}
|
||||
},
|
||||
child:
|
||||
_buildButtonInner('导出到xxx.pkz\n(可直接打开观看的格式,不支持导入,可以躲避BD网盘或者TX的检测)'),
|
||||
_buildButtonInner('导出到xxx.pkz\n(可直接打开观看的格式,不支持导入)\n(可以躲避网盘或者聊天软件的扫描)'),
|
||||
));
|
||||
widgets.add(Container(height: 10));
|
||||
/////////////////////
|
||||
|
|
|
@ -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<String> idList;
|
||||
|
||||
const DownloadExportingGroupScreen({Key? key, required this.idList})
|
||||
: super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _DownloadExportingGroupScreenState();
|
||||
}
|
||||
|
||||
class _DownloadExportingGroupScreenState
|
||||
extends State<DownloadExportingGroupScreen> {
|
||||
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;
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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<DownloadListScreen> {
|
|||
appBar: AppBar(
|
||||
title: const Text('下载列表'),
|
||||
actions: [
|
||||
exportButton(),
|
||||
importButton(),
|
||||
pauseButton(),
|
||||
resetFailedButton(),
|
||||
|
@ -144,6 +146,34 @@ class _DownloadListScreenState extends State<DownloadListScreen> {
|
|||
);
|
||||
}
|
||||
|
||||
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,
|
||||
|
|
|
@ -179,14 +179,13 @@ class _PkzComicInfoScreenState extends State<PkzComicInfoScreen>
|
|||
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: () {
|
||||
|
|
|
@ -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<StatefulWidget> createState() => _KnightLeaderBoardState();
|
||||
}
|
||||
|
||||
class _KnightLeaderBoardState extends State<_KnightLeaderBoard> {
|
||||
Future<List<Knight>> _future = method.leaderboardOfKnight();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return ContentBuilder(
|
||||
future: _future,
|
||||
onRefresh: () async {
|
||||
setState(() {
|
||||
_future = method.leaderboardOfKnight();
|
||||
});
|
||||
},
|
||||
successBuilder: (
|
||||
BuildContext context,
|
||||
AsyncSnapshot<List<Knight>> 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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue