Files
PiliPlus/lib/pages/about/index.dart
bggRGjQaUbCoE 538494b7ec chore: clean up
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
2025-04-20 11:21:21 +08:00

473 lines
18 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'package:PiliPlus/build_config.dart';
import 'package:PiliPlus/services/loggeer.dart';
import 'package:PiliPlus/utils/accounts/account.dart';
import 'package:PiliPlus/utils/login_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'package:PiliPlus/models/github/latest.dart';
import 'package:PiliPlus/utils/storage.dart';
import 'package:PiliPlus/utils/utils.dart';
import '../../utils/cache_manage.dart';
import '../mine/controller.dart';
class AboutPage extends StatefulWidget {
const AboutPage({super.key, this.showAppBar});
final bool? showAppBar;
@override
State<AboutPage> createState() => _AboutPageState();
}
class _AboutPageState extends State<AboutPage> {
final AboutController _aboutController = Get.put(AboutController());
final String _sourceCodeUrl = 'https://github.com/bggRGjQaUbCoE/PiliPlus';
final String _originSourceCodeUrl = 'https://github.com/guozhigq/pilipala';
final String _upstreamUrl = 'https://github.com/orz12/PiliPalaX';
late int _pressCount = 0;
late Color outline;
late TextStyle subTitleStyle;
@override
void didChangeDependencies() {
super.didChangeDependencies();
outline = Theme.of(context).colorScheme.outline;
subTitleStyle =
TextStyle(fontSize: 13, color: Theme.of(context).colorScheme.outline);
}
@override
void initState() {
super.initState();
// 读取缓存占用
getCacheSize();
}
Future<void> getCacheSize() async {
final res = await CacheManage().loadApplicationCache();
_aboutController.cacheSize.value = res;
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar:
widget.showAppBar == false ? null : AppBar(title: const Text('关于')),
body: ListView(
children: [
GestureDetector(
onTap: () {
_pressCount++;
if (_pressCount == 5) {
_pressCount = 0;
showDialog(
context: context,
builder: (context) {
return AlertDialog(
content: TextField(
autofocus: true,
onSubmitted: (value) {
Get.back();
if (value.isNotEmpty) {
PageUtils.handleWebview(value, inApp: true);
}
},
),
);
},
);
}
},
child: ConstrainedBox(
constraints: const BoxConstraints(maxHeight: 150),
child: ExcludeSemantics(
child: Image.asset(
'assets/images/logo/logo.png',
),
),
),
),
ListTile(
title: Text(
'PiliPlus',
textAlign: TextAlign.center,
style:
Theme.of(context).textTheme.titleMedium!.copyWith(height: 2),
),
subtitle: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text(
'使用Flutter开发的B站第三方客户端',
style: TextStyle(color: outline),
semanticsLabel: '与你一起,发现不一样的世界',
),
const Icon(
Icons.accessibility_new,
semanticLabel: "无障碍适配",
size: 18,
),
],
),
),
Obx(
() => ListTile(
onTap: () => Utils.checkUpdate(false),
onLongPress: () =>
Utils.copyText(_aboutController.currentVersion.value),
title: const Text('当前版本'),
leading: const Icon(Icons.commit_outlined),
trailing: Text(
_aboutController.currentVersion.value,
style: subTitleStyle,
),
),
),
ListTile(
title: Text(
'''
Build Time: ${BuildConfig.buildTime}
Commit Hash: ${BuildConfig.commitHash}''',
style: TextStyle(fontSize: 14),
),
leading: const Icon(Icons.info_outline),
onTap: () => PageUtils.launchURL(
'https://github.com/bggRGjQaUbCoE/PiliPlus/commit/${BuildConfig.commitHash}'),
onLongPress: () => Utils.copyText(BuildConfig.commitHash),
),
Divider(
thickness: 1,
height: 30,
color: Theme.of(context).colorScheme.outlineVariant,
),
ListTile(
onTap: () => PageUtils.launchURL(_sourceCodeUrl),
leading: const Icon(Icons.code),
title: const Text('Source Code'),
subtitle: Text(_sourceCodeUrl, style: subTitleStyle),
),
ListTile(
onTap: () => PageUtils.launchURL(_originSourceCodeUrl),
leading: const Icon(Icons.code),
title: const Text('Origin'),
subtitle: Text(
_originSourceCodeUrl,
style: subTitleStyle,
),
),
ListTile(
onTap: () => PageUtils.launchURL(_upstreamUrl),
leading: const Icon(Icons.code),
title: const Text('Upstream'),
subtitle: Text(
_upstreamUrl,
style: subTitleStyle,
),
),
if (Platform.isAndroid)
ListTile(
onTap: () {
Utils.channel.invokeMethod('linkVerifySettings');
},
leading: Icon(MdiIcons.linkBoxOutline),
title: const Text('打开受支持的链接'),
trailing: Icon(
Icons.arrow_forward,
size: 16,
color: outline,
),
),
ListTile(
onTap: () {
showDialog(
context: context,
builder: (context) {
return SimpleDialog(
clipBehavior: Clip.hardEdge,
title: const Text('问题反馈'),
children: [
ListTile(
title: const Text('GitHub Issue'),
onTap: () =>
PageUtils.launchURL('$_sourceCodeUrl/issues'),
),
],
);
},
);
},
leading: const Icon(Icons.feedback_outlined),
title: const Text('问题反馈'),
trailing: Icon(
Icons.arrow_forward,
size: 16,
color: outline,
),
),
ListTile(
onTap: () {
Get.toNamed('/logs');
},
onLongPress: clearLogs,
leading: const Icon(Icons.bug_report_outlined),
title: const Text('错误日志'),
subtitle: Text('长按清除日志', style: subTitleStyle),
trailing: Icon(Icons.arrow_forward, size: 16, color: outline),
),
ListTile(
onTap: () async {
await CacheManage().clearCacheAll(context);
getCacheSize();
},
leading: const Icon(Icons.delete_outline),
title: const Text('清除缓存'),
subtitle: Obx(
() => Text(
'图片及网络缓存 ${_aboutController.cacheSize.value}',
style: subTitleStyle,
),
),
),
ListTile(
title: const Text('导入/导出登录信息'),
leading: const Icon(Icons.import_export_outlined),
onTap: () {
showDialog(
context: context,
builder: (context) => SimpleDialog(
title: const Text('导入/导出登录信息'),
clipBehavior: Clip.hardEdge,
children: [
ListTile(
title: const Text('导出'),
onTap: () async {
Get.back();
String res = jsonEncode(Accounts.account.toMap());
Utils.copyText(res);
},
),
ListTile(
title: const Text('导入'),
onTap: () async {
Get.back();
ClipboardData? data =
await Clipboard.getData('text/plain');
if (data?.text?.isNotEmpty != true) {
SmartDialog.showToast('剪贴板无数据');
return;
}
if (!context.mounted) return;
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('是否导入以下登录信息?'),
content: SingleChildScrollView(
child: Text(data!.text!),
),
actions: [
TextButton(
onPressed: Get.back,
child: Text(
'取消',
style: TextStyle(color: outline),
),
),
TextButton(
onPressed: () {
Get.back();
try {
final res = (jsonDecode(data.text!)
as Map)
.map((key, value) => MapEntry(key,
LoginAccount.fromJson(value)));
Accounts.account
.putAll(res)
.then((_) => Accounts.refresh())
.then((_) {
MineController.anonymity.value =
!Accounts.get(AccountType.heartbeat)
.isLogin;
if (Accounts.main.isLogin) {
return LoginUtils.onLoginMain();
}
});
} catch (e) {
SmartDialog.showToast('导入失败:$e');
}
},
child: const Text('确定'),
),
],
);
},
);
},
),
],
),
);
},
),
ListTile(
title: const Text('导入/导出设置'),
dense: false,
leading: const Icon(Icons.import_export_outlined),
onTap: () {
showDialog(
context: context,
builder: (context) {
return SimpleDialog(
clipBehavior: Clip.hardEdge,
title: const Text('导入/导出设置'),
children: [
ListTile(
title: const Text('导出设置至剪贴板'),
onTap: () async {
Get.back();
String data = await GStorage.exportAllSettings();
Utils.copyText(data);
},
),
ListTile(
title: const Text('从剪贴板导入设置'),
onTap: () async {
Get.back();
ClipboardData? data =
await Clipboard.getData('text/plain');
if (data == null ||
data.text == null ||
data.text!.isEmpty) {
SmartDialog.showToast('剪贴板无数据');
return;
}
if (!context.mounted) return;
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('是否导入如下设置?'),
content: SingleChildScrollView(
child: Text(data.text!),
),
actions: [
TextButton(
onPressed: Get.back,
child: Text(
'取消',
style: TextStyle(color: outline),
),
),
TextButton(
onPressed: () async {
Get.back();
try {
await GStorage.importAllSettings(
data.text!);
SmartDialog.showToast('导入成功');
} catch (e) {
SmartDialog.showToast('导入失败:$e');
}
},
child: const Text('确定'),
),
],
);
},
);
},
),
],
);
},
);
}),
ListTile(
title: const Text('重置所有设置'),
leading: const Icon(Icons.settings_backup_restore_outlined),
onTap: () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('重置所有设置'),
content: const Text('是否重置所有设置?'),
actions: [
TextButton(
onPressed: () {
Get.back();
},
child: const Text('取消'),
),
TextButton(
onPressed: () async {
Get.back();
await Future.wait([
GStorage.setting.clear(),
GStorage.video.clear(),
]);
SmartDialog.showToast('重置成功');
},
child: const Text('重置可导出的设置'),
),
TextButton(
onPressed: () async {
Get.back();
await Future.wait([
GStorage.userInfo.clear(),
GStorage.setting.clear(),
GStorage.localCache.clear(),
GStorage.video.clear(),
GStorage.historyWord.clear(),
Accounts.clear(),
]);
SmartDialog.showToast('重置成功');
},
child: const Text('重置所有数据(含登录信息)'),
),
],
);
},
);
},
),
SizedBox(height: MediaQuery.paddingOf(context).bottom + 80),
],
),
);
}
}
class AboutController extends GetxController {
RxString currentVersion = ''.obs;
RxString remoteVersion = ''.obs;
LatestDataModel? remoteAppInfo;
RxBool isUpdate = true.obs;
RxBool isLoading = true.obs;
LatestDataModel? data;
RxString cacheSize = ''.obs;
@override
void onInit() {
super.onInit();
getCurrentApp();
}
// 获取当前版本
Future getCurrentApp() async {
var currentInfo = await PackageInfo.fromPlatform();
String buildNumber = currentInfo.buildNumber;
currentVersion.value = "${currentInfo.version}+$buildNumber";
}
}