diff --git a/lib/pages/whisper/controller.dart b/lib/pages/whisper/controller.dart index 3804f19a..4ac44e13 100644 --- a/lib/pages/whisper/controller.dart +++ b/lib/pages/whisper/controller.dart @@ -1,5 +1,11 @@ import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart' - show Offset, Session, SessionId, SessionMainReply, SessionPageType; + show + Offset, + Session, + SessionId, + SessionMainReply, + SessionPageType, + ThreeDotItem; import 'package:PiliPlus/grpc/im.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/msg.dart'; @@ -18,6 +24,9 @@ class WhisperController PbMap? offset; + Rx?> threeDotItems = Rx?>(null); + Rx?> outsideItem = Rx?>(null); + @override void onInit() { super.onInit(); @@ -72,6 +81,16 @@ class WhisperController return response.sessions; } + @override + bool customHandleResponse( + bool isRefresh, Success response) { + if (isRefresh) { + threeDotItems.value = response.response.threeDotItems; + outsideItem.value = response.response.outsideItem; + } + return false; + } + @override Future> customGetData() => ImGrpc.sessionMain(offset: offset); @@ -140,4 +159,14 @@ class WhisperController SmartDialog.showToast(res['msg']); } } + + Future onDeleteList() async { + var res = await ImGrpc.deleteSessionList( + pageType: SessionPageType.SESSION_PAGE_TYPE_HOME); + if (res['status']) { + loadingState.value = LoadingState.success(null); + } else { + SmartDialog.showToast(res['msg']); + } + } } diff --git a/lib/pages/whisper/view.dart b/lib/pages/whisper/view.dart index c421f4f6..85e78aba 100644 --- a/lib/pages/whisper/view.dart +++ b/lib/pages/whisper/view.dart @@ -1,13 +1,11 @@ import 'package:PiliPlus/common/skeleton/whisper_item.dart'; -import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart'; import 'package:PiliPlus/http/loading_state.dart'; -import 'package:PiliPlus/pages/contact/view.dart'; import 'package:PiliPlus/pages/whisper/controller.dart'; import 'package:PiliPlus/pages/whisper/widgets/item.dart'; -import 'package:PiliPlus/pages/whisper_settings/view.dart'; +import 'package:PiliPlus/utils/extension.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; @@ -20,7 +18,7 @@ class WhisperPage extends StatefulWidget { } class _WhisperPageState extends State { - final _whisperController = Get.put(WhisperController()); + final _controller = Get.put(WhisperController()); @override Widget build(BuildContext context) { @@ -28,83 +26,70 @@ class _WhisperPageState extends State { appBar: AppBar( title: const Text('消息'), actions: [ - IconButton( - tooltip: '一键已读', - onPressed: () { - showConfirmDialog( - context: context, - title: '一键已读', - content: '是否清除全部新消息提醒?', - onConfirm: _whisperController.onClearUnread, + Obx(() { + if (_controller.outsideItem.value?.isNotEmpty == true) { + return Row( + children: _controller.outsideItem.value!.map((e) { + return IconButton( + tooltip: e.hasTitle() ? e.title : null, + onPressed: () { + e.type.action( + context: context, + onConfirm: () { + switch (e.type) { + case ThreeDotItemType.THREE_DOT_ITEM_TYPE_READ_ALL: + _controller.onClearUnread(); + case ThreeDotItemType + .THREE_DOT_ITEM_TYPE_CLEAR_LIST: + _controller.onDeleteList(); + default: + } + }); + }, + icon: Icon(size: 20, e.type.icon), + ); + }).toList()); + } + return const SizedBox.shrink(); + }), + Obx(() { + if (_controller.threeDotItems.value?.isNotEmpty == true) { + return PopupMenuButton( + itemBuilder: (context) { + return _controller.threeDotItems.value! + .map((e) => PopupMenuItem( + onTap: () { + e.type.action( + context: context, + onConfirm: () { + switch (e.type) { + case ThreeDotItemType + .THREE_DOT_ITEM_TYPE_READ_ALL: + _controller.onClearUnread(); + case ThreeDotItemType + .THREE_DOT_ITEM_TYPE_CLEAR_LIST: + _controller.onDeleteList(); + default: + } + }); + }, + child: Row( + children: [ + Icon(size: 17, e.type.icon), + Text(' ${e.title}'), + ], + ), + )) + .toList(); + }, ); - }, - icon: const Icon( - size: 20, - Icons.cleaning_services, - ), - ), - PopupMenuButton( - itemBuilder: (context) { - return [ - PopupMenuItem( - onTap: () { - Get.to(const WhisperSettingsPage( - imSettingType: IMSettingType.SETTING_TYPE_NEED_ALL, - )); - }, - child: const Row( - children: [ - Icon(size: 19, Icons.settings), - Text(' 消息设置'), - ], - ), - ), - PopupMenuItem( - onTap: () { - Get.toNamed( - '/whisperDetail', - parameters: { - 'talkerId': '844424930131966', - 'name': 'UP主小助手', - 'face': - 'https://message.biliimg.com/bfs/im/489a63efadfb202366c2f88853d2217b5ddc7a13.png', - }, - ); - }, - child: const Row( - children: [ - Icon(size: 18, Icons.live_tv), - Text(' UP主小助手'), - ], - ), - ), - // PopupMenuItem( - // onTap: () {}, - // child: const Row( - // children: [ - // Icon(size: 19, Icons.notifications_none), - // Text(' 应援团消息助手'), - // ], - // ), - // ), - PopupMenuItem( - onTap: () { - Get.to(const ContactPage(isFromSelct: false)); - }, - child: const Row( - children: [ - Icon(size: 19, Icons.account_box_outlined), - Text(' 通讯录'), - ], - ), - ), - ]; - }, - ), + } + return const SizedBox.shrink(); + }), ], ), body: refreshIndicator( - onRefresh: _whisperController.onRefresh, + onRefresh: _controller.onRefresh, child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ @@ -113,8 +98,7 @@ class _WhisperPageState extends State { padding: EdgeInsets.only( bottom: MediaQuery.paddingOf(context).bottom + 100, ), - sliver: - Obx(() => _buildBody(_whisperController.loadingState.value)), + sliver: Obx(() => _buildBody(_controller.loadingState.value)), ), ], ), @@ -135,15 +119,14 @@ class _WhisperPageState extends State { itemCount: loadingState.response!.length, itemBuilder: (context, index) { if (index == loadingState.response!.length - 1) { - _whisperController.onLoadMore(); + _controller.onLoadMore(); } return WhisperSessionItem( item: loadingState.response![index], onSetTop: (isTop, id) => - _whisperController.onSetTop(index, isTop, id), - onRemove: (talkerId) => - _whisperController.onRemove(index, talkerId), - onTap: () => _whisperController.onTap(index), + _controller.onSetTop(index, isTop, id), + onRemove: (talkerId) => _controller.onRemove(index, talkerId), + onTap: () => _controller.onTap(index), ); }, separatorBuilder: (context, index) => Divider( @@ -154,11 +137,11 @@ class _WhisperPageState extends State { ), ) : HttpError( - onReload: _whisperController.onReload, + onReload: _controller.onReload, ), Error() => HttpError( errMsg: loadingState.errMsg, - onReload: _whisperController.onReload, + onReload: _controller.onReload, ), }; } @@ -169,8 +152,8 @@ class _WhisperPageState extends State { sliver: SliverToBoxAdapter( child: Row( mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: List.generate(_whisperController.msgFeedTopItems.length, - (index) { + children: + List.generate(_controller.msgFeedTopItems.length, (index) { final ThemeData theme = Theme.of(context); return GestureDetector( behavior: HitTestBehavior.opaque, @@ -183,16 +166,14 @@ class _WhisperPageState extends State { children: [ Obx( () => Badge( - isLabelVisible: - _whisperController.unreadCounts[index] > 0, - label: Text( - " ${_whisperController.unreadCounts[index]} "), + isLabelVisible: _controller.unreadCounts[index] > 0, + label: Text(" ${_controller.unreadCounts[index]} "), alignment: Alignment.topRight, child: CircleAvatar( radius: 22, backgroundColor: theme.colorScheme.onInverseSurface, child: Icon( - _whisperController.msgFeedTopItems[index]['icon'], + _controller.msgFeedTopItems[index]['icon'], size: 20, color: theme.colorScheme.primary, ), @@ -201,20 +182,20 @@ class _WhisperPageState extends State { ), const SizedBox(height: 6), Text( - _whisperController.msgFeedTopItems[index]['name'], + _controller.msgFeedTopItems[index]['name'], style: const TextStyle(fontSize: 13), ), ], ), ), onTap: () { - if (!_whisperController.msgFeedTopItems[index]['enabled']) { + if (!_controller.msgFeedTopItems[index]['enabled']) { SmartDialog.showToast('已禁用'); return; } - _whisperController.unreadCounts[index] = 0; + _controller.unreadCounts[index] = 0; Get.toNamed( - _whisperController.msgFeedTopItems[index]['route'], + _controller.msgFeedTopItems[index]['route'], ); }, ); diff --git a/lib/pages/whisper_secondary/controller.dart b/lib/pages/whisper_secondary/controller.dart index 4dad7bc8..439ed8d4 100644 --- a/lib/pages/whisper_secondary/controller.dart +++ b/lib/pages/whisper_secondary/controller.dart @@ -1,10 +1,17 @@ import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart' - show Offset, Session, SessionId, SessionPageType, SessionSecondaryReply; + show + Offset, + Session, + SessionId, + SessionPageType, + SessionSecondaryReply, + ThreeDotItem; import 'package:PiliPlus/grpc/im.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/msg.dart'; import 'package:PiliPlus/pages/common/common_list_controller.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; +import 'package:get/get.dart'; import 'package:protobuf/protobuf.dart' show PbMap; class WhisperSecController @@ -15,6 +22,7 @@ class WhisperSecController PbMap? offset; final SessionPageType sessionPageType; + Rx?> threeDotItems = Rx?>(null); @override void onInit() { @@ -33,9 +41,19 @@ class WhisperSecController if (response.paginationParams.hasMore == false) { isEnd = true; } + return response.sessions; } + @override + bool customHandleResponse( + bool isRefresh, Success response) { + if (isRefresh) { + threeDotItems.value = response.response.threeDotItems; + } + return false; + } + @override Future> customGetData() => ImGrpc.sessionSecondary( diff --git a/lib/pages/whisper_secondary/view.dart b/lib/pages/whisper_secondary/view.dart index 1e624be9..a67d83fa 100644 --- a/lib/pages/whisper_secondary/view.dart +++ b/lib/pages/whisper_secondary/view.dart @@ -1,11 +1,11 @@ import 'package:PiliPlus/common/skeleton/whisper_item.dart'; -import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/pages/whisper/widgets/item.dart'; import 'package:PiliPlus/pages/whisper_secondary/controller.dart'; +import 'package:PiliPlus/utils/extension.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -35,50 +35,40 @@ class _WhisperSecPageState extends State { appBar: AppBar( title: Text(widget.name), actions: [ - PopupMenuButton( - itemBuilder: (context) { - return [ - PopupMenuItem( - onTap: () { - showConfirmDialog( - context: context, - title: '一键已读', - content: '是否清除全部新消息提醒?', - onConfirm: _controller.onClearUnread, - ); - }, - child: const Row( - children: [ - Icon( - size: 17, - Icons.cleaning_services, - ), - Text(' 一键已读'), - ], - ), - ), - PopupMenuItem( - onTap: () { - showConfirmDialog( - context: context, - title: '清空列表', - content: '清空后所有消息将被删除,无法恢复', - onConfirm: _controller.onDeleteList, - ); - }, - child: const Row( - children: [ - Icon( - size: 19, - Icons.delete_forever_outlined, - ), - Text(' 清空列表'), - ], - ), - ), - ]; - }, - ), + Obx(() { + if (_controller.threeDotItems.value?.isNotEmpty == true) { + return PopupMenuButton( + itemBuilder: (context) { + return _controller.threeDotItems.value! + .map((e) => PopupMenuItem( + onTap: () { + e.type.action( + context: context, + onConfirm: () { + switch (e.type) { + case ThreeDotItemType + .THREE_DOT_ITEM_TYPE_READ_ALL: + _controller.onClearUnread(); + case ThreeDotItemType + .THREE_DOT_ITEM_TYPE_CLEAR_LIST: + _controller.onDeleteList(); + default: + } + }); + }, + child: Row( + children: [ + Icon(size: 17, e.type.icon), + Text(' ${e.title}'), + ], + ), + )) + .toList(); + }, + ); + } + return const SizedBox.shrink(); + }), ], ), body: refreshIndicator( diff --git a/lib/utils/extension.dart b/lib/utils/extension.dart index 101fd39e..2b48cab0 100644 --- a/lib/utils/extension.dart +++ b/lib/utils/extension.dart @@ -1,9 +1,16 @@ +import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/hero_dialog_route.dart'; import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart'; +import 'package:PiliPlus/grpc/bilibili/app/im/v1.pbenum.dart' + show IMSettingType, ThreeDotItemType; import 'package:PiliPlus/models/common/image_preview_type.dart'; +import 'package:PiliPlus/pages/contact/view.dart'; +import 'package:PiliPlus/pages/whisper_settings/view.dart'; import 'package:floating/floating.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; +import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; extension ImageExtension on num? { int? cacheSize(BuildContext context) { @@ -150,3 +157,57 @@ extension RationalExt on Rational { return (min <= aspectRatio) && (aspectRatio <= max); } } + +extension ThreeDotItemTypeExt on ThreeDotItemType { + IconData get icon => switch (this) { + ThreeDotItemType.THREE_DOT_ITEM_TYPE_MSG_SETTING => Icons.settings, + ThreeDotItemType.THREE_DOT_ITEM_TYPE_READ_ALL => + Icons.cleaning_services, + ThreeDotItemType.THREE_DOT_ITEM_TYPE_CLEAR_LIST => + Icons.delete_forever_outlined, + ThreeDotItemType.THREE_DOT_ITEM_TYPE_UP_HELPER => Icons.live_tv, + ThreeDotItemType.THREE_DOT_ITEM_TYPE_CONTACTS => + Icons.account_box_outlined, + ThreeDotItemType.THREE_DOT_ITEM_TYPE_FANS_GROUP_HELPER => + Icons.notifications_none, + _ => MdiIcons.circleMedium, + }; + + void action( + {required BuildContext context, required VoidCallback onConfirm}) { + switch (this) { + case ThreeDotItemType.THREE_DOT_ITEM_TYPE_READ_ALL: + showConfirmDialog( + context: context, + title: '一键已读', + content: '是否清除全部新消息提醒?', + onConfirm: onConfirm, + ); + case ThreeDotItemType.THREE_DOT_ITEM_TYPE_CLEAR_LIST: + showConfirmDialog( + context: context, + title: '清空列表', + content: '清空后所有消息将被删除,无法恢复', + onConfirm: onConfirm, + ); + case ThreeDotItemType.THREE_DOT_ITEM_TYPE_MSG_SETTING: + Get.to(const WhisperSettingsPage( + imSettingType: IMSettingType.SETTING_TYPE_NEED_ALL, + )); + case ThreeDotItemType.THREE_DOT_ITEM_TYPE_UP_HELPER: + Get.toNamed( + '/whisperDetail', + parameters: { + 'talkerId': '844424930131966', + 'name': 'UP主小助手', + 'face': + 'https://message.biliimg.com/bfs/im/489a63efadfb202366c2f88853d2217b5ddc7a13.png', + }, + ); + case ThreeDotItemType.THREE_DOT_ITEM_TYPE_CONTACTS: + Get.to(const ContactPage(isFromSelct: false)); + default: + SmartDialog.showToast(name); + } + } +}