diff --git a/lib/http/video.dart b/lib/http/video.dart index 2aa748842..bf1d62769 100644 --- a/lib/http/video.dart +++ b/lib/http/video.dart @@ -41,6 +41,7 @@ import 'package:PiliPlus/utils/utils.dart'; import 'package:PiliPlus/utils/wbi_sign.dart'; import 'package:dio/dio.dart'; import 'package:flutter/foundation.dart' show compute; +import 'package:protobuf/protobuf.dart'; /// view层根据 status 判断渲染逻辑 abstract final class VideoHttp { @@ -559,11 +560,13 @@ abstract final class VideoHttp { if (res.data['code'] == 0) { try { final replyInfo = RequestUtils.replyCast(res.data['data']['reply']); - GStorage.reply.put( + GStorage.reply?.put( replyInfo.id.toString(), - (replyInfo.toProto3Json() as Map) - ..remove('memberV2') - ..remove('trackInfo'), + (replyInfo.deepCopy() + ..unknownFields.clear() + ..clearMemberV2() + ..clearTrackInfo()) + .writeToBuffer(), ); return Success(replyInfo); } catch (e, s) { @@ -591,7 +594,7 @@ abstract final class VideoHttp { options: Options(contentType: Headers.formUrlEncodedContentType), ); if (res.data['code'] == 0) { - GStorage.reply.delete(rpid.toString()); + GStorage.reply?.delete(rpid.toString()); return const Success(null); } else { return const Error('请退出账号后重新登录'); diff --git a/lib/pages/mine/view.dart b/lib/pages/mine/view.dart index b95c2d151..c5a04528f 100644 --- a/lib/pages/mine/view.dart +++ b/lib/pages/mine/view.dart @@ -17,6 +17,7 @@ import 'package:PiliPlus/utils/extension/get_ext.dart'; import 'package:PiliPlus/utils/extension/num_ext.dart'; import 'package:PiliPlus/utils/extension/theme_ext.dart'; import 'package:PiliPlus/utils/platform_utils.dart'; +import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:flutter/material.dart' hide ListTile; import 'package:get/get.dart'; @@ -160,14 +161,15 @@ class _MediaPageState extends CommonPageState ), msgBadge(_mainController), ], - IconButton( - iconSize: iconSize, - padding: padding, - style: style, - tooltip: '评论记录', - onPressed: () => Get.toNamed('/myReply'), - icon: const Icon(Icons.message_outlined), - ), + if (GStorage.reply != null) + IconButton( + iconSize: iconSize, + padding: padding, + style: style, + tooltip: '评论记录', + onPressed: () => Get.toNamed('/myReply'), + icon: const Icon(Icons.message_outlined), + ), Obx( () { final anonymity = MineController.anonymity.value; diff --git a/lib/pages/my_reply/view.dart b/lib/pages/my_reply/view.dart index d249ea9a8..e54ac09b5 100644 --- a/lib/pages/my_reply/view.dart +++ b/lib/pages/my_reply/view.dart @@ -4,6 +4,7 @@ import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart'; import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart'; import 'package:PiliPlus/pages/video/reply/widgets/reply_item_grpc.dart'; import 'package:PiliPlus/utils/app_scheme.dart'; +import 'package:PiliPlus/utils/id_utils.dart'; import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/reply_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; @@ -26,11 +27,7 @@ class _MyReplyState extends State with DynMixin { @override void initState() { super.initState(); - _replies = - GStorage.reply.values - .map((e) => ReplyInfo.create()..mergeFromProto3Json(e)) - .toList() - ..sort((a, b) => b.ctime.compareTo(a.ctime)); + _replies = GStorage.reply!.values.map(ReplyInfo.fromBuffer).toList(); } @override @@ -46,7 +43,7 @@ class _MyReplyState extends State with DynMixin { context: context, title: 'Clear Local Storage?', onConfirm: () { - GStorage.reply.clear(); + GStorage.reply!.clear(); _replies.clear(); setState(() {}); }, @@ -112,10 +109,14 @@ class _MyReplyState extends State with DynMixin { } void _onCheckReply(ReplyInfo replyInfo) { + final oid = replyInfo.oid.toInt(); ReplyUtils.onCheckReply( replyInfo: replyInfo, biliSendCommAntifraud: Pref.biliSendCommAntifraud, - sourceId: null, + sourceId: switch (oid) { + 1 => IdUtils.av2bv(oid), + _ => oid.toString(), + }, isManual: true, ); } diff --git a/lib/pages/setting/models/extra_settings.dart b/lib/pages/setting/models/extra_settings.dart index 8199cbcd8..0c5ad1654 100644 --- a/lib/pages/setting/models/extra_settings.dart +++ b/lib/pages/setting/models/extra_settings.dart @@ -354,6 +354,13 @@ List get extraSettings => [ setKey: SettingBoxKey.showDmChart, defaultVal: false, ), + const SwitchModel( + title: '记录评论', + leading: Icon(Icons.message_outlined), + setKey: SettingBoxKey.saveReply, + defaultVal: true, + needReboot: true, + ), const SwitchModel( title: '发评反诈', subtitle: '发送评论后检查评论是否可见', diff --git a/lib/pages/video/reply/widgets/reply_item_grpc.dart b/lib/pages/video/reply/widgets/reply_item_grpc.dart index 3fd43bd8d..bcfcdd304 100644 --- a/lib/pages/video/reply/widgets/reply_item_grpc.dart +++ b/lib/pages/video/reply/widgets/reply_item_grpc.dart @@ -39,6 +39,7 @@ import 'package:flutter/foundation.dart' show kDebugMode; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; +import 'package:protobuf/protobuf.dart'; class ReplyItemGrpc extends StatelessWidget { const ReplyItemGrpc({ @@ -840,7 +841,7 @@ class ReplyItemGrpc extends StatelessWidget { final ownerMid = Int64(Accounts.main.mid); final theme = Theme.of(context); final errorColor = theme.colorScheme.error; - final style = theme.textTheme.titleSmall; + final style = theme.textTheme.titleSmall!; return Padding( padding: EdgeInsets.only( @@ -866,34 +867,56 @@ class ReplyItemGrpc extends StatelessWidget { ), ), ), - if (kDebugMode) ...[ + if (kDebugMode && GStorage.reply != null) ...[ ListTile( onTap: () { Get.back(); - GStorage.reply.put( + GStorage.reply!.put( item.id.toString(), - (item.toProto3Json() as Map) - ..remove('replies') - ..remove('memberV2') - ..remove('trackInfo'), + (item.deepCopy() + ..unknownFields.clear() + ..replies.clear() + ..clearMemberV2() + ..clearTrackInfo()) + .writeToBuffer(), ); }, title: Text( 'save to local', - style: style!.copyWith(color: theme.colorScheme.primary), + style: style.copyWith(color: theme.colorScheme.primary), ), ), ListTile( onTap: () { Get.back(); onDelete(); - GStorage.reply.delete(item.id.toString()); + GStorage.reply!.delete(item.id.toString()); }, title: Text( 'remove from local', style: style.copyWith(color: theme.colorScheme.primary), ), ), + ListTile( + onTap: () { + Get.back(); + final oid = item.oid.toInt(); + final data = + (item.deepCopy() + ..unknownFields.clear() + ..replies.clear() + ..clearMemberV2() + ..clearTrackInfo()) + .writeToBuffer(); + GStorage.reply!.putAll({ + for (var i = oid; i < oid + 1000; i++) i.toString(): data, + }); + }, + title: Text( + 'save to local (x1000)', + style: style.copyWith(color: theme.colorScheme.primary), + ), + ), ], if (ownerMid == upMid || ownerMid == item.member.mid) ListTile( @@ -959,7 +982,7 @@ class ReplyItemGrpc extends StatelessWidget { }, minLeadingWidth: 0, leading: Icon(Icons.delete_outlined, color: errorColor, size: 19), - title: Text('删除', style: style!.copyWith(color: errorColor)), + title: Text('删除', style: style.copyWith(color: errorColor)), ), if (ownerMid != Int64.ZERO) ListTile( @@ -985,7 +1008,7 @@ class ReplyItemGrpc extends StatelessWidget { }, minLeadingWidth: 0, leading: Icon(Icons.error_outline, color: errorColor, size: 19), - title: Text('举报', style: style!.copyWith(color: errorColor)), + title: Text('举报', style: style.copyWith(color: errorColor)), ), if (replyLevel == 1 && !isSubReply && ownerMid == upMid) ListTile( diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index f4f7c6c2e..a91554e40 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -1,4 +1,5 @@ import 'dart:convert'; +import 'dart:typed_data'; import 'package:PiliPlus/models/model_owner.dart'; import 'package:PiliPlus/models/user/danmaku_rule_adapter.dart'; @@ -9,6 +10,7 @@ import 'package:PiliPlus/utils/accounts/account_type_adapter.dart'; import 'package:PiliPlus/utils/accounts/cookie_jar_adapter.dart'; import 'package:PiliPlus/utils/path_utils.dart'; import 'package:PiliPlus/utils/set_int_adapter.dart'; +import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:PiliPlus/utils/utils.dart'; import 'package:hive_flutter/hive_flutter.dart'; import 'package:path/path.dart' as path; @@ -20,7 +22,7 @@ abstract final class GStorage { static late final Box setting; static late final Box video; static late final Box watchProgress; - static late final Box reply; + static late final Box? reply; static Future init() async { await Hive.initFlutter(path.join(appSupportDirPath, 'hive')); @@ -55,17 +57,24 @@ abstract final class GStorage { Accounts.init(), Hive.openBox( 'watchProgress', + keyComparator: _intStrKeyComparator, compactionStrategy: (entries, deletedEntries) { return deletedEntries > 4; }, ).then((res) => watchProgress = res), - Hive.openBox( + ]); + + if (Pref.saveReply) { + reply = await Hive.openBox( 'reply', + keyComparator: _intStrKeyComparator, compactionStrategy: (entries, deletedEntries) { return deletedEntries > 10; }, - ).then((res) => reply = res), - ]); + ); + } else { + reply = null; + } } static String exportAllSettings() { @@ -107,7 +116,7 @@ abstract final class GStorage { video.compact(), Accounts.account.compact(), watchProgress.compact(), - reply.compact(), + ?reply?.compact(), ]); } @@ -120,7 +129,26 @@ abstract final class GStorage { video.close(), Accounts.account.close(), watchProgress.close(), - reply.close(), + ?reply?.close(), ]); } + + static int _intStrKeyComparator(dynamic k1, dynamic k2) { + if (k1 is int) { + if (k2 is int) { + return k2.compareTo(k1); + } else { + return -1; + } + } else if (k2 is String) { + final lenCompare = k2.length.compareTo((k1 as String).length); + if (lenCompare == 0) { + return k2.compareTo(k1); + } else { + return lenCompare; + } + } else { + return 1; + } + } } diff --git a/lib/utils/storage_key.dart b/lib/utils/storage_key.dart index 915cc6713..20cdd7620 100644 --- a/lib/utils/storage_key.dart +++ b/lib/utils/storage_key.dart @@ -228,7 +228,8 @@ abstract final class SettingBoxKey { navBarSort = 'navBarSort', tempPlayerConf = 'tempPlayerConf', reduceLuxColor = 'reduceLuxColor', - liveCdnUrl = 'liveCdnUrl'; + liveCdnUrl = 'liveCdnUrl', + saveReply = 'saveReply'; } abstract final class LocalCacheKey { diff --git a/lib/utils/storage_pref.dart b/lib/utils/storage_pref.dart index 2ba3ebcaa..cf8448a8a 100644 --- a/lib/utils/storage_pref.dart +++ b/lib/utils/storage_pref.dart @@ -960,4 +960,7 @@ abstract final class Pref { static double get touchSlopH => _setting.get(SettingBoxKey.touchSlopH, defaultValue: 24.0); + + static bool get saveReply => + _setting.get(SettingBoxKey.saveReply, defaultValue: true); }