From 2dafffda942283ba0c03d39f26c1eb104e17dfa2 Mon Sep 17 00:00:00 2001 From: bggRGjQaUbCoE Date: Thu, 16 Jan 2025 16:40:51 +0800 Subject: [PATCH] feat: report dyn Signed-off-by: bggRGjQaUbCoE --- lib/models/dynamics/result.dart | 3 + lib/pages/dynamics/widgets/author_panel.dart | 217 ++++++++++++++++-- .../dynamics/widgets/rich_node_panel.dart | 25 +- lib/pages/member/view.dart | 24 +- 4 files changed, 222 insertions(+), 47 deletions(-) diff --git a/lib/models/dynamics/result.dart b/lib/models/dynamics/result.dart index b4ba4fcec..b8d6afa1a 100644 --- a/lib/models/dynamics/result.dart +++ b/lib/models/dynamics/result.dart @@ -54,6 +54,7 @@ class ItemOrigModel { this.modules, this.type, this.visible, + this.idStr, }); Map? basic; @@ -61,6 +62,7 @@ class ItemOrigModel { ItemModulesModel? modules; String? type; bool? visible; + dynamic idStr; ItemOrigModel.fromJson(Map json) { basic = json['basic']; @@ -68,6 +70,7 @@ class ItemOrigModel { modules = ItemModulesModel.fromJson(json['modules']); type = json['type']; visible = json['visible']; + idStr = json['id_str']; } } diff --git a/lib/pages/dynamics/widgets/author_panel.dart b/lib/pages/dynamics/widgets/author_panel.dart index d14adaff1..746e523ee 100644 --- a/lib/pages/dynamics/widgets/author_panel.dart +++ b/lib/pages/dynamics/widgets/author_panel.dart @@ -1,7 +1,11 @@ +import 'package:PiliPlus/http/index.dart'; import 'package:PiliPlus/models/dynamics/result.dart'; +import 'package:PiliPlus/pages/member/view.dart' show radioWidget; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/storage.dart'; +import 'package:dio/dio.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:PiliPlus/common/widgets/network_img_layer.dart'; @@ -135,10 +139,7 @@ class AuthorPanel extends StatelessWidget { useRootNavigator: true, isScrollControlled: true, builder: (context) { - return MorePanel( - item: item, - onRemove: onRemove, - ); + return morePanel(context); }, ); }, @@ -148,19 +149,8 @@ class AuthorPanel extends StatelessWidget { ], ); } -} -class MorePanel extends StatelessWidget { - final dynamic item; - final Function? onRemove; - const MorePanel({ - super.key, - required this.item, - this.onRemove, - }); - - @override - Widget build(BuildContext context) { + Widget morePanel(context) { return Container( padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom), // clipBehavior: Clip.hardEdge, @@ -168,7 +158,7 @@ class MorePanel extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ InkWell( - onTap: () => Get.back(), + onTap: Get.back, borderRadius: const BorderRadius.only( topLeft: Radius.circular(28), topRight: Radius.circular(28), @@ -275,9 +265,28 @@ class MorePanel extends StatelessWidget { .titleSmall! .copyWith(color: Theme.of(context).colorScheme.error)), ), + if (GStorage.isLogin) + ListTile( + title: Text( + '举报', + style: Theme.of(context).textTheme.titleSmall!.copyWith( + color: Theme.of(context).colorScheme.error, + ), + ), + leading: Icon( + Icons.error_outline_outlined, + size: 19, + color: Theme.of(context).colorScheme.error, + ), + onTap: () { + Get.back(); + _showReportDynDialog(context); + }, + minLeadingWidth: 0, + ), const Divider(thickness: 0.1, height: 1), ListTile( - onTap: () => Get.back(), + onTap: Get.back, minLeadingWidth: 0, dense: true, title: Text( @@ -290,4 +299,176 @@ class MorePanel extends StatelessWidget { ), ); } + + void _showReportDynDialog(context) { + showDialog( + context: context, + builder: (context) { + _ReportReasonType? reasonType; + String? reasonDesc; + late final key = GlobalKey(); + + return AlertDialog( + title: Text( + '举报动态', + style: TextStyle(fontSize: 18), + ), + titlePadding: const EdgeInsets.only(left: 22, top: 16, right: 22), + contentPadding: const EdgeInsets.only(top: 5), + actionsPadding: + const EdgeInsets.only(left: 16, right: 16, bottom: 10), + content: Builder(builder: (context) { + return SingleChildScrollView( + child: AnimatedSize( + duration: const Duration(milliseconds: 200), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only( + left: 22, + right: 22, + bottom: 5, + ), + child: const Text('请选择举报的理由:'), + ), + ...List.generate( + _ReportReasonType.values.length ~/ 2, + (index) => Row( + children: List.generate(2, (index2) { + return Expanded( + child: radioWidget<_ReportReasonType>( + paddingStart: index2 == 0 ? 10 : 0, + value: _ReportReasonType + .values[index * 2 + index2], + groupValue: reasonType, + title: _ReportReasonType + .values[index * 2 + index2].title, + onChanged: (value) { + reasonType = value; + if (context.mounted) { + (context as Element?)?.markNeedsBuild(); + } + }, + ), + ); + }), + ), + ), + if (reasonType == _ReportReasonType.s10) ...[ + Padding( + padding: const EdgeInsets.symmetric(horizontal: 22), + child: const Text('为帮助审核人员更快处理,请补充问题类型和出现位置等详细信息'), + ), + Padding( + padding: const EdgeInsets.only( + left: 22, + top: 5, + right: 22, + ), + child: Form( + key: key, + child: TextFormField( + minLines: 4, + maxLines: 4, + initialValue: reasonDesc, + inputFormatters: [ + LengthLimitingTextInputFormatter(60), + ], + decoration: const InputDecoration( + border: OutlineInputBorder(), + contentPadding: EdgeInsets.all(10), + ), + onChanged: (value) => reasonDesc = value, + validator: (value) { + if (value.isNullOrEmpty) { + return '理由不能为空'; + } + return null; + }, + ), + ), + ), + ], + ], + ), + ), + ); + }), + actions: [ + TextButton( + onPressed: Get.back, + child: Text( + '取消', + style: TextStyle( + color: Theme.of(context).colorScheme.outline, + ), + ), + ), + TextButton( + onPressed: () async { + if (reasonType == null) { + return; + } + if (reasonType == _ReportReasonType.s10 && + key.currentState?.validate() != true) { + return; + } + try { + SmartDialog.showLoading(); + Request() + .post( + 'https://api.bilibili.com/x/dynamic/feed/dynamic_report/add', + queryParameters: { + 'csrf': await Request.getCsrf(), + }, + data: { + "accused_uid": item.modules.moduleAuthor.mid, + "dynamic_id": item.idStr, + "reason_type": reasonType!.code, + "reason_desc": reasonType == _ReportReasonType.s10 + ? reasonDesc + : null, + }, + options: Options( + contentType: Headers.formUrlEncodedContentType, + ), + ) + .then((res) { + SmartDialog.dismiss(); + if (res.data['code'] == 0) { + Get.back(); + SmartDialog.showToast('举报成功'); + } else { + SmartDialog.showToast(res.data['message']); + } + }); + } catch (e) { + debugPrint('failed to report dyn: $e'); + } + }, + child: const Text('确定'), + ), + ], + ); + }); + } +} + +enum _ReportReasonType { s1, s2, s3, s4, s5, s6, s7, s8, s9, s10 } + +extension _ReportReasonTypeExt on _ReportReasonType { + String get title => [ + '垃圾广告', + '引战', + '色情', + '人身攻击', + '违法信息', + '涉政谣言', + '涉社会事件谣言', + '虚假不实信息', + '违法信息外链', + '其他', + ][index]; + int get code => [4, 8, 1, 5, 3, 9, 10, 12, 13, 0][index]; } diff --git a/lib/pages/dynamics/widgets/rich_node_panel.dart b/lib/pages/dynamics/widgets/rich_node_panel.dart index 8b5c1dc9a..ffd78b622 100644 --- a/lib/pages/dynamics/widgets/rich_node_panel.dart +++ b/lib/pages/dynamics/widgets/rich_node_panel.dart @@ -178,24 +178,13 @@ InlineSpan? richNode(item, context) { alignment: PlaceholderAlignment.middle, child: GestureDetector( onTap: () { - dynamic id; - if (item is DynamicItemModel) { - id = item.idStr; - } else if (item is ItemOrigModel && - item.basic?['jump_url'] != null) { - id = RegExp(r'/(\d+)') - .firstMatch(item.basic?['jump_url']) - ?.group(1); - } - if (id != null) { - Get.toNamed( - '/webview', - parameters: { - 'url': - 'https://www.bilibili.com/h5/lottery/result?business_id=$id' - }, - ); - } + Get.toNamed( + '/webview', + parameters: { + 'url': + 'https://www.bilibili.com/h5/lottery/result?business_id=${item.idStr}' + }, + ); }, child: Text( '${i.origText} ', diff --git a/lib/pages/member/view.dart b/lib/pages/member/view.dart index a07aa5414..59fc3c288 100644 --- a/lib/pages/member/view.dart +++ b/lib/pages/member/view.dart @@ -581,13 +581,13 @@ class _ReportPanelState extends State { const Text('举报理由(单选,非必选)'), ...List.generate( 5, - (index) => _radioWidget( - index, - _reasonV2, - (value) { + (index) => radioWidget( + value: index, + groupValue: _reasonV2, + onChanged: (value) { setState(() => _reasonV2 = value); }, - ['色情低俗', '不实信息', '违禁', '人身攻击', '赌博诈骗'][index], + title: const ['色情低俗', '不实信息', '违禁', '人身攻击', '赌博诈骗'][index], ), ), const SizedBox(height: 10), @@ -650,16 +650,18 @@ Widget _checkBoxWidget( ); } -Widget _radioWidget( - int value, - int? groupValue, - ValueChanged onChanged, - String title, -) { +Widget radioWidget({ + required T value, + T? groupValue, + required ValueChanged onChanged, + required String title, + double? paddingStart, +}) { return InkWell( onTap: () => onChanged(value), child: Row( children: [ + if (paddingStart != null) SizedBox(width: paddingStart), Radio( value: value, groupValue: groupValue,