opt: msg btn

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-05-10 00:28:09 +08:00
parent 9e4bc24365
commit 0510fbb65a
5 changed files with 223 additions and 144 deletions

View File

@@ -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<int, Offset>? offset;
Rx<List<ThreeDotItem>?> threeDotItems = Rx<List<ThreeDotItem>?>(null);
Rx<List<ThreeDotItem>?> outsideItem = Rx<List<ThreeDotItem>?>(null);
@override
void onInit() {
super.onInit();
@@ -72,6 +81,16 @@ class WhisperController
return response.sessions;
}
@override
bool customHandleResponse(
bool isRefresh, Success<SessionMainReply> response) {
if (isRefresh) {
threeDotItems.value = response.response.threeDotItems;
outsideItem.value = response.response.outsideItem;
}
return false;
}
@override
Future<LoadingState<SessionMainReply>> customGetData() =>
ImGrpc.sessionMain(offset: offset);
@@ -140,4 +159,14 @@ class WhisperController
SmartDialog.showToast(res['msg']);
}
}
Future<void> 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']);
}
}
}

View File

@@ -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<WhisperPage> {
final _whisperController = Get.put(WhisperController());
final _controller = Get.put(WhisperController());
@override
Widget build(BuildContext context) {
@@ -28,83 +26,70 @@ class _WhisperPageState extends State<WhisperPage> {
appBar: AppBar(
title: const Text('消息'),
actions: [
IconButton(
tooltip: '一键已读',
Obx(() {
if (_controller.outsideItem.value?.isNotEmpty == true) {
return Row(
children: _controller.outsideItem.value!.map((e) {
return IconButton(
tooltip: e.hasTitle() ? e.title : null,
onPressed: () {
showConfirmDialog(
e.type.action(
context: context,
title: '一键已读',
content: '是否清除全部新消息提醒?',
onConfirm: _whisperController.onClearUnread,
);
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: const Icon(
size: 20,
Icons.cleaning_services,
),
),
PopupMenuButton(
icon: Icon(size: 20, e.type.icon),
);
}).toList());
}
return const SizedBox.shrink();
}),
Obx(() {
if (_controller.threeDotItems.value?.isNotEmpty == true) {
return PopupMenuButton(
itemBuilder: (context) {
return [
PopupMenuItem(
return _controller.threeDotItems.value!
.map((e) => PopupMenuItem(
onTap: () {
Get.to(const WhisperSettingsPage(
imSettingType: IMSettingType.SETTING_TYPE_NEED_ALL,
));
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: const Row(
child: Row(
children: [
Icon(size: 19, Icons.settings),
Text(' 消息设置'),
Icon(size: 17, e.type.icon),
Text(' ${e.title}'),
],
),
),
PopupMenuItem(
onTap: () {
Get.toNamed(
'/whisperDetail',
parameters: {
'talkerId': '844424930131966',
'name': 'UP主小助手',
'face':
'https://message.biliimg.com/bfs/im/489a63efadfb202366c2f88853d2217b5ddc7a13.png',
))
.toList();
},
);
},
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<WhisperPage> {
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<WhisperPage> {
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<WhisperPage> {
),
)
: 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<WhisperPage> {
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<WhisperPage> {
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<WhisperPage> {
),
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'],
);
},
);

View File

@@ -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<int, Offset>? offset;
final SessionPageType sessionPageType;
Rx<List<ThreeDotItem>?> threeDotItems = Rx<List<ThreeDotItem>?>(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<SessionSecondaryReply> response) {
if (isRefresh) {
threeDotItems.value = response.response.threeDotItems;
}
return false;
}
@override
Future<LoadingState<SessionSecondaryReply>> customGetData() =>
ImGrpc.sessionSecondary(

View File

@@ -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<WhisperSecPage> {
appBar: AppBar(
title: Text(widget.name),
actions: [
PopupMenuButton(
Obx(() {
if (_controller.threeDotItems.value?.isNotEmpty == true) {
return PopupMenuButton(
itemBuilder: (context) {
return [
PopupMenuItem(
return _controller.threeDotItems.value!
.map((e) => PopupMenuItem(
onTap: () {
showConfirmDialog(
e.type.action(
context: context,
title: '一键已读',
content: '是否清除全部新消息提醒?',
onConfirm: _controller.onClearUnread,
);
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: const Row(
child: Row(
children: [
Icon(
size: 17,
Icons.cleaning_services,
),
Text(' 一键已读'),
Icon(size: 17, e.type.icon),
Text(' ${e.title}'),
],
),
),
PopupMenuItem(
onTap: () {
showConfirmDialog(
context: context,
title: '清空列表',
content: '清空后所有消息将被删除,无法恢复',
onConfirm: _controller.onDeleteList,
))
.toList();
},
);
},
child: const Row(
children: [
Icon(
size: 19,
Icons.delete_forever_outlined,
),
Text(' 清空列表'),
],
),
),
];
},
),
}
return const SizedBox.shrink();
}),
],
),
body: refreshIndicator(

View File

@@ -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);
}
}
}