初始化
This commit is contained in:
@@ -0,0 +1,136 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgdj/tools_base/debug_log.dart';
|
||||
import 'package:hgdj/tools_base/global_store/store.dart';
|
||||
import 'package:hgdj/tools_base/toast.dart';
|
||||
import 'package:pull_to_refresh/pull_to_refresh.dart';
|
||||
|
||||
import '../../../../hj_utils/api_service/group_service.dart';
|
||||
import '../../../../tools_base/file_upload/file_upload_tool.dart';
|
||||
import '../../../../tools_base/file_upload/upload_result_model.dart';
|
||||
import '../../../comment/comment_input_view.dart';
|
||||
import '../model/im_group_list_model.dart';
|
||||
import '../model/im_message_resp.dart';
|
||||
|
||||
class GroupChatDetailLogic extends GetxController {
|
||||
final IMGroupItemModel model;
|
||||
|
||||
GroupChatDetailLogic(this.model);
|
||||
|
||||
int pageNum = 1;
|
||||
List<IMMessageModel>? msgList;
|
||||
RefreshController? refreshController;
|
||||
TextEditingController textEditController = TextEditingController();
|
||||
Rx<String?> selectedImagePath = Rx<String?>(null);
|
||||
RxBool isSendingMsg = false.obs;
|
||||
|
||||
@override
|
||||
void onReady() {
|
||||
refreshData();
|
||||
super.onReady();
|
||||
}
|
||||
|
||||
void refreshData() {
|
||||
_loadData();
|
||||
}
|
||||
|
||||
void loadMoreData() {
|
||||
_loadData(page: pageNum + 1);
|
||||
}
|
||||
|
||||
void _loadData({int page = 1, int size = 20}) async {
|
||||
try {
|
||||
final retResp = await GroupService.getMessages(model.groupId, page, size);
|
||||
pageNum = page;
|
||||
msgList ??= [];
|
||||
if (pageNum == 1) {
|
||||
msgList?.clear();
|
||||
}
|
||||
msgList?.addAll(retResp.list ?? []);
|
||||
retResp.hasNext == true
|
||||
? refreshController?.loadComplete()
|
||||
: refreshController?.loadNoData();
|
||||
} catch (e) {
|
||||
debugLog(e);
|
||||
refreshController?.loadComplete();
|
||||
}
|
||||
refreshController?.refreshCompleted();
|
||||
update();
|
||||
}
|
||||
|
||||
Future readySendMsg({bool? isSend}) async {
|
||||
if (isSend == true &&
|
||||
(textEditController.text.isNotEmpty ||
|
||||
selectedImagePath.value?.isNotEmpty == true)) {
|
||||
// 点击发送按钮有内容,直接发送内容, 否则弹出输入框
|
||||
sendMsgEvent();
|
||||
} else {
|
||||
final result = await Get.bottomSheet(
|
||||
CommentInputView(
|
||||
hint: "请输入消息",
|
||||
textCtr: textEditController,
|
||||
imgPath: selectedImagePath.value,
|
||||
onImgChange: (value) => selectedImagePath.value = value,
|
||||
),
|
||||
backgroundColor: Colors.transparent,
|
||||
barrierColor: Colors.transparent,
|
||||
enableDrag: false,
|
||||
settings: RouteSettings(name: CommentInputView.routeName),
|
||||
useRootNavigator: true,
|
||||
);
|
||||
if (result == true) {
|
||||
update();
|
||||
}
|
||||
sendMsgEvent();
|
||||
}
|
||||
}
|
||||
|
||||
Future sendMsgEvent() async {
|
||||
if (textEditController.text.isEmpty &&
|
||||
selectedImagePath.value?.isNotEmpty != true) {
|
||||
showToast("请输入消息内容");
|
||||
return;
|
||||
}
|
||||
if (isSendingMsg.value) return;
|
||||
isSendingMsg.value = true;
|
||||
String? sendImagePath;
|
||||
if (selectedImagePath.value?.isNotEmpty == true) {
|
||||
try {
|
||||
ImageUploadResultModel? imgResult =
|
||||
await FileUploadTool().uploadImage(selectedImagePath.value!);
|
||||
sendImagePath = imgResult?.coverImg ?? "";
|
||||
if (sendImagePath.isEmpty) {
|
||||
isSendingMsg.value = false;
|
||||
showToast("图片上传失败!");
|
||||
return;
|
||||
}
|
||||
} catch (e) {
|
||||
debugLog(e);
|
||||
isSendingMsg.value = false;
|
||||
showToast("图片上传失败!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
try {
|
||||
var ret = await GroupService.sendMessage(
|
||||
model.groupId, textEditController.text, sendImagePath);
|
||||
if (ret.isSuccess) {
|
||||
textEditController.text = "";
|
||||
selectedImagePath.value = null;
|
||||
showToast("消息已发送");
|
||||
if (ret.data is Map && (ret.data['message'] is Map)) {
|
||||
IMMessageModel sendModel =
|
||||
IMMessageModel.fromJson(ret.data['message']);
|
||||
sendModel.portrait = globalStore.meInfo?.portrait;
|
||||
sendModel.name = globalStore.meInfo?.name;
|
||||
msgList?.insert(0, sendModel);
|
||||
update();
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
showToast("消息发送失败!");
|
||||
debugLog(e);
|
||||
}
|
||||
isSendingMsg.value = false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:hgdj/hj_page/comment/widget/comment_foot_view.dart';
|
||||
|
||||
import 'package:hgdj/tools_base/refresh/pull_refresh.dart';
|
||||
|
||||
import '../model/im_group_list_model.dart';
|
||||
import 'soul_group_detail_logic.dart';
|
||||
import 'widget/chat_item_cell.dart';
|
||||
|
||||
class GroupChatDetailPage extends StatelessWidget {
|
||||
final IMGroupItemModel model;
|
||||
|
||||
const GroupChatDetailPage(this.model, {super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GetBuilder<GroupChatDetailLogic>(
|
||||
global: false,
|
||||
init: GroupChatDetailLogic(model),
|
||||
builder: (logic) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(model.name ?? ""),
|
||||
),
|
||||
body: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: pullYsRefresh(
|
||||
onInit: (ctr) => logic.refreshController = ctr,
|
||||
onRefresh: (ctr) => logic.refreshData(),
|
||||
onLoading: (ctr) => logic.loadMoreData(),
|
||||
child: ListView.builder(
|
||||
itemCount: logic.msgList?.length ?? 0,
|
||||
reverse: true,
|
||||
padding: EdgeInsets.only(bottom: 12, top: 12),
|
||||
itemBuilder: (context, index) {
|
||||
return ChatItemCell(model: logic.msgList![index]);
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
Obx(
|
||||
() => CommentFootView(
|
||||
imgPath: logic.selectedImagePath.value,
|
||||
isSending: logic.isSendingMsg.value,
|
||||
onImgChange: (value) => logic.selectedImagePath.value = value,
|
||||
onComment: (isSend) => logic.readySendMsg(isSend: isSend),
|
||||
textCtr: logic.textEditController,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,276 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hgdj/assets_tool/app_colors.dart';
|
||||
import 'package:hgdj/routers/jump_router.dart';
|
||||
import 'package:hgdj/tools_base/widget/net_image_widget.dart';
|
||||
|
||||
import '../../../../../tools_base/global_store/store.dart';
|
||||
import 'package:hgdj/tools_base/widget/image_browser_page.dart';
|
||||
import '../../model/im_message_resp.dart';
|
||||
|
||||
class ChatItemCell extends StatefulWidget {
|
||||
final IMMessageModel? model;
|
||||
|
||||
ChatItemCell({super.key, this.model});
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
return _ChatItemCellState();
|
||||
}
|
||||
}
|
||||
|
||||
class _ChatItemCellState extends State<ChatItemCell> {
|
||||
bool get isImg => widget.model?.image?.isNotEmpty == true;
|
||||
|
||||
bool get isMe => globalStore.isMe(widget.model?.uid);
|
||||
|
||||
double imageWidth = 173;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
}
|
||||
|
||||
void _showImageScan(String imageUrl) {
|
||||
if (imageUrl.isNotEmpty) {
|
||||
ImageBrowserPage.open([widget.model?.image ?? '']);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (isMe) {
|
||||
return _buildRightStyle();
|
||||
} else {
|
||||
return _buildLeftStyle();
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildLeftStyle() {
|
||||
return Container(
|
||||
padding: EdgeInsets.fromLTRB(0, 12, 0, 6),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildTime(),
|
||||
Container(
|
||||
padding: EdgeInsets.fromLTRB(16, 0, 50, 0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
pushToPersonCenter(widget.model?.uid);
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 40,
|
||||
height: 40,
|
||||
child: NetworkImageLoader(
|
||||
imageUrl: widget.model?.portrait ?? "",
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
Flexible(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
widget.model?.name ?? "",
|
||||
style: TextStyle(
|
||||
color: Colors.white.withValues(alpha: 0.9),
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
if (widget.model?.content?.isNotEmpty == true)
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 20, vertical: 10),
|
||||
margin: EdgeInsets.only(top: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withValues(alpha: 0.05),
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(12),
|
||||
bottomRight: Radius.circular(12),
|
||||
topRight: Radius.circular(12),
|
||||
topLeft: Radius.circular(2)),
|
||||
),
|
||||
child: Text(
|
||||
widget.model?.content ?? "",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isImg)
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () {
|
||||
_showImageScan(widget.model?.image ?? "");
|
||||
},
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(top: 5),
|
||||
alignment: Alignment.centerLeft,
|
||||
constraints: BoxConstraints(maxWidth: 173),
|
||||
child: _buildImageWidget(isLeft: true),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildRightStyle() {
|
||||
return Container(
|
||||
padding: EdgeInsets.fromLTRB(0, 12, 0, 6),
|
||||
child: Column(
|
||||
children: [
|
||||
_buildTime(),
|
||||
Container(
|
||||
padding: EdgeInsets.fromLTRB(50, 0, 16, 0),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
Flexible(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.end,
|
||||
children: [
|
||||
Text(
|
||||
widget.model?.name ?? "",
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
SizedBox(height: 10),
|
||||
if (widget.model?.content?.isNotEmpty == true)
|
||||
Container(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: 20, vertical: 10),
|
||||
margin: EdgeInsets.only(top: 5),
|
||||
decoration: BoxDecoration(
|
||||
color: Color(0xff1DC194),
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(12),
|
||||
bottomRight: Radius.circular(12),
|
||||
topLeft: Radius.circular(12),
|
||||
topRight: Radius.circular(4)),
|
||||
),
|
||||
child: Text(
|
||||
widget.model?.content ?? "",
|
||||
style: TextStyle(
|
||||
color: Color(0xff141414),
|
||||
fontSize: 14,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (isImg)
|
||||
InkWell(
|
||||
enableFeedback: false,
|
||||
onTap: () {
|
||||
_showImageScan(widget.model?.image ?? "");
|
||||
},
|
||||
child: Container(
|
||||
margin: EdgeInsets.only(top: 5),
|
||||
alignment: Alignment.centerRight,
|
||||
constraints: BoxConstraints(maxWidth: 173),
|
||||
child: _buildImageWidget(isLeft: false),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(width: 12),
|
||||
GestureDetector(
|
||||
onTap: () {},
|
||||
child: SizedBox(
|
||||
width: 40,
|
||||
height: 40,
|
||||
child: NetworkImageLoader(
|
||||
imageUrl: widget.model?.portrait,
|
||||
width: 40,
|
||||
height: 40,
|
||||
borderRadius: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildImageWidget({bool isLeft = false}) {
|
||||
return Stack(
|
||||
children: [
|
||||
NetworkImageLoader(
|
||||
imageUrl: widget.model?.image ?? "",
|
||||
width: imageWidth,
|
||||
imgBorderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(12),
|
||||
bottomRight: Radius.circular(12),
|
||||
topRight: Radius.circular(isLeft ? 12 : 0),
|
||||
topLeft: Radius.circular(isLeft ? 0 : 12),
|
||||
),
|
||||
),
|
||||
if (isLeft)
|
||||
Positioned(
|
||||
bottom: 12,
|
||||
left: 0,
|
||||
right: 0,
|
||||
child: Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
child: Container(
|
||||
width: 72,
|
||||
height: 26,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(30),
|
||||
color: AppColors.actionRed,
|
||||
),
|
||||
child: Text(
|
||||
'查看原图',
|
||||
style: TextStyle(fontSize: 12, color: Colors.white),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildTime() {
|
||||
// if (widget.model?.isShowTime == true) {
|
||||
// return Container(
|
||||
// margin: EdgeInsets.fromLTRB(0, 12, 0, 12),
|
||||
// padding: EdgeInsets.symmetric(horizontal: 20, vertical: 2),
|
||||
// // decoration: BoxDecoration(
|
||||
// // borderRadius: BorderRadius.circular(30),
|
||||
// // color: Color(0xfff7f7f7).withValues(alpha: 0.42),
|
||||
// // ),
|
||||
// child: Text(
|
||||
// widget.model?.createAtDesc ?? "",
|
||||
// style: TextStyle(
|
||||
// color: Color(0xff666666),
|
||||
// fontSize: 12,
|
||||
// ),
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
return SizedBox();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user