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({
int? talkerId,
}) async {
static Future<LoadingState<SessionMsgDataModel>> sessionMsg(
{int? talkerId}) async {
Map params = await WbiSign.makSign({
'talker_id': talkerId,
'session_type': 1,
@@ -469,15 +468,13 @@ class MsgHttp {
var res = await Request().get(Api.sessionMsg, queryParameters: params);
if (res.data['code'] == 0) {
try {
return {
'status': true,
'data': SessionMsgDataModel.fromJson(res.data['data']),
};
return LoadingState.success(
SessionMsgDataModel.fromJson(res.data['data']));
} catch (err) {
debugPrint(err.toString());
return LoadingState.error(err.toString());
}
} 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
extends CommonListController<List<SessionList>?, SessionList> {
late final bool disableLikeMsg;
late final List msgFeedTopItems;
late final RxList<int> unreadCounts;
@@ -22,7 +21,7 @@ class WhisperController
@override
void onInit() {
super.onInit();
disableLikeMsg =
final disableLikeMsg =
GStorage.setting.get(SettingBoxKey.disableLikeMsg, defaultValue: false);
msgFeedTopItems = [
{

View File

@@ -1,5 +1,7 @@
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_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
@@ -8,12 +10,15 @@ import 'package:PiliPlus/models/msg/session.dart';
import '../../utils/feed_back.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 String name;
late String face;
String? mid;
RxList<MessageItem> messageList = <MessageItem>[].obs;
//表情转换图片规则
List<dynamic>? eInfos;
@@ -25,48 +30,41 @@ class WhisperDetailController extends GetxController {
face = Get.parameters['face']!;
mid = Get.parameters['mid'];
querySessionMsg();
queryData();
}
Future querySessionMsg() async {
var res = await MsgHttp.sessionMsg(talkerId: talkerId);
if (res['status']) {
messageList.value = res['data'].messages;
if (messageList.isNotEmpty) {
if (messageList.length == 1 &&
messageList.last.msgType == 18 &&
messageList.last.msgSource == 18) {
// debugPrint(messageList.last);
// debugPrint(messageList.last.content);
//{content: [{"text":"对方主动回复或关注你前最多发送1条消息","color_day":"#9499A0","color_nig":"#9499A0"}]}
} else {
ackSessionMsg();
}
if (res['data'].eInfos != null) {
eInfos = res['data'].eInfos;
}
@override
bool customHandleResponse(
bool isRefresh, Success<SessionMsgDataModel> response) {
List<MessageItem>? messageList = response.response.messages;
if (messageList?.isNotEmpty == true) {
if (messageList!.length == 1 &&
messageList.last.msgType == 18 &&
messageList.last.msgSource == 18) {
// debugPrint(messageList.last);
// debugPrint(messageList.last.content);
//{content: [{"text":"对方主动回复或关注你前最多发送1条消息","color_day":"#9499A0","color_nig":"#9499A0"}]}
} else {
ackSessionMsg(messageList.last.msgSeqno);
}
if (response.response.eInfos != null) {
eInfos = response.response.eInfos;
}
} else {
SmartDialog.showToast(res['msg']);
}
return false;
}
// 消息标记已读
Future ackSessionMsg() async {
if (messageList.isEmpty) {
return;
}
Future ackSessionMsg(int? msgSeqno) async {
var res = await MsgHttp.ackSessionMsg(
talkerId: talkerId,
ackSeqno: messageList.last.msgSeqno,
ackSeqno: msgSeqno,
);
if (!res['status']) {
SmartDialog.showToast(res['msg']);
}
}
late final ownerMid = Accounts.main.mid;
Future sendMsg({
required String message,
dynamic picMsg,
@@ -80,16 +78,16 @@ class WhisperDetailController extends GetxController {
SmartDialog.showToast('请先登录');
return;
}
if (picMsg == null && message == '') {
SmartDialog.dismiss();
SmartDialog.showToast('请输入内容');
return;
}
if (mid == null) {
SmartDialog.dismiss();
SmartDialog.showToast('这里不能发');
return;
}
if (picMsg == null && message == '') {
SmartDialog.dismiss();
SmartDialog.showToast('请输入内容');
return;
}
var result = await MsgHttp.sendMsg(
senderUid: ownerMid,
receiverId: int.parse(mid!),
@@ -99,13 +97,13 @@ class WhisperDetailController extends GetxController {
);
SmartDialog.dismiss();
if (result['status']) {
// debugPrint(result['data']);
if (msgType == 5) {
messageList[index!].msgStatus = 1;
messageList.refresh();
List<MessageItem> list = (loadingState.value as Success).response;
list[index!].msgStatus = 1;
loadingState.refresh();
SmartDialog.showToast('撤回成功');
} else {
querySessionMsg();
queryData();
onClearText();
SmartDialog.showToast('发送成功');
}
@@ -113,4 +111,13 @@ class WhisperDetailController extends GetxController {
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 'package:PiliPlus/common/widgets/loading_widget.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/models/msg/session.dart';
import 'package:PiliPlus/pages/common/common_publish_page.dart';
@@ -45,11 +47,10 @@ class _WhisperDetailPageState
height: 34,
child: IconButton(
tooltip: '返回',
style: ButtonStyle(
padding: WidgetStateProperty.all(EdgeInsets.zero),
backgroundColor: WidgetStateProperty.resolveWith((states) {
return Theme.of(context).colorScheme.secondaryContainer;
}),
style: IconButton.styleFrom(
padding: EdgeInsets.zero,
backgroundColor:
Theme.of(context).colorScheme.secondaryContainer,
),
onPressed: Get.back,
icon: Icon(
@@ -60,48 +61,49 @@ class _WhisperDetailPageState
),
),
),
title: SizedBox(
width: double.infinity,
height: 50,
title: GestureDetector(
onTap: () {
feedBack();
Get.toNamed(
'/member?mid=${_whisperDetailController.mid}',
arguments: {
'face': _whisperDetailController.face,
},
);
},
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
GestureDetector(
onTap: () {
feedBack();
Get.toNamed(
'/member?mid=${_whisperDetailController.mid}',
arguments: {
'face': _whisperDetailController.face,
'heroTag': null
},
);
},
child: Row(
children: <Widget>[
NetworkImgLayer(
width: 34,
height: 34,
type: 'avatar',
src: _whisperDetailController.face,
),
const SizedBox(width: 6),
Text(
_whisperDetailController.name,
style: Theme.of(context).textTheme.titleMedium,
),
],
NetworkImgLayer(
width: 34,
height: 34,
type: 'avatar',
src: _whisperDetailController.face,
),
const SizedBox(width: 6),
Expanded(
child: Text(
_whisperDetailController.name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.titleMedium,
),
),
const SizedBox(width: 36, height: 36),
],
),
),
),
body: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Expanded(child: _buildList()),
Expanded(
child: Listener(
child: Obx(() =>
_buildBody(_whisperDetailController.loadingState.value)),
onPointerDown: (event) {
// Hide panel when touch ListView.
hidePanel();
},
),
),
_buildInputView(),
buildPanelContainer(Theme.of(context).colorScheme.onInverseSurface),
],
@@ -109,82 +111,81 @@ class _WhisperDetailPageState
);
}
Widget _buildList() {
Widget resultWidget = Obx(
() {
List<MessageItem> messageList = _whisperDetailController.messageList;
if (messageList.isEmpty) {
return const Center(
child: CircularProgressIndicator(),
);
}
return refreshIndicator(
onRefresh: _whisperDetailController.querySessionMsg,
child: ListView.builder(
shrinkWrap: true,
reverse: true,
itemCount: messageList.length,
itemBuilder: (context, int index) {
return ChatItem(
item: messageList[index],
eInfos: _whisperDetailController.eInfos,
onLongPress: messageList[index].senderUid ==
_whisperDetailController.ownerMid
? () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
clipBehavior: Clip.hardEdge,
contentPadding:
const EdgeInsets.fromLTRB(0, 12, 0, 12),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
onTap: () {
Get.back();
_whisperDetailController.sendMsg(
message: '${messageList[index].msgKey}',
onClearText: editController.clear,
msgType: 5,
index: index,
);
},
dense: true,
title: const Text('撤回',
style: TextStyle(fontSize: 14)),
Widget _buildBody(LoadingState<List<MessageItem>?> loadingState) {
return switch (loadingState) {
Loading() => loadingWidget,
Success() => loadingState.response?.isNotEmpty == true
? refreshIndicator(
onRefresh: () async {
await _whisperDetailController.onRefresh();
},
child: ListView.builder(
shrinkWrap: true,
reverse: true,
itemCount: loadingState.response!.length,
padding: const EdgeInsets.only(bottom: 12),
itemBuilder: (context, int index) {
final item = loadingState.response![index];
return ChatItem(
item: item,
eInfos: _whisperDetailController.eInfos,
onLongPress: item.senderUid ==
_whisperDetailController.ownerMid
? () {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
clipBehavior: Clip.hardEdge,
contentPadding:
const EdgeInsets.symmetric(vertical: 12),
content: Column(
mainAxisSize: MainAxisSize.min,
children: [
ListTile(
onTap: () {
Get.back();
_whisperDetailController.sendMsg(
message: '${item.msgKey}',
onClearText: editController.clear,
msgType: 5,
index: index,
);
},
dense: true,
title: const Text(
'撤回',
style: TextStyle(fontSize: 14),
),
),
// ListTile(
// onTap: () {
// Get.back();
// },
// dense: true,
// title: const Text('删除',
// style: TextStyle(fontSize: 14)),
// ),
],
),
// ListTile(
// onTap: () {
// Get.back();
// },
// dense: true,
// title: const Text('删除',
// style: TextStyle(fontSize: 14)),
// ),
],
),
);
},
);
},
);
}
: null,
);
},
padding: const EdgeInsets.only(bottom: 20),
),
);
},
);
resultWidget = Listener(
child: resultWidget,
onPointerDown: (event) {
// Hide panel when touch ListView.
hidePanel();
},
);
return resultWidget;
}
: null,
);
},
),
)
: scrollErrorWidget(
callback: _whisperDetailController.onReload,
),
Error() => scrollErrorWidget(
errMsg: loadingState.errMsg,
callback: _whisperDetailController.onReload,
),
_ => throw UnimplementedError(),
};
}
Widget _buildInputView() {

View File

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