diff --git a/lib/http/api.dart b/lib/http/api.dart index 16d16415..04178453 100644 --- a/lib/http/api.dart +++ b/lib/http/api.dart @@ -775,4 +775,6 @@ class Api { '${HttpString.appBaseUrl}/x/v2/search/recommend'; static const String articleInfo = '/x/article/viewinfo'; + + static const String dynamicReport = '/x/dynamic/feed/dynamic_report/add'; } diff --git a/lib/http/user.dart b/lib/http/user.dart index 2ecaa010..03ca772e 100644 --- a/lib/http/user.dart +++ b/lib/http/user.dart @@ -666,4 +666,28 @@ class UserHttp { return {'status': false, 'msg': res.data['message']}; } } + + static Future dynamicReport({ + required dynamic mid, + required dynamic dynId, + required int reasonType, + String? reasonDesc, + }) async { + final res = await Request().post( + Api.dynamicReport, + queryParameters: { + 'csrf': Accounts.main.csrf, + }, + data: { + "accused_uid": mid, + "dynamic_id": dynId, + "reason_type": reasonType, + "reason_desc": reasonType == 0 ? reasonDesc : null, + }, + options: Options( + contentType: Headers.formUrlEncodedContentType, + ), + ); + return res.data as Map; + } } diff --git a/lib/pages/dynamics/widgets/author_panel.dart b/lib/pages/dynamics/widgets/author_panel.dart index 3f16783a..dd8c6ed7 100644 --- a/lib/pages/dynamics/widgets/author_panel.dart +++ b/lib/pages/dynamics/widgets/author_panel.dart @@ -3,13 +3,11 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/avatar.dart'; import 'package:PiliPlus/common/widgets/report.dart'; import 'package:PiliPlus/common/widgets/save_panel.dart'; -import 'package:PiliPlus/http/index.dart'; import 'package:PiliPlus/http/video.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:cached_network_image/cached_network_image.dart'; -import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -213,254 +211,235 @@ class AuthorPanel extends StatelessWidget { style: ButtonStyle( padding: WidgetStateProperty.all(EdgeInsets.zero), ), - onPressed: () { - showModalBottomSheet( - context: context, - useSafeArea: true, - isScrollControlled: true, - constraints: BoxConstraints( - maxWidth: min(640, min(Get.width, Get.height)), - ), - builder: (context) { - return morePanel(context); - }, - ); - }, + onPressed: () => morePanel(context), icon: const Icon(Icons.more_vert_outlined, size: 18), ), ); - Widget morePanel(context) { + void morePanel(BuildContext context) { String? bvid; - try { - bvid = switch (item.type) { - 'DYNAMIC_TYPE_AV' => item.modules.moduleDynamic.major.archive.bvid, - 'DYNAMIC_TYPE_UGC_SEASON' => - item.modules.moduleDynamic.major.ugcSeason.bvid, - _ => null, - }; - } catch (_) {} - if (bvid == null && item.orig != null) { - try { - bvid = switch (item.orig.type) { - 'DYNAMIC_TYPE_AV' => - item.orig.modules.moduleDynamic.major.archive.bvid, - 'DYNAMIC_TYPE_UGC_SEASON' => - item.orig.modules.moduleDynamic.major.ugcSeason.bvid, + getBvid(String? type, dynamic major) => switch (type) { + 'DYNAMIC_TYPE_AV' => major?.archive?.bvid, + 'DYNAMIC_TYPE_UGC_SEASON' => major?.ugcSeason?.bvid, _ => null, }; - } catch (_) {} + bvid = getBvid(item.type, item.modules?.moduleDynamic?.major); + if (bvid == null && item.orig != null) { + bvid = getBvid(item.type, item.orig?.modules?.moduleDynamic?.major); } - return Padding( - padding: EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - InkWell( - onTap: Get.back, - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(28), - topRight: Radius.circular(28), - ), - child: Container( - height: 35, - padding: const EdgeInsets.only(bottom: 2), - child: Center( + + showModalBottomSheet( + context: context, + useSafeArea: true, + isScrollControlled: true, + constraints: BoxConstraints( + maxWidth: min(640, min(Get.width, Get.height)), + ), + builder: (context) { + return Padding( + padding: + EdgeInsets.only(bottom: MediaQuery.of(context).padding.bottom), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + InkWell( + onTap: Get.back, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(28), + topRight: Radius.circular(28), + ), child: Container( - width: 32, - height: 3, - decoration: BoxDecoration( - color: Theme.of(context).colorScheme.outline, - borderRadius: const BorderRadius.all(Radius.circular(3))), + height: 35, + padding: const EdgeInsets.only(bottom: 2), + child: Center( + child: Container( + width: 32, + height: 3, + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.outline, + borderRadius: + const BorderRadius.all(Radius.circular(3))), + ), + ), ), ), - ), - ), - if (bvid != null) - ListTile( - onTap: () async { - Get.back(); - try { - var res = await UserHttp.toViewLater(bvid: bvid); - SmartDialog.showToast(res['msg']); - } catch (err) { - SmartDialog.showToast('出错了:${err.toString()}'); - } - }, - minLeadingWidth: 0, - leading: const Icon(Icons.watch_later_outlined, size: 19), - title: Text( - '稍后再看', - style: Theme.of(context).textTheme.titleSmall, + if (bvid != null) + ListTile( + onTap: () async { + Get.back(); + try { + var res = await UserHttp.toViewLater(bvid: bvid); + SmartDialog.showToast(res['msg']); + } catch (err) { + SmartDialog.showToast('出错了:${err.toString()}'); + } + }, + minLeadingWidth: 0, + leading: const Icon(Icons.watch_later_outlined, size: 19), + title: Text( + '稍后再看', + style: Theme.of(context).textTheme.titleSmall, + ), + ), + ListTile( + title: Text( + '分享动态', + style: Theme.of(context).textTheme.titleSmall, + ), + leading: const Icon(Icons.share_outlined, size: 19), + onTap: () { + Get.back(); + Utils.shareText( + '${HttpString.dynamicShareBaseUrl}/${item.idStr}'); + }, + minLeadingWidth: 0, ), - ), - ListTile( - title: Text( - '分享动态', - style: Theme.of(context).textTheme.titleSmall, - ), - leading: const Icon(Icons.share_outlined, size: 19), - onTap: () { - Get.back(); - Utils.shareText( - '${HttpString.dynamicShareBaseUrl}/${item.idStr}'); - }, - minLeadingWidth: 0, - ), - ListTile( - onTap: () { - Get.back(); - SavePanel.toSavePanel(item: item); - }, - minLeadingWidth: 0, - leading: const Icon(Icons.save_alt, size: 19), - title: Text('保存动态', style: Theme.of(context).textTheme.titleSmall!), - ), - ListTile( - title: Text( - '临时屏蔽:${item.modules.moduleAuthor.name}', - style: Theme.of(context).textTheme.titleSmall, - ), - leading: const Icon(Icons.visibility_off_outlined, size: 19), - onTap: () { - Get.back(); - DynamicsController dynamicsController = - Get.find(); - dynamicsController.tempBannedList - .add(item.modules.moduleAuthor.mid); - SmartDialog.showToast( - '已临时屏蔽${item.modules.moduleAuthor.name}(${item.modules.moduleAuthor.mid}),重启恢复'); - }, - minLeadingWidth: 0, - ), - if (item.modules.moduleAuthor.mid == Accounts.main.mid) ...[ - ListTile( - onTap: () { - Get.back(); - RequestUtils.checkCreatedDyn(id: item.idStr, isManual: true); - }, - minLeadingWidth: 0, - leading: Stack( - alignment: Alignment.center, - children: [ - const Icon(Icons.shield_outlined, size: 19), - const Icon(Icons.published_with_changes_sharp, size: 12), - ], - ), - title: - Text('检查动态', style: Theme.of(context).textTheme.titleSmall!), - ), - if (onSetTop != null) ListTile( onTap: () { Get.back(); - onSetTop!(item.modules?.moduleTag?.text != null, item.idStr); + SavePanel.toSavePanel(item: item); }, minLeadingWidth: 0, - leading: const Icon(Icons.vertical_align_top, size: 19), - title: Text( - '${item.modules?.moduleTag?.text != null ? '取消' : ''}置顶', + leading: const Icon(Icons.save_alt, size: 19), + title: Text('保存动态', style: Theme.of(context).textTheme.titleSmall!), ), - if (onRemove != null) ListTile( + title: Text( + '临时屏蔽:${item.modules?.moduleAuthor?.name}', + style: Theme.of(context).textTheme.titleSmall, + ), + leading: const Icon(Icons.visibility_off_outlined, size: 19), onTap: () { Get.back(); - showDialog( - context: context, - builder: (context) => AlertDialog( - title: const Text('确定删除该动态?'), - actions: [ - TextButton( - onPressed: Get.back, - child: Text( - '取消', - style: TextStyle( - color: Theme.of(context).colorScheme.outline, - ), - ), - ), - TextButton( - onPressed: () { - Get.back(); - onRemove?.call(item.idStr); - }, - child: const Text('确定'), - ), - ], - ), - ); + Get.find() + .tempBannedList + .add(item.modules!.moduleAuthor!.mid!); + SmartDialog.showToast( + '已临时屏蔽${item.modules?.moduleAuthor?.name}(${item.modules!.moduleAuthor!.mid}),重启恢复'); }, minLeadingWidth: 0, - leading: Icon(Icons.delete_outline, - color: Theme.of(context).colorScheme.error, size: 19), - title: Text('删除', - style: Theme.of(context) - .textTheme - .titleSmall! - .copyWith(color: Theme.of(context).colorScheme.error)), ), - ], - if (Accounts.main.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(); - autoWrapReportDialog( - context, - ReportOptions.dynamicReport, - (reasonType, reasonDesc, banUid) async { - if (banUid) { - VideoHttp.relationMod( - mid: item.modules.moduleAuthor.mid, - act: 5, - reSrc: 11, - ); - } - final res = await Request().post( - '/x/dynamic/feed/dynamic_report/add', - queryParameters: { - 'csrf': Accounts.main.csrf, - }, - data: { - "accused_uid": item.modules.moduleAuthor.mid, - "dynamic_id": item.idStr, - "reason_type": reasonType, - "reason_desc": reasonType == 0 ? reasonDesc : null, - }, - options: Options( - contentType: Headers.formUrlEncodedContentType, - ), - ); - return res.data as Map; + if (item.modules?.moduleAuthor?.mid == Accounts.main.mid) ...[ + ListTile( + onTap: () { + Get.back(); + RequestUtils.checkCreatedDyn( + id: item.idStr, isManual: true); }, - ); - }, - minLeadingWidth: 0, - ), - const Divider(thickness: 0.1, height: 1), - ListTile( - onTap: Get.back, - minLeadingWidth: 0, - dense: true, - title: Text( - '取消', - style: TextStyle(color: Theme.of(context).colorScheme.outline), - textAlign: TextAlign.center, - ), + minLeadingWidth: 0, + leading: const Stack( + alignment: Alignment.center, + children: [ + Icon(Icons.shield_outlined, size: 19), + Icon(Icons.published_with_changes_sharp, size: 12), + ], + ), + title: Text('检查动态', + style: Theme.of(context).textTheme.titleSmall!), + ), + if (onSetTop != null) + ListTile( + onTap: () { + Get.back(); + onSetTop!( + item.modules?.moduleTag?.text != null, item.idStr); + }, + minLeadingWidth: 0, + leading: const Icon(Icons.vertical_align_top, size: 19), + title: Text( + '${item.modules?.moduleTag?.text != null ? '取消' : ''}置顶', + style: Theme.of(context).textTheme.titleSmall!), + ), + if (onRemove != null) + ListTile( + onTap: () { + Get.back(); + showDialog( + context: context, + builder: (context) => AlertDialog( + title: const Text('确定删除该动态?'), + actions: [ + TextButton( + onPressed: Get.back, + child: Text( + '取消', + style: TextStyle( + color: Theme.of(context).colorScheme.outline, + ), + ), + ), + TextButton( + onPressed: () { + Get.back(); + onRemove?.call(item.idStr); + }, + child: const Text('确定'), + ), + ], + ), + ); + }, + minLeadingWidth: 0, + leading: Icon(Icons.delete_outline, + color: Theme.of(context).colorScheme.error, size: 19), + title: Text('删除', + style: Theme.of(context).textTheme.titleSmall!.copyWith( + color: Theme.of(context).colorScheme.error)), + ), + ], + if (Accounts.main.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(); + autoWrapReportDialog( + context, + ReportOptions.dynamicReport, + (reasonType, reasonDesc, banUid) { + if (banUid) { + VideoHttp.relationMod( + mid: item.modules!.moduleAuthor!.mid!, + act: 5, + reSrc: 11, + ); + } + return UserHttp.dynamicReport( + mid: item.modules!.moduleAuthor!.mid, + dynId: item.idStr, + reasonType: reasonType, + ); + }, + ); + }, + minLeadingWidth: 0, + ), + const Divider(thickness: 0.1, height: 1), + ListTile( + onTap: Get.back, + minLeadingWidth: 0, + dense: true, + title: Text( + '取消', + style: + TextStyle(color: Theme.of(context).colorScheme.outline), + textAlign: TextAlign.center, + ), + ), + ], ), - ], - ), + ); + }, ); } } diff --git a/lib/pages/dynamics/widgets/dynamic_panel.dart b/lib/pages/dynamics/widgets/dynamic_panel.dart index e1579c08..c7ed2f1e 100644 --- a/lib/pages/dynamics/widgets/dynamic_panel.dart +++ b/lib/pages/dynamics/widgets/dynamic_panel.dart @@ -1,4 +1,5 @@ import 'package:PiliPlus/common/widgets/image_save.dart'; +import 'package:PiliPlus/models/dynamics/result.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; @@ -9,7 +10,7 @@ import 'content_panel.dart'; import 'forward_panel.dart'; class DynamicPanel extends StatelessWidget { - final dynamic item; + final DynamicItemModel item; final String? source; final Function? onRemove; final Function(List, int)? callback; @@ -28,6 +29,13 @@ class DynamicPanel extends StatelessWidget { @override Widget build(BuildContext context) { + final authorWidget = AuthorPanel( + item: item, + source: source, + onRemove: onRemove, + isSave: isSave, + onSetTop: onSetTop, + ); return Container( decoration: isSave || (source == 'detail' && @@ -46,7 +54,7 @@ class DynamicPanel extends StatelessWidget { color: Colors.transparent, child: InkWell( onTap: source == 'detail' && - [ + const { 'DYNAMIC_TYPE_AV', 'DYNAMIC_TYPE_UGC_SEASON', 'DYNAMIC_TYPE_PGC_UNION', @@ -54,59 +62,20 @@ class DynamicPanel extends StatelessWidget { 'DYNAMIC_TYPE_LIVE', 'DYNAMIC_TYPE_LIVE_RCMD', 'DYNAMIC_TYPE_MEDIALIST', - ].contains(item.type).not + }.contains(item.type).not ? null : () => PageUtils.pushDynDetail(item, 1), - onLongPress: () { - if (item.type == 'DYNAMIC_TYPE_AV') { - imageSaveDialog( - context: context, - title: item.modules.moduleDynamic.major.archive.title, - cover: item.modules.moduleDynamic.major.archive.cover, - ); - } else if (item.type == 'DYNAMIC_TYPE_UGC_SEASON') { - imageSaveDialog( - context: context, - title: item.modules.moduleDynamic.major.ugcSeason.title, - cover: item.modules.moduleDynamic.major.ugcSeason.cover, - ); - } else if (item.type == 'DYNAMIC_TYPE_PGC' || - item.type == 'DYNAMIC_TYPE_PGC_UNION') { - imageSaveDialog( - context: context, - title: item.modules.moduleDynamic.major.pgc.title, - cover: item.modules.moduleDynamic.major.pgc.cover, - ); - } else if (item.type == 'DYNAMIC_TYPE_LIVE_RCMD') { - imageSaveDialog( - context: context, - title: item.modules.moduleDynamic.major.liveRcmd.title, - cover: item.modules.moduleDynamic.major.liveRcmd.cover, - ); - } else if (item.type == 'DYNAMIC_TYPE_LIVE') { - imageSaveDialog( - context: context, - title: item.modules.moduleDynamic.major.live.title, - cover: item.modules.moduleDynamic.major.live.cover, - ); - } - }, + onLongPress: () => _imageSaveDialog(context, authorWidget.morePanel), child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, children: [ Padding( padding: const EdgeInsets.fromLTRB(12, 12, 12, 6), - child: AuthorPanel( - item: item, - source: source, - onRemove: onRemove, - isSave: isSave, - onSetTop: onSetTop, - ), + child: authorWidget, ), - if (item!.modules!.moduleDynamic!.desc != null || - item!.modules!.moduleDynamic!.major != null) + if (item.modules!.moduleDynamic!.desc != null || + item.modules!.moduleDynamic!.major != null) content(isSave, context, item, source, callback), forWard(isSave, item, context, source, callback), const SizedBox(height: 2), @@ -118,4 +87,43 @@ class DynamicPanel extends StatelessWidget { ), ); } + + void _imageSaveDialog( + BuildContext context, + Function(BuildContext) morePanel, + ) { + late String? title; + late String? cover; + late final major = item.modules?.moduleDynamic?.major; + switch (item.type) { + case 'DYNAMIC_TYPE_AV': + title = major?.archive?.title; + cover = major?.archive?.cover; + break; + case 'DYNAMIC_TYPE_UGC_SEASON': + title = major?.ugcSeason?.title; + cover = major?.ugcSeason?.cover; + break; + case 'DYNAMIC_TYPE_PGC' || 'DYNAMIC_TYPE_PGC_UNION': + title = major?.pgc?.title; + cover = major?.pgc?.cover; + break; + case 'DYNAMIC_TYPE_LIVE_RCMD': + title = major?.liveRcmd?.title; + cover = major?.liveRcmd?.cover; + break; + case 'DYNAMIC_TYPE_LIVE': + title = major?.live?.title; + cover = major?.live?.cover; + break; + default: + morePanel(context); + return; + } + imageSaveDialog( + context: context, + title: title, + cover: cover, + ); + } } diff --git a/lib/pages/member_dynamics/view.dart b/lib/pages/member_dynamics/view.dart index 5751c488..a4f2f535 100644 --- a/lib/pages/member_dynamics/view.dart +++ b/lib/pages/member_dynamics/view.dart @@ -125,14 +125,11 @@ class _MemberDynamicsPageState extends State ? LastChildLayoutType.foot : LastChildLayoutType.none; }, - children: (loadingState.response as List) - .map( - (item) => DynamicPanel( + children: loadingState.response! + .map((item) => DynamicPanel( item: item, onRemove: _memberDynamicController.onRemove, - onSetTop: _memberDynamicController.onSetTop, - ), - ) + onSetTop: _memberDynamicController.onSetTop)) .toList(), ) : SliverCrossAxisGroup( diff --git a/lib/pages/member_search/search_dynamic.dart b/lib/pages/member_search/search_dynamic.dart index fedf9ca3..d3d15ce7 100644 --- a/lib/pages/member_search/search_dynamic.dart +++ b/lib/pages/member_search/search_dynamic.dart @@ -111,7 +111,7 @@ class _SearchDynamicState extends State ? LastChildLayoutType.foot : LastChildLayoutType.none; }, - children: (loadingState.response as List) + children: loadingState.response! .map((item) => DynamicPanel(item: item)) .toList(), )