You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1284 lines
44 KiB
1284 lines
44 KiB
import 'dart:convert'; |
|
import 'dart:io'; |
|
import 'dart:ui'; |
|
|
|
import 'package:dio/dio.dart'; |
|
import 'package:emoji_picker_flutter/emoji_picker_flutter.dart'; |
|
import 'package:flutter/gestures.dart'; |
|
import 'package:flutter/material.dart'; |
|
import 'package:flutter/rendering.dart'; |
|
import 'package:flutter/services.dart'; |
|
import 'package:flutter_screenutil/flutter_screenutil.dart'; |
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; |
|
import 'package:huixiang/im/database/message.dart'; |
|
import 'package:huixiang/main.dart'; |
|
import 'package:huixiang/retrofit/data/im_user.dart'; |
|
import 'package:huixiang/retrofit/retrofit_api.dart'; |
|
import 'package:huixiang/view_widget/classic_header.dart'; |
|
import 'package:huixiang/view_widget/my_appbar.dart'; |
|
import 'package:flutter/cupertino.dart'; |
|
import 'package:huixiang/view_widget/my_footer.dart'; |
|
import 'package:image_pickers/image_pickers.dart'; |
|
import 'package:pull_to_refresh/pull_to_refresh.dart'; |
|
import 'package:shared_preferences/shared_preferences.dart'; |
|
import '../../community/release_dynamic.dart'; |
|
import '../../generated/l10n.dart'; |
|
import '../../utils/font_weight.dart'; |
|
import '../retrofit/data/base_data.dart'; |
|
import '../retrofit/data/user_info.dart'; |
|
import '../utils/flutter_utils.dart'; |
|
import '../view_widget/custom_image.dart'; |
|
import 'im_view/on_chat_message.dart'; |
|
import 'im_view/on_chat_msg_instance.dart'; |
|
|
|
class ChatDetailsPage extends StatefulWidget { |
|
final Map<String, dynamic> arguments; |
|
|
|
ChatDetailsPage({this.arguments}); |
|
|
|
@override |
|
State<StatefulWidget> createState() { |
|
return _ChatDetailsPage(); |
|
} |
|
} |
|
|
|
class _ChatDetailsPage extends State<ChatDetailsPage> |
|
with WidgetsBindingObserver |
|
implements OnChatMessage { |
|
ApiService apiService; |
|
List<Medias> mediaPaths = []; |
|
int selectCount = 9; |
|
int dynamicType = 0; |
|
final TextEditingController chatController = TextEditingController(); |
|
bool emojiShowing = false; |
|
double keyboard = -1; |
|
bool needShowSmiley = false; |
|
bool needHideSmiley = false; |
|
bool isKeyBoardShow = false; |
|
bool moreShow = false; |
|
bool needShowMore = false; |
|
bool needHideMore = false; |
|
var commentFocus = FocusNode(); |
|
String hintText = "输入消息内容..."; |
|
UserInfo userInfo; |
|
final OnChatMessage _tempOnChatMessage = |
|
OnChatMsgInstance.instance.onChatMessage; |
|
final ScrollController scrollController = ScrollController(); |
|
String tex = ""; |
|
int copyIndex = 0; |
|
String selfUserId = ""; |
|
ImUser _toUser; |
|
String conversation; |
|
|
|
@override |
|
void onMessage(txt) { |
|
// SmartDialog.showToast("聊天 $txt", alignment: Alignment.center); |
|
} |
|
|
|
RefreshController refreshController = RefreshController(); |
|
List<Message> messages = []; |
|
int page = 0; |
|
|
|
loadMessageList() async { |
|
selfUserId = (await SharedPreferences.getInstance()).getString("userId"); |
|
conversation = conversationId(selfUserId, _toUser.mid); |
|
|
|
ImUser imUser = await hxDatabase.queryImUserById(conversation); |
|
if (imUser == null) { |
|
await hxDatabase.insertOrUpdateImUser(_toUser.toJson()); |
|
} |
|
|
|
// unread msg 2 read state |
|
await hxDatabase.readMessage(conversation); |
|
await refresh(); |
|
|
|
socketClient.addCallback(_toUser.mid, (Message message) { |
|
messages.insert(0, message); |
|
messageShowTime().then((value) { |
|
refreshState(); |
|
jumpToBottom(); |
|
}); |
|
}); |
|
refreshState(); |
|
jumpToBottom(); |
|
} |
|
|
|
Future refresh() async { |
|
List<Message> messagePage = |
|
await hxDatabase.queryUList(conversation, page: page + 1, pageSize: 10); |
|
if (messagePage.isEmpty) { |
|
refreshController.loadNoData(); |
|
return; |
|
} else { |
|
refreshController.loadComplete(); |
|
page += 1; |
|
} |
|
if (page == 1) { |
|
messages = messagePage; |
|
} else { |
|
messages.addAll(messagePage); |
|
} |
|
await messageShowTime(); |
|
return Future.value(); |
|
} |
|
|
|
Future messageShowTime() async { |
|
List<Message> messagePages = await hxDatabase.queryTList(conversation); |
|
for (var value in messages) { |
|
Message message = messagePages |
|
.firstWhere((element) => value.id == element.id, orElse: () => null); |
|
value.showTime = message != null; |
|
} |
|
} |
|
|
|
///查询个人信息 |
|
queryUser() async { |
|
final SharedPreferences value = await SharedPreferences.getInstance(); |
|
if (value.containsKey('user') && |
|
value.getString('user') != null && |
|
value.getString('user') != "") { |
|
userInfo = UserInfo.fromJson(jsonDecode(value.getString('user'))); |
|
if (userInfo.phone?.isNotEmpty ?? false) { |
|
setState(() {}); |
|
return; |
|
} |
|
} |
|
if (apiService == null) |
|
apiService = |
|
ApiService(Dio(), context: context, token: value.getString("token")); |
|
BaseData<UserInfo> baseData = |
|
await apiService.queryInfo().catchError((onError) {}); |
|
if (baseData != null && baseData.isSuccess) { |
|
setState(() { |
|
userInfo = baseData.data; |
|
}); |
|
SharedPreferences.getInstance().then((value) => { |
|
value.setString('user', jsonEncode(baseData.data)), |
|
}); |
|
} |
|
} |
|
|
|
refreshState() { |
|
if (mounted) setState(() {}); |
|
} |
|
|
|
@override |
|
void initState() { |
|
super.initState(); |
|
|
|
_toUser = widget.arguments["toUser"]; |
|
OnChatMsgInstance.instance.onChatMessage = this; |
|
WidgetsBinding.instance.addObserver(this); |
|
commentFocus.addListener(_focusNodeListener); |
|
|
|
queryUser(); |
|
loadMessageList(); |
|
} |
|
|
|
void jumpToBottom() { |
|
Future.delayed(const Duration(milliseconds: 100), () { |
|
scrollController.position |
|
.jumpTo(0); |
|
}); |
|
} |
|
|
|
void didChangeMetrics() { |
|
WidgetsBinding.instance.addPostFrameCallback((_) { |
|
if (!mounted) return; |
|
isKeyBoardShow = MediaQuery.of(context).viewInsets.bottom > 0; |
|
if (MediaQuery.of(context).viewInsets.bottom == 0) { |
|
if (isKeyBoardShow) { |
|
FocusScope.of(context).requestFocus(FocusNode()); |
|
if (mounted) if (!emojiShowing) if (!moreShow) |
|
setState(() { |
|
hintText = "请输入消息内容..."; |
|
isKeyBoardShow = false; |
|
}); |
|
} |
|
} else { |
|
if (mounted) |
|
setState(() { |
|
isKeyBoardShow = true; |
|
}); |
|
} |
|
}); |
|
if (needShowSmiley && window.viewInsets.bottom <= 0.1) { |
|
needShowSmiley = false; |
|
setState(() { |
|
emojiShowing = true; |
|
}); |
|
} |
|
if (needHideSmiley && window.viewInsets.bottom > 0.1) { |
|
needHideSmiley = false; |
|
setState(() { |
|
emojiShowing = false; |
|
}); |
|
} |
|
if (needShowMore && window.viewInsets.bottom <= 0.1) { |
|
needShowMore = false; |
|
setState(() { |
|
moreShow = true; |
|
}); |
|
} |
|
if (needHideMore && window.viewInsets.bottom > 0.1) { |
|
needHideMore = false; |
|
setState(() { |
|
moreShow = false; |
|
}); |
|
} |
|
} |
|
|
|
@override |
|
void dispose() { |
|
super.dispose(); |
|
OnChatMsgInstance.instance.onChatMessage = _tempOnChatMessage; |
|
WidgetsBinding.instance.removeObserver(this); |
|
commentFocus.removeListener(_focusNodeListener); |
|
scrollController.dispose(); |
|
socketClient.removeCallback(_toUser.mid); |
|
} |
|
|
|
void _focusNodeListener() { |
|
/*if (_focusNode.hasFocus || _focusNode.consumeKeyboardToken()){ |
|
setState(() { |
|
smileyPadGone = true; |
|
}); |
|
}*/ |
|
} |
|
|
|
///输入框点击事件 |
|
_onTextFieldTap() { |
|
if (emojiShowing) { |
|
needHideSmiley = true; |
|
} |
|
if (moreShow) { |
|
needHideMore = true; |
|
} |
|
} |
|
|
|
///表情包点击事件 |
|
_onSmileyTap() { |
|
if (!emojiShowing && commentFocus.hasFocus && isKeyBoardShow) { |
|
needShowSmiley = true; |
|
commentFocus.unfocus(); |
|
} else { |
|
setState(() { |
|
emojiShowing = !emojiShowing; |
|
isKeyBoardShow = emojiShowing; |
|
moreShow = false; |
|
}); |
|
} |
|
} |
|
|
|
///更多点击事件 |
|
_onMoreTap() { |
|
if (!moreShow && commentFocus.hasFocus && isKeyBoardShow) { |
|
needShowMore = true; |
|
commentFocus.unfocus(); |
|
} else { |
|
setState(() { |
|
moreShow = !moreShow; |
|
isKeyBoardShow = moreShow; |
|
emojiShowing = false; |
|
}); |
|
} |
|
} |
|
|
|
///图片/视频选择 |
|
Future getImageOrVideo(GalleryMode galleryMode) async { |
|
if (selectCount == 0) return; |
|
List<Media> medias = await ImagePickers.pickerPaths( |
|
galleryMode: galleryMode, |
|
selectCount: (galleryMode == GalleryMode.video) ? 1 : selectCount, |
|
showGif: true, |
|
showCamera: false, |
|
compressSize: 500, |
|
uiConfig: UIConfig( |
|
uiThemeColor: Color(0xFFFFFFFF), |
|
), |
|
cropConfig: CropConfig( |
|
enableCrop: false, |
|
width: 200, |
|
height: 200, |
|
), |
|
); |
|
|
|
mediaPaths.addAll(medias.map((e) => Medias(e)).toList()); |
|
selectCount = 9 - mediaPaths.length; |
|
|
|
if (mediaPaths.length > 0) { |
|
if (galleryMode == GalleryMode.image) { |
|
dynamicType = 1; |
|
} else { |
|
dynamicType = 2; |
|
} |
|
|
|
List<String> filePath = mediaPaths.map((e) => e.path).toList(); |
|
filePath.forEach((path) { |
|
socketClient.sendMessage(_toUser.mid, "", attach: path, msgType: galleryMode == GalleryMode.image ? 2 : 4); |
|
}); |
|
|
|
} |
|
setState(() {}); |
|
} |
|
|
|
@override |
|
Widget build(BuildContext context) { |
|
double h = MediaQuery.of(context).viewInsets.bottom; |
|
if (h > 0) { |
|
jumpToBottom(); |
|
if (keyboard < h) { |
|
keyboard = h; |
|
// setState(() {}); |
|
} |
|
} |
|
return GestureDetector( |
|
behavior: HitTestBehavior.translucent, |
|
onTap: () { |
|
FocusScope.of(context).requestFocus(FocusNode()); |
|
setState(() { |
|
needShowSmiley = false; |
|
emojiShowing = false; |
|
isKeyBoardShow = emojiShowing; |
|
moreShow = false; |
|
isKeyBoardShow = moreShow; |
|
}); |
|
}, |
|
child: Scaffold( |
|
// resizeToAvoidBottomInset: false, |
|
backgroundColor: Color(0xFFF6F6F6), |
|
appBar: MyAppBar( |
|
title: _toUser.nickname, |
|
titleColor: Color(0xFF0D0D0D), |
|
titleSize: 17.sp, |
|
leading: true, |
|
leadingColor: Colors.black, |
|
action: GestureDetector( |
|
behavior: HitTestBehavior.opaque, |
|
onTap: () async { |
|
await Navigator.of(context).pushNamed('/router/chat_setting', |
|
arguments: {"userId": _toUser.mid}); |
|
page = 0; |
|
refresh().then((value) { |
|
refreshState(); |
|
}); |
|
}, |
|
child: Container( |
|
alignment: Alignment.center, |
|
child: Icon( |
|
Icons.more_horiz, |
|
color: Colors.black, |
|
size: 30, |
|
), |
|
), |
|
), |
|
), |
|
body: Container( |
|
child: Column( |
|
children: [ |
|
Expanded( |
|
child: SmartRefresher( |
|
enablePullDown: false, |
|
enablePullUp: true, |
|
header: MyHeader(), |
|
footer: CustomFooter( |
|
loadStyle: LoadStyle.ShowWhenLoading, |
|
builder: (BuildContext context, LoadStatus mode) { |
|
return SizedBox(); |
|
}, |
|
), |
|
reverse: true, |
|
scrollController: scrollController, |
|
controller: refreshController, |
|
onRefresh: () { |
|
debugPrint(""); |
|
}, |
|
onLoading: () { |
|
refresh().then((value) { |
|
refreshState(); |
|
}); |
|
}, |
|
child: chatDetailsList(), |
|
), |
|
flex: 1, |
|
), |
|
input(), |
|
], |
|
), |
|
), |
|
), |
|
); |
|
} |
|
|
|
///聊天列表 |
|
Widget chatDetailsList() { |
|
return ListView.builder( |
|
itemCount: messages.length, |
|
reverse: true, |
|
padding: EdgeInsets.zero, |
|
itemBuilder: (context, position) { |
|
return GestureDetector( |
|
behavior: HitTestBehavior.opaque, |
|
onTap: () { |
|
setState(() { |
|
copyIndex = 0; |
|
FocusScope.of(context).requestFocus(FocusNode()); |
|
}); |
|
}, |
|
child: chatDetailsItem(position), |
|
); |
|
}, |
|
); |
|
} |
|
|
|
Widget chatDetailsItem(position) { |
|
bool isSelf = messages[position].fromId == selfUserId; |
|
bool isText = messages[position].msgType == 1; |
|
bool isImage = messages[position].msgType == 2; |
|
return Container( |
|
padding: EdgeInsets.only( |
|
top: 16.h, |
|
bottom: 16.h, |
|
), |
|
child: Column( |
|
children: [ |
|
if (messages[position].showTime) |
|
Text( |
|
// position == messages.length-1 |
|
// ? |
|
AppUtils.milliTimeFormatter(DateTime.fromMillisecondsSinceEpoch( |
|
int.parse(messages[position].time))) |
|
// : AppUtils.getTimeDisplay( |
|
// DateTime.fromMillisecondsSinceEpoch( |
|
// int.parse(messages[position].time)), |
|
// DateTime.fromMillisecondsSinceEpoch( |
|
// int.parse(messages[position+1].time))) |
|
, |
|
textAlign: TextAlign.center, |
|
style: TextStyle( |
|
color: Color(0xFFA29E9E), |
|
fontSize: 10.sp, |
|
fontWeight: MyFontWeight.regular, |
|
), |
|
), |
|
// if (messages.indexOf(message) == (messages.length - 1)) |
|
// Padding( |
|
// padding: EdgeInsets.only(top: 10.h, bottom: 24.h), |
|
// child: Text( |
|
// "在对方未回复或关注你之前,你只能发送一条信息", |
|
// textAlign: TextAlign.center, |
|
// style: TextStyle( |
|
// color: Color(0xFFA29E9E), |
|
// fontSize: 10.sp, |
|
// fontWeight: MyFontWeight.regular, |
|
// ), |
|
// ), |
|
// ), |
|
// if (messages.indexOf(message) == (messages.length - 1)) |
|
// SizedBox( |
|
// height: 16.h, |
|
// ), |
|
// if (copyIndex == -1) |
|
// Stack( |
|
// alignment: Alignment.bottomCenter, |
|
// children: [ |
|
// Container( |
|
// padding: EdgeInsets.only(bottom: 13.h), |
|
// child: Container( |
|
// width: 180.w, |
|
// decoration: BoxDecoration( |
|
// color: Color(0xFF2A2A2A), |
|
// borderRadius: BorderRadius.circular(6), |
|
// ), |
|
// padding: EdgeInsets.symmetric( |
|
// horizontal: 32.w, |
|
// vertical: 7.5.h, |
|
// ), |
|
// child: Row( |
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|
// crossAxisAlignment: CrossAxisAlignment.center, |
|
// children: [ |
|
// GestureDetector( |
|
// onTap: () { |
|
// setState(() { |
|
// copyIndex = 0; |
|
// this.copy(tex); |
|
// }); |
|
// }, |
|
// child: Column( |
|
// children: [ |
|
// Image.asset( |
|
// "assets/image/icon_chat_copy.webp", |
|
// height: 16, |
|
// width: 16, |
|
// ), |
|
// SizedBox( |
|
// height: 2.h, |
|
// ), |
|
// Text( |
|
// "复制", |
|
// textAlign: TextAlign.center, |
|
// style: TextStyle( |
|
// color: Colors.white, |
|
// fontSize: 12.sp, |
|
// fontWeight: MyFontWeight.regular, |
|
// ), |
|
// ), |
|
// ], |
|
// ), |
|
// ), |
|
// GestureDetector( |
|
// onTap: () {}, |
|
// child: Column( |
|
// children: [ |
|
// Image.asset( |
|
// "assets/image/icon_chat_delete.webp", |
|
// height: 16, |
|
// width: 16, |
|
// ), |
|
// SizedBox( |
|
// height: 2.h, |
|
// ), |
|
// Text( |
|
// S.of(context).shanchu, |
|
// textAlign: TextAlign.center, |
|
// style: TextStyle( |
|
// color: Colors.white, |
|
// fontSize: 12.sp, |
|
// fontWeight: MyFontWeight.regular, |
|
// ), |
|
// ), |
|
// ], |
|
// ), |
|
// ) |
|
// ], |
|
// ), |
|
// ), |
|
// ), |
|
// Image.asset( |
|
// "assets/image/icon_copy_j.webp", |
|
// height: 17, |
|
// width: 17, |
|
// ), |
|
// ], |
|
// ), |
|
|
|
/// not self |
|
if (!isSelf && isText) |
|
SizedBox( |
|
height: 10.h, |
|
), |
|
if (!isSelf && isText) |
|
Padding( |
|
padding: EdgeInsets.only(left: 17.w, right: 39.w), |
|
child: Row( |
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
children: [ |
|
GestureDetector( |
|
behavior: HitTestBehavior.opaque, |
|
onTap: () { |
|
Navigator.of(context).pushNamed( |
|
'/router/personal_page', |
|
arguments: { |
|
"memberId": _toUser?.mid ?? "", |
|
"inletType": 1 |
|
}, |
|
); |
|
}, |
|
child: MImage( |
|
_toUser.avatar, |
|
isCircle: true, |
|
height: 44.h, |
|
width: 44.h, |
|
fit: BoxFit.cover, |
|
errorSrc: "assets/image/default_1.webp", |
|
fadeSrc: "assets/image/default_1.webp", |
|
), |
|
), |
|
SizedBox( |
|
width: 12.w, |
|
), |
|
Expanded( |
|
child: Container( |
|
alignment: Alignment.centerLeft, |
|
child: Container( |
|
decoration: BoxDecoration( |
|
borderRadius: BorderRadius.circular(6), |
|
color: Color(0xFFFFFFFF), |
|
boxShadow: [ |
|
BoxShadow( |
|
color: Color(0xFFA8A3A3).withAlpha(12), |
|
offset: Offset(0, 4), |
|
blurRadius: 4, |
|
spreadRadius: 0, |
|
), |
|
], |
|
), |
|
padding: EdgeInsets.symmetric( |
|
vertical: 8.h, |
|
horizontal: 12.w, |
|
), |
|
child: GestureDetector( |
|
onLongPress: () { |
|
setState(() { |
|
copyIndex = 1; |
|
}); |
|
}, |
|
child: Text( |
|
tex = messages[position].content, |
|
textAlign: TextAlign.left, |
|
style: TextStyle( |
|
height: 1.2.h, |
|
color: Color(0XFF0D0D0D), |
|
fontSize: 17.sp, |
|
fontWeight: MyFontWeight.medium, |
|
), |
|
), |
|
), |
|
), |
|
), |
|
), |
|
], |
|
), |
|
), |
|
|
|
// if (copyIndex == 1) |
|
// Stack( |
|
// alignment: Alignment.bottomCenter, |
|
// children: [ |
|
// Container( |
|
// padding: EdgeInsets.only(bottom: 13.h), |
|
// child: Container( |
|
// width: 180.w, |
|
// decoration: BoxDecoration( |
|
// color: Color(0xFF2A2A2A), |
|
// borderRadius: BorderRadius.circular(6), |
|
// ), |
|
// padding: |
|
// EdgeInsets.symmetric(horizontal: 32.w, vertical: 7.5.h), |
|
// child: Row( |
|
// mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|
// crossAxisAlignment: CrossAxisAlignment.center, |
|
// children: [ |
|
// GestureDetector( |
|
// onTap: () { |
|
// setState(() { |
|
// copyIndex = 0; |
|
// this.copy(tex); |
|
// }); |
|
// }, |
|
// child: Column( |
|
// children: [ |
|
// Image.asset( |
|
// "assets/image/icon_chat_copy.webp", |
|
// height: 16, |
|
// width: 16, |
|
// ), |
|
// SizedBox( |
|
// height: 2.h, |
|
// ), |
|
// Text( |
|
// "复制", |
|
// textAlign: TextAlign.center, |
|
// style: TextStyle( |
|
// color: Colors.white, |
|
// fontSize: 12.sp, |
|
// fontWeight: MyFontWeight.regular, |
|
// ), |
|
// ), |
|
// ], |
|
// ), |
|
// ), |
|
// GestureDetector( |
|
// onTap: () {}, |
|
// child: Column( |
|
// children: [ |
|
// Image.asset( |
|
// "assets/image/icon_chat_delete.webp", |
|
// height: 16, |
|
// width: 16, |
|
// ), |
|
// SizedBox( |
|
// height: 2.h, |
|
// ), |
|
// Text( |
|
// S.of(context).shanchu, |
|
// textAlign: TextAlign.center, |
|
// style: TextStyle( |
|
// color: Colors.white, |
|
// fontSize: 12.sp, |
|
// fontWeight: MyFontWeight.regular, |
|
// ), |
|
// ), |
|
// ], |
|
// ), |
|
// ) |
|
// ], |
|
// ), |
|
// ), |
|
// ), |
|
// Image.asset( |
|
// "assets/image/icon_copy_j.webp", |
|
// height: 17, |
|
// width: 17, |
|
// ), |
|
// ], |
|
// ), |
|
|
|
/// self |
|
if (isSelf && isText) |
|
SizedBox( |
|
height: 10.h, |
|
), |
|
if (isSelf && isText) |
|
Padding( |
|
padding: EdgeInsets.only(left: 36.w, right: 16.w), |
|
child: Row( |
|
crossAxisAlignment: CrossAxisAlignment.start, |
|
children: [ |
|
if (messages[position].state == 3) |
|
Container( |
|
decoration: BoxDecoration( |
|
borderRadius: BorderRadius.circular(100), |
|
color: Color(0xFFFF441A), |
|
), |
|
width: 20, |
|
height: 20, |
|
alignment: Alignment.center, |
|
child: Text( |
|
"!", |
|
textAlign: TextAlign.left, |
|
style: TextStyle( |
|
color: Colors.white, |
|
fontSize: 17.sp, |
|
fontWeight: MyFontWeight.regular, |
|
), |
|
), |
|
), |
|
if (messages[position].state == 3) |
|
SizedBox( |
|
width: 12.w, |
|
), |
|
Expanded( |
|
child: Container( |
|
alignment: Alignment.centerRight, |
|
child: Container( |
|
decoration: BoxDecoration( |
|
borderRadius: BorderRadius.circular(6), |
|
color: Color(0xFF32A060), |
|
boxShadow: [ |
|
BoxShadow( |
|
color: Color(0xFFA8A3A3).withAlpha(12), |
|
offset: Offset(0, 4), |
|
blurRadius: 4, |
|
spreadRadius: 0, |
|
), |
|
], |
|
), |
|
padding: EdgeInsets.symmetric( |
|
vertical: 8.h, |
|
horizontal: 12.w, |
|
), |
|
child: GestureDetector( |
|
onLongPress: () { |
|
setState(() { |
|
copyIndex = 1; |
|
// showCustomDialog(position); |
|
}); |
|
}, |
|
child: Text( |
|
tex = messages[position].content, |
|
textAlign: TextAlign.left, |
|
style: TextStyle( |
|
height: 1.2.h, |
|
color: Colors.white, |
|
fontSize: 17.sp, |
|
fontWeight: MyFontWeight.medium, |
|
), |
|
), |
|
), |
|
), |
|
), |
|
), |
|
SizedBox( |
|
width: 12.w, |
|
), |
|
GestureDetector( |
|
behavior: HitTestBehavior.opaque, |
|
onTap: () { |
|
Navigator.of(context).pushNamed('/router/personal_page', |
|
arguments: {"memberId": "0", "inletType": 1}); |
|
}, |
|
child: MImage( |
|
userInfo?.headimg ?? "", |
|
isCircle: true, |
|
height: 44.h, |
|
width: 44.h, |
|
fit: BoxFit.cover, |
|
errorSrc: "assets/image/default_1.webp", |
|
fadeSrc: "assets/image/default_1.webp", |
|
), |
|
), |
|
], |
|
), |
|
), |
|
|
|
/// not self image 图片 |
|
if (!isSelf && isImage) |
|
Padding( |
|
padding: EdgeInsets.only(left: 17.w, right: 39.w, top: 20.h), |
|
child: Row( |
|
children: [ |
|
MImage( |
|
userInfo?.headimg ?? "", |
|
isCircle: true, |
|
width: 44, |
|
height: 44, |
|
fit: BoxFit.cover, |
|
errorSrc: "assets/image/default_1.webp", |
|
fadeSrc: "assets/image/default_1.webp", |
|
), |
|
SizedBox( |
|
width: 12.w, |
|
), |
|
Expanded( |
|
flex: 3, |
|
child: Container( |
|
decoration: BoxDecoration( |
|
borderRadius: BorderRadius.circular(6), |
|
color: Color(0xFFFFFFFF), |
|
boxShadow: [ |
|
BoxShadow( |
|
color: Color(0xFFA8A3A3).withAlpha(12), |
|
offset: Offset(0, 4), |
|
blurRadius: 4, |
|
spreadRadius: 0, |
|
), |
|
], |
|
), |
|
child: GestureDetector( |
|
onLongPress: () { |
|
setState(() {}); |
|
}, |
|
child: Image.file( |
|
File(messages[position].attach), |
|
width: 180.h, |
|
height: 200.h, |
|
fit: BoxFit.fill, |
|
), |
|
), |
|
), |
|
), |
|
Spacer(), |
|
], |
|
), |
|
), |
|
|
|
/// self image 图片 |
|
if (isSelf && isImage) |
|
Padding( |
|
padding: EdgeInsets.only(left: 39.w, right: 17.w, top: 20.h), |
|
child: Row( |
|
children: [ |
|
Spacer(), |
|
Expanded( |
|
flex: 3, |
|
child: Container( |
|
decoration: BoxDecoration( |
|
borderRadius: BorderRadius.circular(6), |
|
color: Color(0xFFFFFFFF), |
|
boxShadow: [ |
|
BoxShadow( |
|
color: Color(0xFFA8A3A3).withAlpha(12), |
|
offset: Offset(0, 4), |
|
blurRadius: 4, |
|
spreadRadius: 0, |
|
), |
|
], |
|
), |
|
child: GestureDetector( |
|
onLongPress: () { |
|
setState(() {}); |
|
}, |
|
child: Image.file( |
|
File(messages[position].attach), |
|
width: 180.h, |
|
height: 200.h, |
|
fit: BoxFit.fill, |
|
), |
|
), |
|
), |
|
), |
|
SizedBox( |
|
width: 12.w, |
|
), |
|
MImage( |
|
userInfo?.headimg ?? "", |
|
isCircle: true, |
|
width: 44, |
|
height: 44, |
|
fit: BoxFit.cover, |
|
errorSrc: "assets/image/default_1.webp", |
|
fadeSrc: "assets/image/default_1.webp", |
|
), |
|
], |
|
), |
|
), |
|
|
|
/// no reply long time |
|
// if (messages.indexOf(message) == 0) |
|
// Padding( |
|
// padding: EdgeInsets.only(left: 17.w, right: 17.w, top: 24.h), |
|
// child: Text( |
|
// "由于对方没有回复你,你只能发送一条消息,需要对方关注或回复后才能恢复正常聊天", |
|
// textAlign: TextAlign.center, |
|
// style: TextStyle( |
|
// color: Color(0xFFA29E9E), |
|
// fontSize: 10.sp, |
|
// fontWeight: MyFontWeight.regular, |
|
// ), |
|
// ), |
|
// ), |
|
], |
|
), |
|
); |
|
} |
|
|
|
///富文本输入框 |
|
Widget input() { |
|
return Container( |
|
color: Color(0xFFFDFCFC), |
|
padding: EdgeInsets.only(top: 14.h, bottom: 15.h), |
|
child: Column( |
|
children: [ |
|
///输入框 |
|
Row( |
|
children: [ |
|
Expanded( |
|
flex: 1, |
|
child: Container( |
|
margin: EdgeInsets.only( |
|
left: 20.w, |
|
), |
|
decoration: BoxDecoration( |
|
color: Color(0xFFF6F6F6), |
|
borderRadius: BorderRadius.circular(6), |
|
), |
|
child: Container( |
|
margin: EdgeInsets.only(left: 17.w), |
|
alignment: Alignment.topLeft, |
|
child: TextField( |
|
textInputAction: TextInputAction.send, |
|
onTap: () { |
|
moreShow = false; |
|
_onTextFieldTap(); |
|
}, |
|
onEditingComplete: () { |
|
var commentText = chatController.text; |
|
if (commentText.trim() == "") { |
|
return; |
|
} |
|
socketClient.sendMessage(_toUser.mid, commentText) |
|
.then((value) { |
|
Message message = value; |
|
messages.insert(0, message); |
|
chatController.clear(); |
|
messageShowTime().then((value) { |
|
refreshState(); |
|
jumpToBottom(); |
|
}); |
|
}); |
|
}, |
|
maxLines: 8, |
|
minLines: 1, |
|
focusNode: commentFocus, |
|
controller: chatController, |
|
decoration: InputDecoration( |
|
border: InputBorder.none, |
|
hintText: hintText, |
|
hintStyle: TextStyle( |
|
fontSize: 14.sp, |
|
color: Color(0xFF868686), |
|
), |
|
), |
|
), |
|
), |
|
), |
|
), |
|
GestureDetector( |
|
behavior: HitTestBehavior.opaque, |
|
onTap: () { |
|
_onSmileyTap(); |
|
jumpToBottom(); |
|
}, |
|
child: Container( |
|
padding: EdgeInsets.only(left: 15.w, right: 8.w), |
|
child: Image.asset( |
|
"assets/image/icon_chat_emo.webp", |
|
height: 26.h, |
|
width: 26.h, |
|
), |
|
), |
|
), |
|
GestureDetector( |
|
behavior: HitTestBehavior.opaque, |
|
onTap: () { |
|
_onMoreTap(); |
|
jumpToBottom(); |
|
// SmartDialog.showToast("暂不支持", alignment: Alignment.center); |
|
}, |
|
child: Container( |
|
padding: EdgeInsets.only(left: 8.w, right: 19.w), |
|
child: Image.asset( |
|
"assets/image/chat_more.webp", |
|
height: 26.h, |
|
width: 26.h, |
|
), |
|
), |
|
), |
|
], |
|
), |
|
SizedBox( |
|
height: 16.h, |
|
), |
|
|
|
///表情 |
|
Offstage( |
|
offstage: !emojiShowing, |
|
child: SizedBox( |
|
height: keyboard == -1 ? 270 : keyboard, |
|
width: MediaQuery.of(context).size.width, |
|
child: EmojiPicker( |
|
textEditingController: chatController, |
|
config: Config( |
|
columns: 7, |
|
emojiSizeMax: 32 * (Platform.isIOS ? 1.10 : 1.0), |
|
verticalSpacing: 0, |
|
horizontalSpacing: 0, |
|
gridPadding: EdgeInsets.zero, |
|
initCategory: Category.RECENT, |
|
bgColor: const Color(0xFFF2F2F2), |
|
// indicatorColor: Colors.blue, |
|
iconColor: Colors.grey, |
|
iconColorSelected: Colors.blue, |
|
backspaceColor: Colors.blue, |
|
skinToneDialogBgColor: Colors.white, |
|
skinToneIndicatorColor: Colors.grey, |
|
enableSkinTones: true, |
|
showRecentsTab: true, |
|
recentsLimit: 28, |
|
replaceEmojiOnLimitExceed: false, |
|
noRecents: Text( |
|
"最近使用", |
|
style: TextStyle(fontSize: 20, color: Colors.black26), |
|
textAlign: TextAlign.center, |
|
), |
|
loadingIndicator: const SizedBox.shrink(), |
|
tabIndicatorAnimDuration: Duration(milliseconds: 0), |
|
categoryIcons: const CategoryIcons(), |
|
buttonMode: ButtonMode.MATERIAL, |
|
checkPlatformCompatibility: true, |
|
), |
|
), |
|
), |
|
), |
|
|
|
///更多 |
|
Offstage( |
|
offstage: !moreShow, |
|
child: Container( |
|
height: keyboard == -1 ? 167.h : keyboard, |
|
child: Column( |
|
children: [ |
|
Container( |
|
width: double.infinity, |
|
height: 1.h, |
|
color: Color(0xFFF7F7F7), |
|
margin: EdgeInsets.only(bottom: 10.h), |
|
), |
|
Row( |
|
children: [ |
|
GestureDetector( |
|
behavior: HitTestBehavior.opaque, |
|
onTap: () { |
|
getImageOrVideo(GalleryMode.video); |
|
}, |
|
child: Column( |
|
children: [ |
|
Container( |
|
decoration: BoxDecoration( |
|
borderRadius: BorderRadius.circular(6), |
|
color: Color(0xFFFFFFFF), |
|
boxShadow: [ |
|
BoxShadow( |
|
color: Color(0xFFD5D5D5).withAlpha(25), |
|
offset: Offset(4, 2), |
|
blurRadius: 4, |
|
spreadRadius: 0, |
|
) |
|
], |
|
), |
|
margin: EdgeInsets.only(right: 15.w, left: 14.w), |
|
padding: EdgeInsets.all(12), |
|
child: Image.asset( |
|
"assets/image/icon_chat_camera.webp", |
|
height: 24, |
|
width: 24, |
|
), |
|
), |
|
Padding( |
|
padding: EdgeInsets.only(top: 8.h), |
|
child: Text( |
|
"拍照", |
|
style: TextStyle( |
|
fontSize: 12.sp, |
|
color: Color(0xFFA29E9E), |
|
fontWeight: MyFontWeight.regular, |
|
), |
|
), |
|
), |
|
], |
|
), |
|
), |
|
GestureDetector( |
|
behavior: HitTestBehavior.opaque, |
|
onTap: () { |
|
getImageOrVideo(GalleryMode.image); |
|
}, |
|
child: Column( |
|
children: [ |
|
Container( |
|
decoration: BoxDecoration( |
|
borderRadius: BorderRadius.circular(6), |
|
color: Color(0xFFFFFFFF), |
|
boxShadow: [ |
|
BoxShadow( |
|
color: Color(0xFFD5D5D5).withAlpha(25), |
|
offset: Offset(4, 2), |
|
blurRadius: 4, |
|
spreadRadius: 0, |
|
) |
|
], |
|
), |
|
padding: EdgeInsets.all(12), |
|
child: Image.asset( |
|
"assets/image/icon_chat_photo.webp", |
|
height: 24, |
|
width: 24, |
|
), |
|
), |
|
Padding( |
|
padding: EdgeInsets.only(top: 8.h), |
|
child: Text( |
|
"相册", |
|
style: TextStyle( |
|
fontSize: 12.sp, |
|
color: Color(0xFFA29E9E), |
|
fontWeight: MyFontWeight.regular, |
|
), |
|
), |
|
), |
|
], |
|
), |
|
), |
|
], |
|
), |
|
], |
|
), |
|
), |
|
), |
|
], |
|
), |
|
); |
|
} |
|
|
|
///复制弹窗 |
|
showCustomDialog(int position) { |
|
showDialog( |
|
context: context, |
|
builder: (BuildContext context) { |
|
return AlertDialog( |
|
backgroundColor: Colors.transparent, |
|
elevation: 0, |
|
content: Container( |
|
// width: 60.w, |
|
height:50.h, |
|
decoration: BoxDecoration( |
|
color: Color(0xFF2A2A2A), |
|
borderRadius: BorderRadius.circular(6), |
|
), |
|
padding: EdgeInsets.symmetric( |
|
horizontal: 32.w, |
|
vertical: 7.5.h, |
|
), |
|
child: Row( |
|
mainAxisAlignment: MainAxisAlignment.spaceBetween, |
|
crossAxisAlignment: CrossAxisAlignment.center, |
|
children: [ |
|
GestureDetector( |
|
onTap: () { |
|
setState(() { |
|
copyIndex = 0; |
|
this.copy(tex); |
|
}); |
|
}, |
|
child: Column( |
|
children: [ |
|
Image.asset( |
|
"assets/image/icon_chat_copy.webp", |
|
height: 16, |
|
width: 16, |
|
), |
|
SizedBox( |
|
height: 2.h, |
|
), |
|
Text( |
|
"复制", |
|
textAlign: TextAlign.center, |
|
style: TextStyle( |
|
color: Colors.white, |
|
fontSize: 12.sp, |
|
fontWeight: MyFontWeight.regular, |
|
), |
|
), |
|
], |
|
), |
|
), |
|
GestureDetector( |
|
onTap: () {}, |
|
child: Column( |
|
children: [ |
|
Image.asset( |
|
"assets/image/icon_chat_delete.webp", |
|
height: 16, |
|
width: 16, |
|
), |
|
SizedBox( |
|
height: 2.h, |
|
), |
|
Text( |
|
S.of(context).shanchu, |
|
textAlign: TextAlign.center, |
|
style: TextStyle( |
|
color: Colors.white, |
|
fontSize: 12.sp, |
|
fontWeight: MyFontWeight.regular, |
|
), |
|
), |
|
], |
|
), |
|
) |
|
], |
|
), |
|
) |
|
); |
|
}); |
|
} |
|
|
|
/// 复制文本 |
|
copy(String tex) { |
|
print(tex); |
|
Clipboard.setData(ClipboardData(text: tex)); |
|
} |
|
|
|
}
|
|
|