diff --git a/lib/http/msg.dart b/lib/http/msg.dart index 921b37048..32981ea04 100644 --- a/lib/http/msg.dart +++ b/lib/http/msg.dart @@ -375,7 +375,7 @@ abstract final class MsgHttp { } // 发送私信 - static Future sendMsg({ + static Future> sendMsg({ int? senderUid, int? receiverId, int? msgType, @@ -417,12 +417,9 @@ abstract final class MsgHttp { ), ); if (res.data['code'] == 0) { - return { - 'status': true, - 'data': res.data['data'], - }; + return const Success(null); } else { - return {'status': false, 'msg': res.data['message']}; + return Error(res.data['message']); } } diff --git a/lib/pages/contact/view.dart b/lib/pages/contact/view.dart index 95d0336de..9a441e95a 100644 --- a/lib/pages/contact/view.dart +++ b/lib/pages/contact/view.dart @@ -47,7 +47,7 @@ class _ContactPageState extends State actions: [ IconButton( onPressed: () async { - UserModel? userModel = await Navigator.of(context).push( + final UserModel? userModel = await Navigator.of(context).push( GetPageRoute( page: () => FollowSearchPage( mid: mid, diff --git a/lib/pages/dynamics_create/view.dart b/lib/pages/dynamics_create/view.dart index 3b7b0d7ce..332e8c640 100644 --- a/lib/pages/dynamics_create/view.dart +++ b/lib/pages/dynamics_create/view.dart @@ -617,7 +617,7 @@ class _CreateDynPanelState extends CommonRichTextPubPageState { RichTextItem? voteItem = editController.items.firstWhereOrNull( (e) => e.type == RichTextType.vote, ); - VoteInfo? voteInfo = await Navigator.of(context).push( + final VoteInfo? voteInfo = await Navigator.of(context).push( GetPageRoute( page: () => CreateVotePage( voteId: voteItem?.id == null ? null : int.parse(voteItem!.id!), @@ -818,7 +818,7 @@ class _CreateDynPanelState extends CommonRichTextPubPageState { Future _onReserve() async { controller.keepChatPanel(); - ReserveInfoData? reserveInfo = await Navigator.of(context).push( + final ReserveInfoData? reserveInfo = await Navigator.of(context).push( GetPageRoute( page: () => CreateReservePage(sid: _reserveCard.value?.id), ), diff --git a/lib/pages/fan/view.dart b/lib/pages/fan/view.dart index 6bac81fc2..c8a8a2be1 100644 --- a/lib/pages/fan/view.dart +++ b/lib/pages/fan/view.dart @@ -74,6 +74,7 @@ class _FansPageState extends FollowTypePageState { mid: item.mid, name: item.uname!, avatar: item.face!, + selected: true, ), ); return; diff --git a/lib/pages/fav/video/view.dart b/lib/pages/fav/video/view.dart index 7d2e394d4..3a7010e80 100644 --- a/lib/pages/fav/video/view.dart +++ b/lib/pages/fav/video/view.dart @@ -63,7 +63,7 @@ class _FavVideoPageState extends State heroTag: heroTag, item: item, onTap: () async { - var res = await Get.toNamed( + final res = await Get.toNamed( '/favDetail', arguments: item, parameters: { diff --git a/lib/pages/follow/widgets/follow_item.dart b/lib/pages/follow/widgets/follow_item.dart index b4c038883..2a93348b0 100644 --- a/lib/pages/follow/widgets/follow_item.dart +++ b/lib/pages/follow/widgets/follow_item.dart @@ -33,6 +33,7 @@ class FollowItem extends StatelessWidget { mid: item.mid, name: item.uname!, avatar: item.face!, + selected: true, ), ); } else { diff --git a/lib/pages/member_favorite/view.dart b/lib/pages/member_favorite/view.dart index 68af659c2..97188c917 100644 --- a/lib/pages/member_favorite/view.dart +++ b/lib/pages/member_favorite/view.dart @@ -172,8 +172,8 @@ class _MemberFavoriteState extends State height: 98, child: MemberFavItem( item: item, - callback: (res) { - if (res == true) { + onDelete: (isDeleted) { + if (isDeleted ?? false) { _controller.favState ..value.mediaListResponse?.list?.remove(item) ..refresh(); diff --git a/lib/pages/member_favorite/widget/item.dart b/lib/pages/member_favorite/widget/item.dart index d1ee7a191..44761b263 100644 --- a/lib/pages/member_favorite/widget/item.dart +++ b/lib/pages/member_favorite/widget/item.dart @@ -12,10 +12,10 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; class MemberFavItem extends StatelessWidget { - const MemberFavItem({super.key, required this.item, this.callback}); + const MemberFavItem({super.key, required this.item, this.onDelete}); final SpaceFavItemModel item; - final ValueChanged? callback; + final ValueChanged? onDelete; @override Widget build(BuildContext context) { @@ -34,14 +34,14 @@ class MemberFavItem extends StatelessWidget { } if (item.type == 0 || item.type == 11) { - var res = await Get.toNamed( + final bool? isDeleted = await Get.toNamed( '/favDetail', parameters: { 'mediaId': item.id.toString(), 'heroTag': Utils.makeHeroTag(item.id), }, ); - callback?.call(res); + onDelete?.call(isDeleted); } else { SubDetailPage.toSubDetailPage( item.id!, diff --git a/lib/pages/setting/models/style_settings.dart b/lib/pages/setting/models/style_settings.dart index f9de4f850..dbf72df9e 100644 --- a/lib/pages/setting/models/style_settings.dart +++ b/lib/pages/setting/models/style_settings.dart @@ -669,7 +669,7 @@ List get styleSettings => [ ), NormalModel( onTap: (context, setState) async { - var result = await Get.toNamed('/fontSizeSetting'); + final double? result = await Get.toNamed('/fontSizeSetting'); if (result != null) { Get.put(ColorSelectController()).currentTextScale.value = result; } diff --git a/lib/pages/share/view.dart b/lib/pages/share/view.dart index 01e1c6b88..734d6d831 100644 --- a/lib/pages/share/view.dart +++ b/lib/pages/share/view.dart @@ -11,15 +11,17 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; class UserModel { - const UserModel({ + UserModel({ required this.mid, required this.name, required this.avatar, + this.selected = false, }); final int mid; final String name; final String avatar; + bool selected; @override bool operator ==(Object other) { @@ -41,11 +43,9 @@ class SharePanel extends StatefulWidget { super.key, required this.content, this.userList, - this.selectedIndex, }); final Map content; - final int? selectedIndex; final List? userList; @override @@ -53,7 +53,6 @@ class SharePanel extends StatefulWidget { } class _SharePanelState extends State { - int _selectedIndex = -1; final List _userList = []; final ScrollController _scrollController = ScrollController(); final FocusNode _focusNode = FocusNode(); @@ -72,9 +71,6 @@ class _SharePanelState extends State { super.initState(); if (widget.userList?.isNotEmpty == true) { _userList.addAll(widget.userList!); - if (widget.selectedIndex != null) { - _selectedIndex = widget.selectedIndex!; - } } } @@ -114,61 +110,66 @@ class _SharePanelState extends State { padding: EdgeInsets.zero, childBuilder: (index) { final item = _userList[index]; - return GestureDetector( - onTap: () { - _selectedIndex = index; - setState(() {}); - }, - behavior: HitTestBehavior.opaque, - child: SizedBox( - width: 65, - child: Stack( - clipBehavior: Clip.none, - alignment: Alignment.topCenter, - children: [ - Column( + return Builder( + builder: (context) { + return GestureDetector( + onTap: () { + item.selected = !item.selected; + (context as Element).markNeedsBuild(); + }, + behavior: HitTestBehavior.opaque, + child: SizedBox( + width: 65, + child: Stack( + clipBehavior: Clip.none, + alignment: Alignment.topCenter, children: [ - Padding( - padding: const EdgeInsets.all(5), - child: NetworkImgLayer( - width: 40, - height: 40, - src: item.avatar, - type: ImageType.avatar, + Column( + children: [ + Padding( + padding: const EdgeInsets.all(5), + child: NetworkImgLayer( + width: 40, + height: 40, + src: item.avatar, + type: ImageType.avatar, + ), + ), + const SizedBox(height: 2), + Text( + item.name, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: const TextStyle(fontSize: 12), + ), + ], + ), + if (item.selected) + Container( + width: 50, + height: 50, + decoration: BoxDecoration( + color: theme.colorScheme.primary + .withValues( + alpha: 0.3, + ), + shape: BoxShape.circle, + border: Border.all( + width: 1.5, + color: theme.colorScheme.primary, + ), + ), + child: const Icon( + Icons.check, + size: 20, + color: Colors.white, + ), ), - ), - const SizedBox(height: 2), - Text( - item.name, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: const TextStyle(fontSize: 12), - ), ], ), - if (index == _selectedIndex) - Container( - width: 50, - height: 50, - decoration: BoxDecoration( - color: theme.colorScheme.primary.withValues( - alpha: 0.3, - ), - shape: BoxShape.circle, - border: Border.all( - width: 1.5, - color: theme.colorScheme.primary, - ), - ), - child: const Icon( - Icons.check, - size: 20, - color: Colors.white, - ), - ), - ], - ), - ), + ), + ); + }, ); }, ), @@ -176,14 +177,13 @@ class _SharePanelState extends State { GestureDetector( onTap: () async { _focusNode.unfocus(); - UserModel? userModel = await Navigator.of(context).push( + final UserModel? userModel = await Navigator.of(context).push( GetPageRoute(page: () => const ContactPage()), ); if (userModel != null) { _userList ..remove(userModel) ..insert(0, userModel); - _selectedIndex = 0; _scrollController.jumpToTop(); setState(() {}); } @@ -248,17 +248,7 @@ class _SharePanelState extends State { ), const SizedBox(width: 12), FilledButton.tonal( - onPressed: () { - if (_selectedIndex == -1) { - SmartDialog.showToast('请选择分享的用户'); - return; - } - RequestUtils.pmShare( - receiverId: _userList[_selectedIndex].mid, - content: widget.content, - message: _controller.text, - ); - }, + onPressed: _onSend, style: FilledButton.styleFrom( tapTargetSize: MaterialTapTargetSize.shrinkWrap, visualDensity: const VisualDensity( @@ -274,4 +264,31 @@ class _SharePanelState extends State { ), ); } + + Future _onSend() async { + final list = _userList.where((user) => user.selected); + if (list.isEmpty) { + SmartDialog.showToast('请选择分享的用户'); + return; + } + SmartDialog.showLoading(); + final res = await Future.wait( + list.map( + (user) => RequestUtils.pmShare( + receiverId: user.mid, + content: widget.content, + message: _controller.text, + ), + ), + ); + SmartDialog.dismiss(); + if (res.every((e) => e)) { + Get.back(); + SmartDialog.showToast('分享成功'); + } else if (res.every((e) => !e)) { + SmartDialog.showToast('分享失败'); + } else { + SmartDialog.showToast('部分分享失败'); + } + } } diff --git a/lib/pages/video/reply_new/view.dart b/lib/pages/video/reply_new/view.dart index 5f7c30b64..125deedb5 100644 --- a/lib/pages/video/reply_new/view.dart +++ b/lib/pages/video/reply_new/view.dart @@ -320,7 +320,7 @@ class _ReplyPageState extends CommonRichTextPubPageState { item( onTap: () async { controller.keepChatPanel(); - ({String title, String url})? res = await Get.to( + final ({String title, String url})? res = await Get.to( ReplySearchPage(type: widget.replyType, oid: widget.oid), ); if (res != null) { diff --git a/lib/pages/whisper_detail/controller.dart b/lib/pages/whisper_detail/controller.dart index 1a6e843da..ba04ab1cc 100644 --- a/lib/pages/whisper_detail/controller.dart +++ b/lib/pages/whisper_detail/controller.dart @@ -82,7 +82,7 @@ class WhisperDetailController extends CommonListController { SmartDialog.showToast('请先登录'); return; } - var result = await ImGrpc.sendMsg( + final result = await ImGrpc.sendMsg( senderUid: account.mid, receiverId: mid!, content: msgType == 5 diff --git a/lib/utils/page_utils.dart b/lib/utils/page_utils.dart index eb3e38b54..f98ce5de3 100644 --- a/lib/utils/page_utils.dart +++ b/lib/utils/page_utils.dart @@ -62,7 +62,6 @@ abstract class PageUtils { }) async { // if (kDebugMode) debugPrint(content.toString()); - int? selectedIndex; List userList = []; final shareListRes = await ImGrpc.shareList(size: 3); @@ -77,11 +76,10 @@ abstract class PageUtils { ), ); } else if (context.mounted) { - UserModel? userModel = await Navigator.of(context).push( + final UserModel? userModel = await Navigator.of(context).push( GetPageRoute(page: () => const ContactPage()), ); if (userModel != null) { - selectedIndex = 0; userList.add(userModel); } } @@ -92,7 +90,6 @@ abstract class PageUtils { builder: (context) => SharePanel( content: content, userList: userList, - selectedIndex: selectedIndex, ), useSafeArea: true, enableDrag: false, diff --git a/lib/utils/request_utils.dart b/lib/utils/request_utils.dart index dbfd39de6..9cf446213 100644 --- a/lib/utils/request_utils.dart +++ b/lib/utils/request_utils.dart @@ -11,7 +11,6 @@ import 'package:PiliPlus/http/dynamics.dart'; import 'package:PiliPlus/http/fav.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/member.dart'; -import 'package:PiliPlus/http/msg.dart'; import 'package:PiliPlus/http/user.dart'; import 'package:PiliPlus/http/validate.dart'; import 'package:PiliPlus/http/video.dart'; @@ -64,13 +63,11 @@ abstract final class RequestUtils { // 16:番剧(id 为 epid) // 17:番剧 // https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/message/private_msg_content.md - static Future pmShare({ + static Future pmShare({ required int receiverId, required Map content, String? message, }) async { - SmartDialog.showLoading(); - final ownerMid = Accounts.main.mid; final contentRes = await ImGrpc.sendMsg( senderUid: ownerMid, @@ -83,26 +80,19 @@ abstract final class RequestUtils { if (contentRes.isSuccess) { if (message?.isNotEmpty == true) { - var msgRes = await MsgHttp.sendMsg( + final msgRes = await ImGrpc.sendMsg( senderUid: ownerMid, receiverId: receiverId, content: jsonEncode({"content": message}), - msgType: 1, + msgType: MsgType.EN_MSG_TYPE_TEXT, ); - Get.back(); - if (msgRes['status']) { - SmartDialog.showToast('分享成功'); - } else { - SmartDialog.showToast('内容分享成功,但消息分享失败: ${msgRes['msg']}'); - } + return msgRes.isSuccess; } else { - Get.back(); - SmartDialog.showToast('分享成功'); + return true; } } else { - SmartDialog.showToast('分享失败: ${(contentRes as Error).errMsg}'); + return false; } - SmartDialog.dismiss(); } static Future actionRelationMod({