From 8819461eed1328c90c31211e642ec2383c929875 Mon Sep 17 00:00:00 2001 From: bggRGjQaUbCoE Date: Sat, 15 Feb 2025 18:04:38 +0800 Subject: [PATCH] mod: dyn detail: add action panel Closes #235 Signed-off-by: bggRGjQaUbCoE --- lib/pages/dynamics/detail/controller.dart | 36 +++- lib/pages/dynamics/detail/view.dart | 210 ++++++++++++++++++++-- 2 files changed, 228 insertions(+), 18 deletions(-) diff --git a/lib/pages/dynamics/detail/controller.dart b/lib/pages/dynamics/detail/controller.dart index 4b3c67d4..84c89c2e 100644 --- a/lib/pages/dynamics/detail/controller.dart +++ b/lib/pages/dynamics/detail/controller.dart @@ -1,8 +1,13 @@ import 'package:PiliPlus/grpc/app/main/community/reply/v1/reply.pb.dart'; +import 'package:PiliPlus/http/dynamics.dart'; import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/models/dynamics/result.dart'; import 'package:PiliPlus/pages/common/reply_controller.dart'; +import 'package:PiliPlus/utils/feed_back.dart'; import 'package:PiliPlus/utils/global_data.dart'; import 'package:PiliPlus/utils/storage.dart'; +import 'package:flutter/cupertino.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; import 'package:PiliPlus/http/html.dart'; import 'package:PiliPlus/http/reply.dart'; @@ -23,7 +28,7 @@ class DynamicDetailController extends ReplyController { item = Get.arguments['item']; floor = Get.arguments['floor']; if (floor == 1) { - count.value = int.parse(item!.modules!.moduleStat!.comment!.count ?? '0'); + count.value = int.parse(item.modules!.moduleStat!.comment!.count ?? '0'); } if (oid != 0) { @@ -58,4 +63,33 @@ class DynamicDetailController extends ReplyController { page: currentPage, banWordForReply: banWordForReply, ); + + // 动态点赞 + Future onLikeDynamic(VoidCallback callback) async { + feedBack(); + String dynamicId = item.idStr!; + // 1 已点赞 2 不喜欢 0 未操作 + Like like = item.modules.moduleStat.like; + int count = like.count == '点赞' ? 0 : int.parse(like.count ?? '0'); + bool status = like.status!; + int up = status ? 2 : 1; + var res = await DynamicsHttp.likeDynamic(dynamicId: dynamicId, up: up); + if (res['status']) { + SmartDialog.showToast(!status ? '点赞成功' : '取消赞'); + if (up == 1) { + item.modules.moduleStat.like.count = (count + 1).toString(); + item.modules.moduleStat.like.status = true; + } else { + if (count == 1) { + item.modules.moduleStat.like.count = '点赞'; + } else { + item.modules.moduleStat.like.count = (count - 1).toString(); + } + item.modules.moduleStat.like.status = false; + } + callback(); + } else { + SmartDialog.showToast(res['msg']); + } + } } diff --git a/lib/pages/dynamics/detail/view.dart b/lib/pages/dynamics/detail/view.dart index da36e1e4..64b5469c 100644 --- a/lib/pages/dynamics/detail/view.dart +++ b/lib/pages/dynamics/detail/view.dart @@ -4,8 +4,10 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/custom_sliver_persistent_header_delegate.dart'; import 'package:PiliPlus/common/widgets/loading_widget.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; +import 'package:PiliPlus/http/constants.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/common/reply_sort_type.dart'; +import 'package:PiliPlus/pages/dynamics/repost_dyn_panel.dart'; import 'package:PiliPlus/pages/video/detail/reply/widgets/reply_item.dart'; import 'package:PiliPlus/pages/video/detail/reply/widgets/reply_item_grpc.dart'; import 'package:PiliPlus/utils/extension.dart'; @@ -15,6 +17,7 @@ import 'package:PiliPlus/utils/utils.dart'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; +import 'package:font_awesome_flutter/font_awesome_flutter.dart'; import 'package:get/get.dart'; import 'package:PiliPlus/common/skeleton/video_reply.dart'; import 'package:PiliPlus/common/widgets/http_error.dart'; @@ -25,6 +28,7 @@ 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'; import '../widgets/dynamic_panel.dart'; @@ -402,30 +406,202 @@ class _DynamicDetailPageState extends State ), if (_fabAnimationCtr != null) Positioned( - bottom: MediaQuery.of(context).padding.bottom + 14, - right: 14, + left: 0, + right: 0, + bottom: 0, child: SlideTransition( position: Tween( - begin: const Offset(0, 2), + begin: const Offset(0, 1), end: const Offset(0, 0), ).animate(CurvedAnimation( parent: _fabAnimationCtr!, curve: Curves.easeInOut, )), - child: FloatingActionButton( - heroTag: null, - onPressed: () { - feedBack(); - dynamic oid = _dynamicDetailController.oid ?? - IdUtils.bv2av(Get.parameters['bvid']!); - _dynamicDetailController.onReply( - context, - oid: oid, - replyType: ReplyType.values[replyType], - ); - }, - tooltip: '评论动态', - child: const Icon(Icons.reply), + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + Padding( + padding: const EdgeInsets.only(right: 14, bottom: 14), + child: FloatingActionButton( + heroTag: null, + onPressed: () { + feedBack(); + dynamic oid = _dynamicDetailController.oid ?? + IdUtils.bv2av(Get.parameters['bvid']!); + _dynamicDetailController.onReply( + context, + oid: oid, + replyType: ReplyType.values[replyType], + ); + }, + tooltip: '评论动态', + child: const Icon(Icons.reply), + ), + ), + Container( + decoration: BoxDecoration( + color: Theme.of(context).colorScheme.surface, + border: Border( + top: BorderSide( + color: Theme.of(context) + .colorScheme + .outline + .withOpacity(0.08), + ), + ), + ), + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom), + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceAround, + children: [ + Expanded( + child: Builder( + builder: (context) => TextButton.icon( + onPressed: () { + showModalBottomSheet( + context: context, + isScrollControlled: true, + useSafeArea: true, + builder: (context) => RepostPanel( + item: _dynamicDetailController.item, + callback: () { + int count = int.tryParse( + _dynamicDetailController + .item + .modules + .moduleStat + .forward + ?.count ?? + '0') ?? + 0; + _dynamicDetailController + .item + .modules + .moduleStat + .forward! + .count = (count + 1).toString(); + if (context.mounted) { + (context as Element?) + ?.markNeedsBuild(); + } + }, + ), + ); + }, + icon: Icon( + FontAwesomeIcons.shareFromSquare, + size: 16, + color: Theme.of(context).colorScheme.outline, + semanticLabel: "转发", + ), + style: TextButton.styleFrom( + padding: + const EdgeInsets.fromLTRB(15, 0, 15, 0), + foregroundColor: + Theme.of(context).colorScheme.outline, + ), + label: Text( + _dynamicDetailController.item.modules + .moduleStat.forward!.count != + null + ? Utils.numFormat(_dynamicDetailController + .item + .modules + .moduleStat + .forward! + .count) + : '转发', + ), + ), + ), + ), + Expanded( + child: TextButton.icon( + onPressed: () { + Share.share( + '${HttpString.dynamicShareBaseUrl}/${_dynamicDetailController.item.idStr}'); + }, + icon: Icon( + FontAwesomeIcons.shareNodes, + size: 16, + color: Theme.of(context).colorScheme.outline, + semanticLabel: "分享", + ), + style: TextButton.styleFrom( + padding: + const EdgeInsets.fromLTRB(15, 0, 15, 0), + foregroundColor: + Theme.of(context).colorScheme.outline, + ), + label: const Text('分享'), + ), + ), + Expanded( + child: Builder( + builder: (context) => TextButton.icon( + onPressed: () => + _dynamicDetailController.onLikeDynamic(() { + if (context.mounted) { + (context as Element?)?.markNeedsBuild(); + } + }), + icon: Icon( + _dynamicDetailController + .item.modules.moduleStat.like!.status! + ? FontAwesomeIcons.solidThumbsUp + : FontAwesomeIcons.thumbsUp, + size: 16, + color: _dynamicDetailController + .item.modules.moduleStat.like!.status! + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.outline, + semanticLabel: _dynamicDetailController + .item.modules.moduleStat.like!.status! + ? "已赞" + : "点赞", + ), + style: TextButton.styleFrom( + padding: + const EdgeInsets.fromLTRB(15, 0, 15, 0), + foregroundColor: + Theme.of(context).colorScheme.outline, + ), + label: AnimatedSwitcher( + duration: const Duration(milliseconds: 400), + transitionBuilder: (Widget child, + Animation animation) { + return ScaleTransition( + scale: animation, child: child); + }, + child: Text( + _dynamicDetailController.item.modules + .moduleStat.like!.count != + null + ? Utils.numFormat( + _dynamicDetailController.item + .modules.moduleStat.like!.count) + : '点赞', + style: TextStyle( + color: _dynamicDetailController.item + .modules.moduleStat.like!.status! + ? Theme.of(context) + .colorScheme + .primary + : Theme.of(context) + .colorScheme + .outline, + ), + ), + ), + ), + ), + ), + ], + ), + ), + ], ), ), ),