20 changed files with 2705 additions and 411 deletions
Unified View
Diff Options
-
65.vscode/launch.json
-
924lib/controller/message/chat_controller.dart
-
360lib/controller/message/conversation_controller.dart
-
2lib/controller/mine/edit_info_controller.dart
-
13lib/controller/setting/setting_controller.dart
-
325lib/im/im_manager.dart
-
2lib/network/home_api.g.dart
-
24lib/network/rtc_api.g.dart
-
64lib/network/user_api.g.dart
-
1lib/pages/home/content_card.dart
-
39lib/pages/home/user_information_page.dart
-
44lib/pages/message/chat_page.dart
-
8lib/pages/message/conversation_tab.dart
-
115lib/widget/message/chat_gift_item.dart
-
184lib/widget/message/chat_gift_popup.dart
-
6lib/widget/message/chat_input_bar.dart
-
293lib/widget/message/gift_item.dart
-
39lib/widget/message/message_item.dart
-
68location_plugin/example/pubspec.lock
-
540pubspec.lock
@ -0,0 +1,65 @@ |
|||||
|
{ |
||||
|
// 使用 IntelliSense 了解相关属性。 |
||||
|
// 悬停以查看现有属性的描述。 |
||||
|
// 欲了解更多信息,请访问: https://go.microsoft.com/fwlink/?linkid=830387 |
||||
|
"version": "0.2.0", |
||||
|
"configurations": [ |
||||
|
{ |
||||
|
"name": "dating_touchme_app", |
||||
|
"request": "launch", |
||||
|
"type": "dart" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "dating_touchme_app (profile mode)", |
||||
|
"request": "launch", |
||||
|
"type": "dart", |
||||
|
"flutterMode": "profile" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "dating_touchme_app (release mode)", |
||||
|
"request": "launch", |
||||
|
"type": "dart", |
||||
|
"flutterMode": "release" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "location_plugin", |
||||
|
"cwd": "location_plugin", |
||||
|
"request": "launch", |
||||
|
"type": "dart" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "location_plugin (profile mode)", |
||||
|
"cwd": "location_plugin", |
||||
|
"request": "launch", |
||||
|
"type": "dart", |
||||
|
"flutterMode": "profile" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "location_plugin (release mode)", |
||||
|
"cwd": "location_plugin", |
||||
|
"request": "launch", |
||||
|
"type": "dart", |
||||
|
"flutterMode": "release" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "example", |
||||
|
"cwd": "location_plugin/example", |
||||
|
"request": "launch", |
||||
|
"type": "dart" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "example (profile mode)", |
||||
|
"cwd": "location_plugin/example", |
||||
|
"request": "launch", |
||||
|
"type": "dart", |
||||
|
"flutterMode": "profile" |
||||
|
}, |
||||
|
{ |
||||
|
"name": "example (release mode)", |
||||
|
"cwd": "location_plugin/example", |
||||
|
"request": "launch", |
||||
|
"type": "dart", |
||||
|
"flutterMode": "release" |
||||
|
} |
||||
|
] |
||||
|
} |
||||
924
lib/controller/message/chat_controller.dart
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
@ -0,0 +1,115 @@ |
|||||
|
import 'package:cached_network_image/cached_network_image.dart'; |
||||
|
import 'package:dating_touchme_app/model/live/gift_product_model.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
|
||||
|
class ChatGiftItem extends StatelessWidget { |
||||
|
final GiftProductModel item; |
||||
|
final int active; |
||||
|
final int index; |
||||
|
final void Function(int) changeActive; |
||||
|
|
||||
|
const ChatGiftItem({ |
||||
|
super.key, |
||||
|
required this.item, |
||||
|
required this.active, |
||||
|
required this.index, |
||||
|
required this.changeActive, |
||||
|
}); |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
final isActive = active == index; |
||||
|
|
||||
|
return InkWell( |
||||
|
onTap: () { |
||||
|
changeActive(index); |
||||
|
}, |
||||
|
child: Container( |
||||
|
width: 83.w, |
||||
|
height: 94.w, |
||||
|
padding: EdgeInsets.only(top: 10.w), |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(9.w)), |
||||
|
color: Color.fromRGBO( |
||||
|
117, |
||||
|
98, |
||||
|
249, |
||||
|
isActive ? .2 : 0, |
||||
|
), |
||||
|
border: Border.all( |
||||
|
width: 1, |
||||
|
color: Color.fromRGBO( |
||||
|
117, |
||||
|
98, |
||||
|
249, |
||||
|
isActive ? 1 : 0, |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
child: Column( |
||||
|
children: [ |
||||
|
_buildImage(), |
||||
|
SizedBox(height: 7.w), |
||||
|
Text( |
||||
|
item.productTitle, |
||||
|
style: TextStyle( |
||||
|
fontSize: 11.w, |
||||
|
color: const Color.fromRGBO(51, 51, 51, 1), |
||||
|
), |
||||
|
maxLines: 1, |
||||
|
overflow: TextOverflow.ellipsis, |
||||
|
), |
||||
|
SizedBox(height: 1.w), |
||||
|
Text( |
||||
|
"${item.unitSellingPrice.toInt()}支", |
||||
|
style: TextStyle( |
||||
|
fontSize: 7.w, |
||||
|
color: const Color.fromRGBO(144, 144, 144, 1), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildImage() { |
||||
|
if (item.mainPic.isNotEmpty) { |
||||
|
return CachedNetworkImage( |
||||
|
imageUrl: item.mainPic, |
||||
|
width: 41.w, |
||||
|
height: 41.w, |
||||
|
fit: BoxFit.cover, |
||||
|
placeholder: (context, url) => Container( |
||||
|
width: 41.w, |
||||
|
height: 41.w, |
||||
|
color: Colors.grey[300], |
||||
|
child: Center( |
||||
|
child: SizedBox( |
||||
|
width: 20.w, |
||||
|
height: 20.w, |
||||
|
child: CircularProgressIndicator( |
||||
|
strokeWidth: 2, |
||||
|
color: Colors.grey[600], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
errorWidget: (context, url, error) => Container( |
||||
|
width: 41.w, |
||||
|
height: 41.w, |
||||
|
color: Colors.grey[300], |
||||
|
child: Icon(Icons.error_outline, size: 20.w, color: Colors.grey), |
||||
|
), |
||||
|
); |
||||
|
} else { |
||||
|
return Container( |
||||
|
width: 41.w, |
||||
|
height: 41.w, |
||||
|
color: Colors.grey[300], |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,184 @@ |
|||||
|
import 'package:dating_touchme_app/model/live/gift_product_model.dart'; |
||||
|
import 'package:dating_touchme_app/widget/message/chat_gift_item.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; |
||||
|
|
||||
|
class ChatGiftPopup extends StatefulWidget { |
||||
|
const ChatGiftPopup({ |
||||
|
super.key, |
||||
|
required this.activeGift, |
||||
|
required this.giftNum, |
||||
|
required this.giftList, |
||||
|
required this.changeActive, |
||||
|
required this.onSendGift, |
||||
|
}); |
||||
|
|
||||
|
final ValueNotifier<int?> activeGift; |
||||
|
final ValueNotifier<int> giftNum; |
||||
|
final List<GiftProductModel> giftList; |
||||
|
final void Function(int) changeActive; |
||||
|
final Future<void> Function(GiftProductModel, int) onSendGift; |
||||
|
|
||||
|
@override |
||||
|
State<ChatGiftPopup> createState() => _ChatGiftPopupState(); |
||||
|
} |
||||
|
|
||||
|
class _ChatGiftPopupState extends State<ChatGiftPopup> { |
||||
|
@override |
||||
|
void initState() { |
||||
|
super.initState(); |
||||
|
// 默认选择第一个礼物 |
||||
|
if (widget.giftList.isNotEmpty && widget.activeGift.value == null) { |
||||
|
widget.activeGift.value = 0; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
// 处理赠送礼物 |
||||
|
Future<void> _handleSendGift() async { |
||||
|
// 检查是否选中了礼物 |
||||
|
final activeIndex = widget.activeGift.value; |
||||
|
if (activeIndex == null || |
||||
|
activeIndex < 0 || |
||||
|
activeIndex >= widget.giftList.length) { |
||||
|
SmartDialog.showToast('请先选择礼物'); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
// 获取选中的礼物 |
||||
|
final gift = widget.giftList[activeIndex]; |
||||
|
final quantity = widget.giftNum.value; |
||||
|
|
||||
|
// 发送礼物 |
||||
|
await widget.onSendGift(gift, quantity); |
||||
|
SmartDialog.dismiss(); |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
return Material( |
||||
|
color: Colors.transparent, |
||||
|
child: Container( |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.vertical( |
||||
|
top: Radius.circular(9.w), |
||||
|
), |
||||
|
color: Colors.white, |
||||
|
), |
||||
|
height: 363.w, |
||||
|
child: Column( |
||||
|
children: [ |
||||
|
_buildTab(), |
||||
|
_buildGiftSwiper(), |
||||
|
_buildBottomBar(), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildTab() { |
||||
|
return Container( |
||||
|
height: 47.w, |
||||
|
padding: EdgeInsets.only(left: 29.w), |
||||
|
child: Row( |
||||
|
children: [ |
||||
|
Text( |
||||
|
"礼物", |
||||
|
style: TextStyle( |
||||
|
fontSize: 13.w, |
||||
|
color: const Color.fromRGBO(117, 98, 249, 1), |
||||
|
fontWeight: FontWeight.w700, |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildGiftSwiper() { |
||||
|
if (widget.giftList.isEmpty) { |
||||
|
return Expanded( |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
'暂无礼物', |
||||
|
style: TextStyle(fontSize: 14.w, color: Colors.grey), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
return Expanded( |
||||
|
child: ValueListenableBuilder<int?>( |
||||
|
valueListenable: widget.activeGift, |
||||
|
builder: (context, active, _) { |
||||
|
return GridView.builder( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 10.w, vertical: 10.w), |
||||
|
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( |
||||
|
crossAxisCount: 4, // 每行4个 |
||||
|
crossAxisSpacing: 7.w, |
||||
|
mainAxisSpacing: 7.w, |
||||
|
childAspectRatio: 0.85, // 调整宽高比 |
||||
|
), |
||||
|
itemCount: widget.giftList.length, |
||||
|
itemBuilder: (context, index) { |
||||
|
return ChatGiftItem( |
||||
|
item: widget.giftList[index], |
||||
|
active: active ?? 0, |
||||
|
index: index, |
||||
|
changeActive: widget.changeActive, |
||||
|
); |
||||
|
}, |
||||
|
); |
||||
|
}, |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
Widget _buildBottomBar() { |
||||
|
return Container( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 10.w), |
||||
|
child: Row( |
||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
||||
|
children: [ |
||||
|
// 数量选择(暂时不实现,固定为1) |
||||
|
SizedBox(width: 1.w), |
||||
|
ValueListenableBuilder<int>( |
||||
|
valueListenable: widget.giftNum, |
||||
|
builder: (context, num, _) { |
||||
|
return Row( |
||||
|
children: [ |
||||
|
GestureDetector( |
||||
|
onTap: () => _handleSendGift(), |
||||
|
child: Container( |
||||
|
width: 63.w, |
||||
|
height: 30.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.all(Radius.circular(30.w)), |
||||
|
gradient: const LinearGradient( |
||||
|
begin: Alignment.centerLeft, |
||||
|
end: Alignment.centerRight, |
||||
|
colors: [ |
||||
|
Color.fromRGBO(61, 138, 224, 1), |
||||
|
Color.fromRGBO(131, 89, 255, 1), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
child: Center( |
||||
|
child: Text( |
||||
|
"赠送", |
||||
|
style: TextStyle(fontSize: 13.w, color: Colors.white), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
}, |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
} |
||||
|
|
||||
@ -0,0 +1,293 @@ |
|||||
|
import 'dart:convert'; |
||||
|
import 'package:cached_network_image/cached_network_image.dart'; |
||||
|
import 'package:flutter/material.dart'; |
||||
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
||||
|
import 'package:im_flutter_sdk/im_flutter_sdk.dart'; |
||||
|
|
||||
|
import '../../generated/assets.dart'; |
||||
|
|
||||
|
class GiftItem extends StatelessWidget { |
||||
|
final EMMessage message; |
||||
|
final bool isSentByMe; |
||||
|
final bool showTime; |
||||
|
final String formattedTime; |
||||
|
final VoidCallback? onResend; |
||||
|
|
||||
|
const GiftItem({ |
||||
|
required this.message, |
||||
|
required this.isSentByMe, |
||||
|
required this.showTime, |
||||
|
required this.formattedTime, |
||||
|
this.onResend, |
||||
|
super.key, |
||||
|
}); |
||||
|
|
||||
|
/// 从消息内容中解析礼物信息(使用特殊的JSON格式) |
||||
|
Map<String, dynamic>? _parseGiftInfo() { |
||||
|
try { |
||||
|
if (message.body.type == MessageType.TXT) { |
||||
|
final textBody = message.body as EMTextMessageBody; |
||||
|
final content = textBody.content; |
||||
|
|
||||
|
// 检查是否是礼物消息(以 [GIFT:] 开头) |
||||
|
if (content.startsWith('[GIFT:]')) { |
||||
|
final jsonStr = content.substring(7); // 移除 '[GIFT:]' 前缀 |
||||
|
return jsonDecode(jsonStr) as Map<String, dynamic>; |
||||
|
} |
||||
|
} |
||||
|
} catch (e) { |
||||
|
print('解析礼物信息失败: $e'); |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
/// 获取礼物标题 |
||||
|
String _getGiftTitle() { |
||||
|
final giftInfo = _parseGiftInfo(); |
||||
|
if (giftInfo != null) { |
||||
|
return giftInfo['giftProductTitle']?.toString() ?? '礼物'; |
||||
|
} |
||||
|
return '礼物'; |
||||
|
} |
||||
|
|
||||
|
/// 获取礼物图片 |
||||
|
String _getGiftImage() { |
||||
|
final giftInfo = _parseGiftInfo(); |
||||
|
if (giftInfo != null) { |
||||
|
return giftInfo['giftMainPic']?.toString() ?? ''; |
||||
|
} |
||||
|
return ''; |
||||
|
} |
||||
|
|
||||
|
/// 获取礼物数量 |
||||
|
int _getGiftQuantity() { |
||||
|
final giftInfo = _parseGiftInfo(); |
||||
|
if (giftInfo != null) { |
||||
|
return giftInfo['quantity'] as int? ?? 1; |
||||
|
} |
||||
|
return 1; |
||||
|
} |
||||
|
|
||||
|
@override |
||||
|
Widget build(BuildContext context) { |
||||
|
final giftInfo = _parseGiftInfo(); |
||||
|
if (giftInfo == null) { |
||||
|
// 如果解析失败,不显示 |
||||
|
return SizedBox.shrink(); |
||||
|
} |
||||
|
|
||||
|
final giftTitle = _getGiftTitle(); |
||||
|
final giftImage = _getGiftImage(); |
||||
|
final quantity = _getGiftQuantity(); |
||||
|
|
||||
|
return Column( |
||||
|
children: [ |
||||
|
// 显示时间 |
||||
|
if (showTime) _buildTimeLabel(), |
||||
|
Container( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 16.w, vertical: 8.h), |
||||
|
child: Row( |
||||
|
mainAxisAlignment: |
||||
|
isSentByMe ? MainAxisAlignment.end : MainAxisAlignment.start, |
||||
|
crossAxisAlignment: CrossAxisAlignment.center, |
||||
|
children: [ |
||||
|
if (!isSentByMe) _buildAvatar(), |
||||
|
if (!isSentByMe) SizedBox(width: 8.w), |
||||
|
// 发送消息时,状态在左侧 |
||||
|
if (isSentByMe) |
||||
|
Align( |
||||
|
alignment: Alignment.center, |
||||
|
child: Container( |
||||
|
margin: EdgeInsets.only(top: 10.h), |
||||
|
child: _buildMessageStatus(), |
||||
|
), |
||||
|
), |
||||
|
if (isSentByMe) SizedBox(width: 10.w), |
||||
|
// 礼物消息容器 |
||||
|
Container( |
||||
|
constraints: BoxConstraints(maxWidth: 200.w), |
||||
|
margin: EdgeInsets.only(top: 10.h), |
||||
|
padding: EdgeInsets.all(12.w), |
||||
|
decoration: BoxDecoration( |
||||
|
color: isSentByMe ? Color(0xff8E7BF6) : Colors.white, |
||||
|
borderRadius: BorderRadius.only( |
||||
|
topLeft: |
||||
|
isSentByMe ? Radius.circular(12.w) : Radius.circular(0), |
||||
|
topRight: |
||||
|
isSentByMe ? Radius.circular(0) : Radius.circular(12.w), |
||||
|
bottomLeft: Radius.circular(12.w), |
||||
|
bottomRight: Radius.circular(12.w), |
||||
|
), |
||||
|
), |
||||
|
child: Row( |
||||
|
mainAxisSize: MainAxisSize.min, |
||||
|
children: [ |
||||
|
// 礼物图片 |
||||
|
if (giftImage.isNotEmpty) |
||||
|
Container( |
||||
|
width: 40.w, |
||||
|
height: 40.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.circular(8.w), |
||||
|
color: Colors.grey[200], |
||||
|
), |
||||
|
child: ClipRRect( |
||||
|
borderRadius: BorderRadius.circular(8.w), |
||||
|
child: CachedNetworkImage( |
||||
|
imageUrl: giftImage, |
||||
|
fit: BoxFit.cover, |
||||
|
placeholder: (context, url) => Container( |
||||
|
color: Colors.grey[200], |
||||
|
child: Center( |
||||
|
child: SizedBox( |
||||
|
width: 20.w, |
||||
|
height: 20.w, |
||||
|
child: CircularProgressIndicator( |
||||
|
strokeWidth: 2, |
||||
|
color: Colors.grey[600], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
errorWidget: (context, url, error) => Container( |
||||
|
color: Colors.grey[200], |
||||
|
child: Icon( |
||||
|
Icons.card_giftcard, |
||||
|
size: 20.w, |
||||
|
color: Colors.grey[400], |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
), |
||||
|
) |
||||
|
else |
||||
|
Container( |
||||
|
width: 40.w, |
||||
|
height: 40.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.circular(8.w), |
||||
|
color: Colors.grey[200], |
||||
|
), |
||||
|
child: Icon( |
||||
|
Icons.card_giftcard, |
||||
|
size: 20.w, |
||||
|
color: Colors.grey[400], |
||||
|
), |
||||
|
), |
||||
|
SizedBox(width: 8.w), |
||||
|
// 礼物信息 |
||||
|
Flexible( |
||||
|
child: Column( |
||||
|
crossAxisAlignment: CrossAxisAlignment.start, |
||||
|
mainAxisSize: MainAxisSize.min, |
||||
|
children: [ |
||||
|
Text( |
||||
|
giftTitle, |
||||
|
style: TextStyle( |
||||
|
fontSize: 14.sp, |
||||
|
color: isSentByMe ? Colors.white : Colors.black87, |
||||
|
fontWeight: FontWeight.w500, |
||||
|
), |
||||
|
maxLines: 1, |
||||
|
overflow: TextOverflow.ellipsis, |
||||
|
), |
||||
|
if (quantity > 1) ...[ |
||||
|
SizedBox(height: 2.h), |
||||
|
Text( |
||||
|
'x$quantity', |
||||
|
style: TextStyle( |
||||
|
fontSize: 12.sp, |
||||
|
color: isSentByMe |
||||
|
? Colors.white70 |
||||
|
: Colors.grey[600], |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
if (isSentByMe) SizedBox(width: 8.w), |
||||
|
if (isSentByMe) _buildAvatar(), |
||||
|
], |
||||
|
), |
||||
|
), |
||||
|
], |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
// 构建时间标签 |
||||
|
Widget _buildTimeLabel() { |
||||
|
return Container( |
||||
|
alignment: Alignment.center, |
||||
|
padding: EdgeInsets.symmetric(horizontal: 16.w), |
||||
|
child: Container( |
||||
|
padding: EdgeInsets.symmetric(horizontal: 12.w), |
||||
|
child: Text( |
||||
|
formattedTime, |
||||
|
style: TextStyle(fontSize: 12.sp, color: Colors.grey), |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
// 构建头像 |
||||
|
Widget _buildAvatar() { |
||||
|
return Container( |
||||
|
width: 40.w, |
||||
|
height: 40.w, |
||||
|
decoration: BoxDecoration( |
||||
|
borderRadius: BorderRadius.circular(20.w), |
||||
|
image: DecorationImage( |
||||
|
image: AssetImage(Assets.imagesAvatarsExample), |
||||
|
fit: BoxFit.cover, |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} |
||||
|
|
||||
|
// 构建消息状态(发送中、已发送、失败重发) |
||||
|
Widget _buildMessageStatus() { |
||||
|
if (!isSentByMe) { |
||||
|
return SizedBox.shrink(); |
||||
|
} |
||||
|
|
||||
|
final status = message.status; |
||||
|
|
||||
|
if (status == MessageStatus.FAIL) { |
||||
|
// 发送失败,显示重发按钮 |
||||
|
return GestureDetector( |
||||
|
onTap: onResend, |
||||
|
child: Container( |
||||
|
width: 20.w, |
||||
|
height: 20.w, |
||||
|
decoration: BoxDecoration( |
||||
|
color: Colors.red.withOpacity(0.1), |
||||
|
shape: BoxShape.circle, |
||||
|
), |
||||
|
child: Icon( |
||||
|
Icons.refresh, |
||||
|
size: 14.w, |
||||
|
color: Colors.red, |
||||
|
), |
||||
|
), |
||||
|
); |
||||
|
} else if (status == MessageStatus.PROGRESS) { |
||||
|
// 发送中,显示加载动画 |
||||
|
return Container( |
||||
|
width: 16.w, |
||||
|
height: 16.w, |
||||
|
child: CircularProgressIndicator( |
||||
|
strokeWidth: 2, |
||||
|
valueColor: AlwaysStoppedAnimation<Color>(Colors.grey), |
||||
|
), |
||||
|
); |
||||
|
} else { |
||||
|
// 发送成功,不显示任何状态 |
||||
|
return SizedBox.shrink(); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
540
pubspec.lock
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save