Merge branch 'main' into mod-not-login-recommend2

This commit is contained in:
guozhigq
2024-02-05 00:35:11 +08:00
committed by GitHub
43 changed files with 1546 additions and 665 deletions

View File

@ -7,6 +7,9 @@ import 'package:pilipala/models/common/theme_type.dart';
import 'package:pilipala/utils/feed_back.dart';
import 'package:pilipala/utils/login.dart';
import 'package:pilipala/utils/storage.dart';
import '../../models/common/dynamic_badge_mode.dart';
import '../main/index.dart';
import 'widgets/select_dialog.dart';
class SettingController extends GetxController {
Box userInfoCache = GStrorage.userInfo;
@ -19,6 +22,7 @@ class SettingController extends GetxController {
RxInt picQuality = 10.obs;
Rx<ThemeType> themeType = ThemeType.system.obs;
var userInfo;
Rx<DynamicBadgeMode> dynamicBadgeType = DynamicBadgeMode.number.obs;
@override
void onInit() {
@ -33,6 +37,9 @@ class SettingController extends GetxController {
setting.get(SettingBoxKey.defaultPicQa, defaultValue: 10);
themeType.value = ThemeType.values[setting.get(SettingBoxKey.themeMode,
defaultValue: ThemeType.system.code)];
dynamicBadgeType.value = DynamicBadgeMode.values[setting.get(
SettingBoxKey.dynamicBadgeMode,
defaultValue: DynamicBadgeMode.number.code)];
}
loginOut() async {
@ -76,4 +83,31 @@ class SettingController extends GetxController {
feedBackEnable.value = !feedBackEnable.value;
setting.put(SettingBoxKey.feedBackEnable, feedBackEnable.value);
}
// 设置动态未读标记
setDynamicBadgeMode(BuildContext context) async {
DynamicBadgeMode? result = await showDialog(
context: context,
builder: (context) {
return SelectDialog<DynamicBadgeMode>(
title: '动态未读标记',
value: dynamicBadgeType.value,
values: DynamicBadgeMode.values.map((e) {
return {'title': e.description, 'value': e};
}).toList(),
);
},
);
if (result != null) {
dynamicBadgeType.value = result;
setting.put(SettingBoxKey.dynamicBadgeMode, result.code);
MainController mainController = Get.put(MainController());
mainController.dynamicBadgeType.value =
DynamicBadgeMode.values[result.code];
if (mainController.dynamicBadgeType.value != DynamicBadgeMode.hidden) {
mainController.getUnreadDynamic();
}
SmartDialog.showToast('设置成功');
}
}
}

View File

@ -22,6 +22,17 @@ class _TabbarSetPageState extends State<TabbarSetPage> {
defaultTabs = tabsConfig;
tabbarSort = settingStorage.get(SettingBoxKey.tabbarSort,
defaultValue: ['live', 'rcmd', 'hot', 'bangumi']);
// 对 tabData 进行排序
defaultTabs.sort((a, b) {
int indexA = tabbarSort.indexOf((a['type'] as TabType).id);
int indexB = tabbarSort.indexOf((b['type'] as TabType).id);
// 如果类型在 sortOrder 中不存在,则放在末尾
if (indexA == -1) indexA = tabbarSort.length;
if (indexB == -1) indexB = tabbarSort.length;
return indexA.compareTo(indexB);
});
}
void saveEdit() {

View File

@ -0,0 +1,201 @@
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:pilipala/common/widgets/no_data.dart';
import 'package:url_launcher/url_launcher.dart';
import '../../../services/loggeer.dart';
class LogsPage extends StatefulWidget {
const LogsPage({super.key});
@override
State<LogsPage> createState() => _LogsPageState();
}
class _LogsPageState extends State<LogsPage> {
late File logsPath;
late String fileContent;
List logsContent = [];
@override
void initState() {
getPath();
super.initState();
}
void getPath() async {
logsPath = await getLogsPath();
fileContent = await logsPath.readAsString();
logsContent = await parseLogs(fileContent);
setState(() {});
}
Future<List<Map<String, dynamic>>> parseLogs(String fileContent) async {
const String splitToken =
'======================================================================';
List contentList = fileContent.split(splitToken).map((item) {
return item
.replaceAll(
'============================== CATCHER 2 LOG ==============================',
'Pilipala错误日志 \n ********************')
.replaceAll('DEVICE INFO', '设备信息')
.replaceAll('APP INFO', '应用信息')
.replaceAll('ERROR', '错误信息')
.replaceAll('STACK TRACE', '错误堆栈');
}).toList();
List<Map<String, dynamic>> result = [];
for (String i in contentList) {
DateTime? date;
String body = i
.split("\n")
.map((l) {
if (l.startsWith("Crash occurred on")) {
date = DateTime.parse(
l.split("Crash occurred on")[1].trim().split('.')[0],
);
return "";
}
return l;
})
.where((dynamic l) => l.replaceAll("\n", "").trim().isNotEmpty)
.join("\n");
if (date != null || body != '') {
result.add({'date': date, 'body': body, 'expand': false});
}
}
return result.reversed.toList();
}
void copyLogs() async {
await Clipboard.setData(ClipboardData(text: fileContent));
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('复制成功')),
);
}
}
void feedback() {
launchUrl(
Uri.parse('https://github.com/guozhigq/pilipala/issues'),
// 系统自带浏览器打开
mode: LaunchMode.externalApplication,
);
}
void clearLogsHandle() async {
if (await clearLogs()) {
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
const SnackBar(content: Text('已清空')),
);
logsContent = [];
setState(() {});
}
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: false,
titleSpacing: 0,
title: Text('日志', style: Theme.of(context).textTheme.titleMedium),
actions: [
PopupMenuButton<String>(
onSelected: (String type) {
// 处理菜单项选择的逻辑
switch (type) {
case 'copy':
copyLogs();
break;
case 'feedback':
feedback();
break;
case 'clear':
clearLogsHandle();
break;
default:
}
},
itemBuilder: (BuildContext context) => <PopupMenuEntry<String>>[
const PopupMenuItem<String>(
value: 'copy',
child: Text('复制日志'),
),
const PopupMenuItem<String>(
value: 'feedback',
child: Text('错误反馈'),
),
const PopupMenuItem<String>(
value: 'clear',
child: Text('清空日志'),
),
],
),
const SizedBox(width: 6),
],
),
body: logsContent.isNotEmpty
? ListView.builder(
itemCount: logsContent.length,
itemBuilder: (context, index) {
final log = logsContent[index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Row(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
log['date'].toString(),
style: Theme.of(context).textTheme.titleMedium,
),
),
TextButton.icon(
onPressed: () async {
await Clipboard.setData(
ClipboardData(text: log['body']),
);
if (context.mounted) {
ScaffoldMessenger.of(context).showSnackBar(
SnackBar(
content: Text(
'已将 ${log['date'].toString()} 复制至剪贴板',
),
),
);
}
},
icon: const Icon(Icons.copy_outlined, size: 16),
label: const Text('复制'),
)
],
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 1,
clipBehavior: Clip.antiAliasWithSaveLayer,
child: Padding(
padding: const EdgeInsets.all(12.0),
child: SelectableText(log['body']),
),
),
),
const Divider(indent: 12, endIndent: 12),
],
);
},
)
: const CustomScrollView(
slivers: <Widget>[
NoData(),
],
),
);
}
}

View File

@ -10,6 +10,7 @@ import 'package:pilipala/pages/setting/widgets/select_dialog.dart';
import 'package:pilipala/pages/setting/widgets/slide_dialog.dart';
import 'package:pilipala/utils/storage.dart';
import '../../models/common/dynamic_badge_mode.dart';
import 'controller.dart';
import 'widgets/switch_item.dart';
@ -241,6 +242,14 @@ class _StyleSettingState extends State<StyleSetting> {
'当前模式:${settingController.themeType.value.description}',
style: subTitleStyle)),
),
ListTile(
dense: false,
onTap: () => settingController.setDynamicBadgeMode(context),
title: Text('动态未读标记', style: titleStyle),
subtitle: Obx(() => Text(
'当前标记样式:${settingController.dynamicBadgeType.value.description}',
style: subTitleStyle)),
),
ListTile(
dense: false,
onTap: () => Get.toNamed('/colorSetting'),