refa: whisper detail page

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-04-18 09:49:57 +08:00
parent ebe08c23e4
commit 261922d73a
5 changed files with 168 additions and 163 deletions

View File

@@ -455,9 +455,8 @@ class MsgHttp {
} }
} }
static Future sessionMsg({ static Future<LoadingState<SessionMsgDataModel>> sessionMsg(
int? talkerId, {int? talkerId}) async {
}) async {
Map params = await WbiSign.makSign({ Map params = await WbiSign.makSign({
'talker_id': talkerId, 'talker_id': talkerId,
'session_type': 1, 'session_type': 1,
@@ -469,15 +468,13 @@ class MsgHttp {
var res = await Request().get(Api.sessionMsg, queryParameters: params); var res = await Request().get(Api.sessionMsg, queryParameters: params);
if (res.data['code'] == 0) { if (res.data['code'] == 0) {
try { try {
return { return LoadingState.success(
'status': true, SessionMsgDataModel.fromJson(res.data['data']));
'data': SessionMsgDataModel.fromJson(res.data['data']),
};
} catch (err) { } catch (err) {
debugPrint(err.toString()); return LoadingState.error(err.toString());
} }
} else { } else {
return {'status': false, 'msg': res.data['message']}; return LoadingState.error(res.data['message']);
} }
} }

View File

@@ -13,7 +13,6 @@ import '../../utils/storage.dart';
class WhisperController class WhisperController
extends CommonListController<List<SessionList>?, SessionList> { extends CommonListController<List<SessionList>?, SessionList> {
late final bool disableLikeMsg;
late final List msgFeedTopItems; late final List msgFeedTopItems;
late final RxList<int> unreadCounts; late final RxList<int> unreadCounts;
@@ -22,7 +21,7 @@ class WhisperController
@override @override
void onInit() { void onInit() {
super.onInit(); super.onInit();
disableLikeMsg = final disableLikeMsg =
GStorage.setting.get(SettingBoxKey.disableLikeMsg, defaultValue: false); GStorage.setting.get(SettingBoxKey.disableLikeMsg, defaultValue: false);
msgFeedTopItems = [ msgFeedTopItems = [
{ {

View File

@@ -1,5 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/pages/common/common_list_controller.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
@@ -8,12 +10,15 @@ import 'package:PiliPlus/models/msg/session.dart';
import '../../utils/feed_back.dart'; import '../../utils/feed_back.dart';
import '../../utils/storage.dart'; import '../../utils/storage.dart';
class WhisperDetailController extends GetxController { class WhisperDetailController
extends CommonListController<SessionMsgDataModel, MessageItem> {
late final ownerMid = Accounts.main.mid;
late int talkerId; late int talkerId;
late String name; late String name;
late String face; late String face;
String? mid; String? mid;
RxList<MessageItem> messageList = <MessageItem>[].obs;
//表情转换图片规则 //表情转换图片规则
List<dynamic>? eInfos; List<dynamic>? eInfos;
@@ -25,48 +30,41 @@ class WhisperDetailController extends GetxController {
face = Get.parameters['face']!; face = Get.parameters['face']!;
mid = Get.parameters['mid']; mid = Get.parameters['mid'];
querySessionMsg(); queryData();
} }
Future querySessionMsg() async { @override
var res = await MsgHttp.sessionMsg(talkerId: talkerId); bool customHandleResponse(
if (res['status']) { bool isRefresh, Success<SessionMsgDataModel> response) {
messageList.value = res['data'].messages; List<MessageItem>? messageList = response.response.messages;
if (messageList.isNotEmpty) { if (messageList?.isNotEmpty == true) {
if (messageList.length == 1 && if (messageList!.length == 1 &&
messageList.last.msgType == 18 && messageList.last.msgType == 18 &&
messageList.last.msgSource == 18) { messageList.last.msgSource == 18) {
// debugPrint(messageList.last); // debugPrint(messageList.last);
// debugPrint(messageList.last.content); // debugPrint(messageList.last.content);
//{content: [{"text":"对方主动回复或关注你前最多发送1条消息","color_day":"#9499A0","color_nig":"#9499A0"}]} //{content: [{"text":"对方主动回复或关注你前最多发送1条消息","color_day":"#9499A0","color_nig":"#9499A0"}]}
} else { } else {
ackSessionMsg(); ackSessionMsg(messageList.last.msgSeqno);
} }
if (res['data'].eInfos != null) { if (response.response.eInfos != null) {
eInfos = res['data'].eInfos; eInfos = response.response.eInfos;
} }
} }
} else { return false;
SmartDialog.showToast(res['msg']);
}
} }
// 消息标记已读 // 消息标记已读
Future ackSessionMsg() async { Future ackSessionMsg(int? msgSeqno) async {
if (messageList.isEmpty) {
return;
}
var res = await MsgHttp.ackSessionMsg( var res = await MsgHttp.ackSessionMsg(
talkerId: talkerId, talkerId: talkerId,
ackSeqno: messageList.last.msgSeqno, ackSeqno: msgSeqno,
); );
if (!res['status']) { if (!res['status']) {
SmartDialog.showToast(res['msg']); SmartDialog.showToast(res['msg']);
} }
} }
late final ownerMid = Accounts.main.mid;
Future sendMsg({ Future sendMsg({
required String message, required String message,
dynamic picMsg, dynamic picMsg,
@@ -80,16 +78,16 @@ class WhisperDetailController extends GetxController {
SmartDialog.showToast('请先登录'); SmartDialog.showToast('请先登录');
return; return;
} }
if (picMsg == null && message == '') {
SmartDialog.dismiss();
SmartDialog.showToast('请输入内容');
return;
}
if (mid == null) { if (mid == null) {
SmartDialog.dismiss(); SmartDialog.dismiss();
SmartDialog.showToast('这里不能发'); SmartDialog.showToast('这里不能发');
return; return;
} }
if (picMsg == null && message == '') {
SmartDialog.dismiss();
SmartDialog.showToast('请输入内容');
return;
}
var result = await MsgHttp.sendMsg( var result = await MsgHttp.sendMsg(
senderUid: ownerMid, senderUid: ownerMid,
receiverId: int.parse(mid!), receiverId: int.parse(mid!),
@@ -99,13 +97,13 @@ class WhisperDetailController extends GetxController {
); );
SmartDialog.dismiss(); SmartDialog.dismiss();
if (result['status']) { if (result['status']) {
// debugPrint(result['data']);
if (msgType == 5) { if (msgType == 5) {
messageList[index!].msgStatus = 1; List<MessageItem> list = (loadingState.value as Success).response;
messageList.refresh(); list[index!].msgStatus = 1;
loadingState.refresh();
SmartDialog.showToast('撤回成功'); SmartDialog.showToast('撤回成功');
} else { } else {
querySessionMsg(); queryData();
onClearText(); onClearText();
SmartDialog.showToast('发送成功'); SmartDialog.showToast('发送成功');
} }
@@ -113,4 +111,13 @@ class WhisperDetailController extends GetxController {
SmartDialog.showToast(result['msg']); SmartDialog.showToast(result['msg']);
} }
} }
@override
List<MessageItem>? getDataList(SessionMsgDataModel response) {
return response.messages;
}
@override
Future<LoadingState<SessionMsgDataModel>> customGetData() =>
MsgHttp.sessionMsg(talkerId: talkerId);
} }

View File

@@ -1,5 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:PiliPlus/common/widgets/loading_widget.dart';
import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/http/msg.dart'; import 'package:PiliPlus/http/msg.dart';
import 'package:PiliPlus/models/msg/session.dart'; import 'package:PiliPlus/models/msg/session.dart';
import 'package:PiliPlus/pages/common/common_publish_page.dart'; import 'package:PiliPlus/pages/common/common_publish_page.dart';
@@ -45,11 +47,10 @@ class _WhisperDetailPageState
height: 34, height: 34,
child: IconButton( child: IconButton(
tooltip: '返回', tooltip: '返回',
style: ButtonStyle( style: IconButton.styleFrom(
padding: WidgetStateProperty.all(EdgeInsets.zero), padding: EdgeInsets.zero,
backgroundColor: WidgetStateProperty.resolveWith((states) { backgroundColor:
return Theme.of(context).colorScheme.secondaryContainer; Theme.of(context).colorScheme.secondaryContainer,
}),
), ),
onPressed: Get.back, onPressed: Get.back,
icon: Icon( icon: Icon(
@@ -60,25 +61,18 @@ class _WhisperDetailPageState
), ),
), ),
), ),
title: SizedBox( title: GestureDetector(
width: double.infinity,
height: 50,
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: () { onTap: () {
feedBack(); feedBack();
Get.toNamed( Get.toNamed(
'/member?mid=${_whisperDetailController.mid}', '/member?mid=${_whisperDetailController.mid}',
arguments: { arguments: {
'face': _whisperDetailController.face, 'face': _whisperDetailController.face,
'heroTag': null
}, },
); );
}, },
child: Row( child: Row(
children: <Widget>[ children: [
NetworkImgLayer( NetworkImgLayer(
width: 34, width: 34,
height: 34, height: 34,
@@ -86,22 +80,30 @@ class _WhisperDetailPageState
src: _whisperDetailController.face, src: _whisperDetailController.face,
), ),
const SizedBox(width: 6), const SizedBox(width: 6),
Text( Expanded(
child: Text(
_whisperDetailController.name, _whisperDetailController.name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.titleMedium, style: Theme.of(context).textTheme.titleMedium,
), ),
],
), ),
),
const SizedBox(width: 36, height: 36),
], ],
), ),
), ),
), ),
body: Column( body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [ children: [
Expanded(child: _buildList()), Expanded(
child: Listener(
child: Obx(() =>
_buildBody(_whisperDetailController.loadingState.value)),
onPointerDown: (event) {
// Hide panel when touch ListView.
hidePanel();
},
),
),
_buildInputView(), _buildInputView(),
buildPanelContainer(Theme.of(context).colorScheme.onInverseSurface), buildPanelContainer(Theme.of(context).colorScheme.onInverseSurface),
], ],
@@ -109,26 +111,25 @@ class _WhisperDetailPageState
); );
} }
Widget _buildList() { Widget _buildBody(LoadingState<List<MessageItem>?> loadingState) {
Widget resultWidget = Obx( return switch (loadingState) {
() { Loading() => loadingWidget,
List<MessageItem> messageList = _whisperDetailController.messageList; Success() => loadingState.response?.isNotEmpty == true
if (messageList.isEmpty) { ? refreshIndicator(
return const Center( onRefresh: () async {
child: CircularProgressIndicator(), await _whisperDetailController.onRefresh();
); },
}
return refreshIndicator(
onRefresh: _whisperDetailController.querySessionMsg,
child: ListView.builder( child: ListView.builder(
shrinkWrap: true, shrinkWrap: true,
reverse: true, reverse: true,
itemCount: messageList.length, itemCount: loadingState.response!.length,
padding: const EdgeInsets.only(bottom: 12),
itemBuilder: (context, int index) { itemBuilder: (context, int index) {
final item = loadingState.response![index];
return ChatItem( return ChatItem(
item: messageList[index], item: item,
eInfos: _whisperDetailController.eInfos, eInfos: _whisperDetailController.eInfos,
onLongPress: messageList[index].senderUid == onLongPress: item.senderUid ==
_whisperDetailController.ownerMid _whisperDetailController.ownerMid
? () { ? () {
showDialog( showDialog(
@@ -137,7 +138,7 @@ class _WhisperDetailPageState
return AlertDialog( return AlertDialog(
clipBehavior: Clip.hardEdge, clipBehavior: Clip.hardEdge,
contentPadding: contentPadding:
const EdgeInsets.fromLTRB(0, 12, 0, 12), const EdgeInsets.symmetric(vertical: 12),
content: Column( content: Column(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
@@ -145,15 +146,17 @@ class _WhisperDetailPageState
onTap: () { onTap: () {
Get.back(); Get.back();
_whisperDetailController.sendMsg( _whisperDetailController.sendMsg(
message: '${messageList[index].msgKey}', message: '${item.msgKey}',
onClearText: editController.clear, onClearText: editController.clear,
msgType: 5, msgType: 5,
index: index, index: index,
); );
}, },
dense: true, dense: true,
title: const Text('撤回', title: const Text(
style: TextStyle(fontSize: 14)), '撤回',
style: TextStyle(fontSize: 14),
),
), ),
// ListTile( // ListTile(
// onTap: () { // onTap: () {
@@ -172,19 +175,17 @@ class _WhisperDetailPageState
: null, : null,
); );
}, },
padding: const EdgeInsets.only(bottom: 20),
), ),
); )
}, : scrollErrorWidget(
); callback: _whisperDetailController.onReload,
resultWidget = Listener( ),
child: resultWidget, Error() => scrollErrorWidget(
onPointerDown: (event) { errMsg: loadingState.errMsg,
// Hide panel when touch ListView. callback: _whisperDetailController.onReload,
hidePanel(); ),
}, _ => throw UnimplementedError(),
); };
return resultWidget;
} }
Widget _buildInputView() { Widget _buildInputView() {

View File

@@ -1,6 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart'; import 'package:PiliPlus/common/widgets/interactiveviewer_gallery/interactiveviewer_gallery.dart';
import 'package:PiliPlus/models/msg/session.dart';
import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/id_utils.dart'; import 'package:PiliPlus/utils/id_utils.dart';
import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/page_utils.dart';
@@ -41,13 +42,13 @@ enum MsgType {
} }
class ChatItem extends StatelessWidget { class ChatItem extends StatelessWidget {
final dynamic item; final MessageItem item;
final List? eInfos; final List? eInfos;
final VoidCallback? onLongPress; final VoidCallback? onLongPress;
const ChatItem({ const ChatItem({
super.key, super.key,
this.item, required this.item,
this.eInfos, this.eInfos,
this.onLongPress, this.onLongPress,
}) : isOwner = onLongPress != null; }) : isOwner = onLongPress != null;
@@ -137,7 +138,7 @@ class ChatItem extends StatelessWidget {
} }
Widget messageContent(BuildContext context) { Widget messageContent(BuildContext context) {
switch (MsgType.parse(item.msgType)) { switch (MsgType.parse(item.msgType!)) {
case MsgType.notify_msg: case MsgType.notify_msg:
return SystemNotice(item: item); return SystemNotice(item: item);
case MsgType.pic_card: case MsgType.pic_card: