diff --git a/lib/pages/common/reply_controller.dart b/lib/pages/common/reply_controller.dart index df8819a67..06711e79a 100644 --- a/lib/pages/common/reply_controller.dart +++ b/lib/pages/common/reply_controller.dart @@ -1,4 +1,9 @@ +import 'dart:convert'; +import 'dart:io'; + import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pb.dart'; +import 'package:PiliPlus/http/constants.dart'; +import 'package:PiliPlus/http/init.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/reply.dart'; import 'package:PiliPlus/models/common/reply_type.dart'; @@ -8,6 +13,7 @@ import 'package:PiliPlus/pages/video/detail/reply_new/reply_page.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/global_data.dart'; import 'package:PiliPlus/utils/utils.dart'; +import 'package:android_intent_plus/android_intent.dart'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; @@ -33,9 +39,15 @@ abstract class ReplyController extends CommonController { late bool hasUpTop = false; late final banWordForReply = GStorage.banWordForReply; - late final enableCommAntifraud = GStorage.enableCommAntifraud; late final antiGoodsReply = GStorage.antiGoodsReply; + // comment antifraud + late final _enableCommAntifraud = GStorage.enableCommAntifraud; + late final _biliSendCommAntifraud = GStorage.biliSendCommAntifraud; + bool get enableCommAntifraud => + _enableCommAntifraud || _biliSendCommAntifraud; + dynamic get sourceId; + @override void onInit() { super.onInit(); @@ -210,14 +222,22 @@ abstract class ReplyController extends CommonController { loadingState.value = LoadingState.success(response); if (enableCommAntifraud && context.mounted) { checkReply( - context, - oid ?? replyItem.oid.toInt(), - replyItem?.id.toInt(), - replyItem?.type.toInt() ?? + context: context, + oid: oid ?? replyItem.oid.toInt(), + rpid: replyItem?.id.toInt(), + replyType: replyItem?.type.toInt() ?? replyType?.index ?? ReplyType.video.index, - replyInfo.id.toInt(), - replyInfo.content.message, + replyId: replyInfo.id.toInt(), + message: replyInfo.content.message, + // + root: replyInfo.root.toInt(), + parent: replyInfo.parent.toInt(), + ctime: replyInfo.ctime.toInt(), + pictures: replyInfo.content.pictures + .map((item) => item.toProto3Json()) + .toList(), + mid: replyInfo.mid.toInt(), ); } } else { @@ -236,14 +256,20 @@ abstract class ReplyController extends CommonController { loadingState.value = LoadingState.success(response); if (enableCommAntifraud && context.mounted) { checkReply( - context, - oid ?? replyItem.oid, - replyItem?.rpid, - replyItem?.type.toInt() ?? + context: context, + oid: oid ?? replyItem.oid, + rpid: replyItem?.rpid, + replyType: replyItem?.type.toInt() ?? replyType?.index ?? ReplyType.video.index, - replyInfo.rpid ?? 0, - replyInfo.content?.message ?? '', + replyId: replyInfo.rpid ?? 0, + message: replyInfo.content?.message ?? '', + // + root: replyInfo.root, + parent: replyInfo.parent, + ctime: replyInfo.ctime, + pictures: replyInfo.content?.pictures, + mid: replyInfo.mid, ); } } @@ -291,14 +317,56 @@ abstract class ReplyController extends CommonController { } // ref https://github.com/freedom-introvert/biliSendCommAntifraud - void checkReply( - BuildContext context, - dynamic oid, - dynamic rpid, - int replyType, - int replyId, - String message, - ) async { + void checkReply({ + required BuildContext context, + required dynamic oid, + required dynamic rpid, + required int replyType, + required int replyId, + required String message, + dynamic root, + dynamic parent, + dynamic ctime, + dynamic pictures, + dynamic mid, + }) async { + await Future.delayed(const Duration(seconds: 5)); + + // biliSendCommAntifraud + if (_biliSendCommAntifraud && Platform.isAndroid) { + try { + List cookies = await Request.cookieManager.cookieJar + .loadForRequest(Uri.parse(HttpString.apiBaseUrl)); + final List cookieString = cookies + .map((Cookie cookie) => '${cookie.name}=${cookie.value}') + .toList(); + AndroidIntent intent = AndroidIntent( + package: 'icu.freedomIntrovert.biliSendCommAntifraud', + componentName: + 'icu.freedomIntrovert.biliSendCommAntifraud.ByXposedLaunchedActivity', + arguments: { + 'action': 0, + 'oid': oid, + 'type': replyType, + 'rpid': replyId, + 'root': root, + 'parent': parent, + 'ctime': ctime, + 'comment_text': message, + if (pictures.isNotEmpty == true) 'pictures': jsonEncode(pictures), + 'source_id': sourceId, + 'uid': mid, + 'cookies': cookieString, + }, + ); + intent.launch(); + } catch (e) { + debugPrint('biliSendCommAntifraud: $e'); + } + return; + } + + // CommAntifraud void showReplyCheckResult(String message) { showDialog( context: context, @@ -309,7 +377,6 @@ abstract class ReplyController extends CommonController { ); } - await Future.delayed(const Duration(seconds: 5)); if (context.mounted.not) return; // root reply if (rpid == null) { diff --git a/lib/pages/dynamics/detail/controller.dart b/lib/pages/dynamics/detail/controller.dart index 552b553f1..fa8994c8a 100644 --- a/lib/pages/dynamics/detail/controller.dart +++ b/lib/pages/dynamics/detail/controller.dart @@ -1,8 +1,10 @@ import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pb.dart'; import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/models/common/reply_type.dart'; import 'package:PiliPlus/models/dynamics/result.dart'; import 'package:PiliPlus/pages/common/reply_controller.dart'; import 'package:PiliPlus/utils/global_data.dart'; +import 'package:PiliPlus/utils/id_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:get/get.dart'; import 'package:PiliPlus/http/html.dart'; @@ -11,13 +13,17 @@ import 'package:fixnum/fixnum.dart' as $fixnum; class DynamicDetailController extends ReplyController { DynamicDetailController(this.oid, this.type); - int? oid; - int? type; + int oid; + int type; late DynamicItemModel item; int? floor; late final horizontalPreview = GStorage.horizontalPreview; + @override + dynamic get sourceId => + type == ReplyType.video.index ? IdUtils.av2bv(oid) : oid; + @override void onInit() { super.onInit(); @@ -42,8 +48,8 @@ class DynamicDetailController extends ReplyController { @override Future customGetData() => GlobalData().grpcReply ? ReplyHttp.replyListGrpc( - type: type ?? 1, - oid: oid!, + type: type, + oid: oid, cursor: CursorReq( next: cursor?.next ?? $fixnum.Int64(0), mode: mode.value, @@ -53,9 +59,9 @@ class DynamicDetailController extends ReplyController { ) : ReplyHttp.replyList( isLogin: isLogin, - oid: oid!, + oid: oid, nextOffset: nextOffset, - type: type!, + type: type, sort: sortType.value.index, page: currentPage, banWordForReply: banWordForReply, diff --git a/lib/pages/dynamics/detail/view.dart b/lib/pages/dynamics/detail/view.dart index 0ca3e98cf..3a8270d59 100644 --- a/lib/pages/dynamics/detail/view.dart +++ b/lib/pages/dynamics/detail/view.dart @@ -27,7 +27,6 @@ import 'package:PiliPlus/pages/dynamics/detail/index.dart'; import 'package:PiliPlus/pages/dynamics/widgets/author_panel.dart'; import 'package:PiliPlus/pages/video/detail/reply_reply/index.dart'; import 'package:PiliPlus/utils/feed_back.dart'; -import 'package:PiliPlus/utils/id_utils.dart'; import 'package:share_plus/share_plus.dart'; import '../../../utils/grid.dart'; @@ -430,11 +429,9 @@ class _DynamicDetailPageState extends State heroTag: null, onPressed: () { feedBack(); - dynamic oid = _dynamicDetailController.oid ?? - IdUtils.bv2av(Get.parameters['bvid']!); _dynamicDetailController.onReply( context, - oid: oid, + oid: _dynamicDetailController.oid, replyType: ReplyType.values[replyType], ); }, diff --git a/lib/pages/html/controller.dart b/lib/pages/html/controller.dart index 2fa24bafa..16a802ff7 100644 --- a/lib/pages/html/controller.dart +++ b/lib/pages/html/controller.dart @@ -26,6 +26,9 @@ class HtmlRenderController extends ReplyController { late final horizontalPreview = GStorage.horizontalPreview; + @override + dynamic get sourceId => id; + @override void onInit() { super.onInit(); diff --git a/lib/pages/setting/widgets/model.dart b/lib/pages/setting/widgets/model.dart index 216753586..9ab30e595 100644 --- a/lib/pages/setting/widgets/model.dart +++ b/lib/pages/setting/widgets/model.dart @@ -42,6 +42,7 @@ import 'package:auto_orientation/auto_orientation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; @@ -1967,6 +1968,14 @@ List get extraSettings => [ setKey: SettingBoxKey.enableCommAntifraud, defaultVal: false, ), + SettingsModel( + settingsType: SettingsType.sw1tch, + title: '使用「哔哩发评反诈」检查评论', + subtitle: '仅对Android生效', + leading: Icon(FontAwesomeIcons.b), + setKey: SettingBoxKey.biliSendCommAntifraud, + defaultVal: false, + ), SettingsModel( settingsType: SettingsType.sw1tch, title: '屏蔽带货动态', diff --git a/lib/pages/video/detail/reply/controller.dart b/lib/pages/video/detail/reply/controller.dart index 2fa746713..189874ffa 100644 --- a/lib/pages/video/detail/reply/controller.dart +++ b/lib/pages/video/detail/reply/controller.dart @@ -4,25 +4,21 @@ import 'package:PiliPlus/models/common/reply_type.dart'; import 'package:PiliPlus/pages/common/reply_controller.dart'; import 'package:PiliPlus/http/reply.dart'; import 'package:PiliPlus/utils/global_data.dart'; +import 'package:PiliPlus/utils/id_utils.dart'; import 'package:fixnum/fixnum.dart' as $fixnum; class VideoReplyController extends ReplyController { - VideoReplyController( - this.aid, - this.rpid, - this.replyLevel, - ); + VideoReplyController({required this.aid}); // 视频aid 请求时使用的oid - int? aid; - // 层级 2为楼中楼 - String? replyLevel; - // rpid 请求楼中楼回复 - String? rpid; + int aid; + + @override + dynamic get sourceId => IdUtils.av2bv(aid); @override Future customGetData() => GlobalData().grpcReply ? ReplyHttp.replyListGrpc( - oid: aid!, + oid: aid, cursor: CursorReq( next: cursor?.next ?? $fixnum.Int64(0), mode: mode.value, @@ -32,7 +28,7 @@ class VideoReplyController extends ReplyController { ) : ReplyHttp.replyList( isLogin: isLogin, - oid: aid!, + oid: aid, nextOffset: nextOffset, type: ReplyType.video.index, sort: sortType.value.index, diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index 4e377b127..c229cb207 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -14,12 +14,11 @@ import 'package:get/get.dart'; import 'package:PiliPlus/common/skeleton/video_reply.dart'; import 'package:PiliPlus/models/common/reply_type.dart'; import 'package:PiliPlus/utils/feed_back.dart'; -import 'package:PiliPlus/utils/id_utils.dart'; import 'controller.dart'; class VideoReplyPanel extends StatefulWidget { final String? bvid; - final int? oid; + final int oid; final int rpid; final String? replyLevel; final String heroTag; @@ -31,7 +30,7 @@ class VideoReplyPanel extends StatefulWidget { const VideoReplyPanel({ super.key, this.bvid, - this.oid, + required this.oid, this.rpid = 0, this.replyLevel, required this.heroTag, @@ -65,13 +64,7 @@ class _VideoReplyPanelState extends State // heroTag = Get.arguments['heroTag']; heroTag = widget.heroTag; replyLevel = widget.replyLevel ?? '1'; - if (replyLevel == '2') { - _videoReplyController = Get.put( - VideoReplyController(widget.oid, widget.rpid.toString(), replyLevel), - tag: widget.rpid.toString()); - } else { - _videoReplyController = Get.find(tag: heroTag); - } + _videoReplyController = Get.find(tag: heroTag); fabAnimationCtr = AnimationController( vsync: this, duration: const Duration(milliseconds: 100)); @@ -196,11 +189,9 @@ class _VideoReplyPanelState extends State heroTag: null, onPressed: () { feedBack(); - dynamic oid = _videoReplyController.aid ?? - IdUtils.bv2av(Get.parameters['bvid']!); _videoReplyController.onReply( context, - oid: oid, + oid: _videoReplyController.aid, replyType: ReplyType.video, ); }, diff --git a/lib/pages/video/detail/reply_reply/controller.dart b/lib/pages/video/detail/reply_reply/controller.dart index d665572cf..3f8ac7b44 100644 --- a/lib/pages/video/detail/reply_reply/controller.dart +++ b/lib/pages/video/detail/reply_reply/controller.dart @@ -3,6 +3,7 @@ import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/video/reply/item.dart'; import 'package:PiliPlus/pages/common/reply_controller.dart'; import 'package:PiliPlus/utils/global_data.dart'; +import 'package:PiliPlus/utils/id_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -27,9 +28,9 @@ class VideoReplyReplyController extends ReplyController bool hasRoot = false; int? id; // 视频aid 请求时使用的oid - int? oid; + int oid; // rpid 请求楼中楼回复 - int? rpid; + int rpid; ReplyType replyType; // = ReplyType.video; int? upMid; @@ -42,6 +43,10 @@ class VideoReplyReplyController extends ReplyController late final horizontalPreview = GStorage.horizontalPreview; + @override + dynamic get sourceId => + replyType == ReplyType.video ? IdUtils.av2bv(oid) : oid; + @override void onInit() { super.onInit(); @@ -49,26 +54,6 @@ class VideoReplyReplyController extends ReplyController queryData(); } - @override - Future queryData([bool isRefresh = true]) async { - // if (GlobalData().grpcReply && - // !isDialogue && - // currentPage == 1 && - // !hasRoot && - // firstFloor == null && - // rpid != null) { - // await GrpcRepo.replyInfo( - // rpid: rpid!, - // ).then((res) { - // if (res['status'] && (res['data']?.mid ?? -1) > 0) { - // firstFloor = res['data']; - // hasRoot = true; - // } - // }); - // } - return super.queryData(isRefresh); - } - @override Future onRefresh() { cursor = null; @@ -177,8 +162,8 @@ class VideoReplyReplyController extends ReplyController Future customGetData() => isDialogue ? ReplyHttp.dialogListGrpc( type: replyType.index, - oid: oid!, - root: rpid!, + oid: oid, + root: rpid, rpid: dialog!, cursor: CursorReq( next: cursor?.next, @@ -190,8 +175,8 @@ class VideoReplyReplyController extends ReplyController : GlobalData().grpcReply ? ReplyHttp.replyReplyListGrpc( type: replyType.index, - oid: oid!, - root: rpid!, + oid: oid, + root: rpid, rpid: id ?? 0, cursor: CursorReq( next: cursor?.next, @@ -202,8 +187,8 @@ class VideoReplyReplyController extends ReplyController ) : ReplyHttp.replyReplyList( isLogin: isLogin, - oid: oid!, - root: rpid!, + oid: oid, + root: rpid, pageNum: currentPage, type: replyType.index, banWordForReply: banWordForReply, diff --git a/lib/pages/video/detail/reply_reply/view.dart b/lib/pages/video/detail/reply_reply/view.dart index ddceccee2..dbcc0fd2a 100644 --- a/lib/pages/video/detail/reply_reply/view.dart +++ b/lib/pages/video/detail/reply_reply/view.dart @@ -22,8 +22,8 @@ class VideoReplyReplyPanel extends StatefulWidget { const VideoReplyReplyPanel({ super.key, this.id, - this.oid, - this.rpid, + required this.oid, + required this.rpid, this.dialog, this.firstFloor, this.source, @@ -34,8 +34,8 @@ class VideoReplyReplyPanel extends StatefulWidget { this.onDismissed, }); final int? id; - final int? oid; - final int? rpid; + final int oid; + final int rpid; final int? dialog; final dynamic firstFloor; final String? source; @@ -366,12 +366,20 @@ class _VideoReplyReplyPanelState extends State LoadingState.success(list); if (_videoReplyReplyController.enableCommAntifraud && mounted) { _videoReplyReplyController.checkReply( - context, - oid, - root, - widget.replyType.index, - replyInfo.id.toInt(), - replyInfo.content.message, + context: context, + oid: oid, + rpid: root, + replyType: widget.replyType.index, + replyId: replyInfo.id.toInt(), + message: replyInfo.content.message, + // + root: replyInfo.root.toInt(), + parent: replyInfo.parent.toInt(), + ctime: replyInfo.ctime.toInt(), + pictures: replyInfo.content.pictures + .map((item) => item.toProto3Json()) + .toList(), + mid: replyInfo.mid.toInt(), ); } } else { @@ -386,12 +394,18 @@ class _VideoReplyReplyPanelState extends State LoadingState.success(list); if (_videoReplyReplyController.enableCommAntifraud && mounted) { _videoReplyReplyController.checkReply( - context, - oid, - root, - widget.replyType.index, - replyInfo.rpid ?? 0, - replyInfo.content?.message ?? '', + context: context, + oid: oid, + rpid: root, + replyType: widget.replyType.index, + replyId: replyInfo.rpid ?? 0, + message: replyInfo.content?.message ?? '', + // + root: replyInfo.root, + parent: replyInfo.parent, + ctime: replyInfo.ctime, + pictures: replyInfo.content?.pictures, + mid: replyInfo.mid, ); } } diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart index 8b77325fd..9d3a10f14 100644 --- a/lib/pages/video/detail/view.dart +++ b/lib/pages/video/detail/view.dart @@ -121,8 +121,9 @@ class _VideoDetailPageState extends State if (videoDetailController.showReply) { _videoReplyController = Get.put( - VideoReplyController(videoDetailController.oid.value, '0', '1'), - tag: heroTag); + VideoReplyController(aid: videoDetailController.oid.value), + tag: heroTag, + ); } videoIntroController = Get.put(VideoIntroController(), tag: heroTag); _listenerDetail = videoIntroController.videoDetail.listen((value) { diff --git a/lib/utils/app_scheme.dart b/lib/utils/app_scheme.dart index 5521f6532..bfe7ec51c 100644 --- a/lib/utils/app_scheme.dart +++ b/lib/utils/app_scheme.dart @@ -90,9 +90,8 @@ class PiliScheme { // to check // to video reply String? oid = RegExp(r'/(\d+)').firstMatch(path)?.group(1); - if (oid != null) { - int? rpid = - int.tryParse(uri.queryParameters['comment_root_id']!); + int? rpid = int.tryParse(uri.queryParameters['comment_root_id']!); + if (oid != null && rpid != null) { Get.to( () => Scaffold( resizeToAvoidBottomInset: false, @@ -233,9 +232,9 @@ class PiliScheme { if (path.startsWith("/detail/")) { if (uri.queryParameters['comment_root_id'] != null) { String? oid = RegExp(r'/(\d+)').firstMatch(path)?.group(1); - if (oid != null) { - int? rpid = - int.tryParse(uri.queryParameters['comment_root_id']!); + int? rpid = + int.tryParse(uri.queryParameters['comment_root_id']!); + if (oid != null && rpid != null) { Get.to( () => Scaffold( resizeToAvoidBottomInset: false, @@ -252,7 +251,7 @@ class PiliScheme { ], ), body: VideoReplyReplyPanel( - oid: int.tryParse(oid), + oid: int.parse(oid), rpid: rpid, source: 'routePush', replyType: ReplyType.dynamics, diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart index 09802a92a..9e90bb826 100644 --- a/lib/utils/storage.dart +++ b/lib/utils/storage.dart @@ -366,6 +366,9 @@ class GStorage { static bool get enableCommAntifraud => GStorage.setting .get(SettingBoxKey.enableCommAntifraud, defaultValue: false); + static bool get biliSendCommAntifraud => GStorage.setting + .get(SettingBoxKey.biliSendCommAntifraud, defaultValue: false); + static bool get coinWithLike => GStorage.setting.get(SettingBoxKey.coinWithLike, defaultValue: false); @@ -609,6 +612,7 @@ class SettingBoxKey { showSeekPreview = 'showSeekPreview', showDmChart = 'showDmChart', enableCommAntifraud = 'enableCommAntifraud', + biliSendCommAntifraud = 'biliSendCommAntifraud', coinWithLike = 'coinWithLike', isPureBlackTheme = 'isPureBlackTheme', antiGoodsDyn = 'antiGoodsDyn', diff --git a/lib/utils/utils.dart b/lib/utils/utils.dart index 2fc10b54a..a9aa3ca79 100644 --- a/lib/utils/utils.dart +++ b/lib/utils/utils.dart @@ -310,8 +310,11 @@ class Utils { /// 点击评论action 直接查看评论 if (action == 'comment') { - Utils.toDupNamed('/dynamicDetail', - arguments: {'item': item, 'floor': floor, 'action': action}); + Utils.toDupNamed('/dynamicDetail', arguments: { + 'item': item, + 'floor': floor, + 'action': action, + }); return; } diff --git a/pubspec.lock b/pubspec.lock index 26dbc1322..0a666cfe2 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -22,6 +22,14 @@ packages: url: "https://pub.dev" source: hosted version: "6.7.0" + android_intent_plus: + dependency: "direct main" + description: + name: android_intent_plus + sha256: dfc1fd3a577205ae8f11e990fb4ece8c90cceabbee56fcf48e463ecf0bd6aae3 + url: "https://pub.dev" + source: hosted + version: "5.3.0" animations: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index 8e9a8cd58..956067871 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -182,6 +182,7 @@ dependencies: flex_seed_scheme: ^3.4.1 live_photo_maker: ^0.0.6 fl_chart: ^0.69.2 + android_intent_plus: ^5.3.0 dependency_overrides: screen_brightness: ^2.0.1