Browse Source

聊天列表数据更改;

添加好友弹窗更改;
wr_202303
wurong 4 months ago
parent
commit
d221f5e87c
  1. 105
      lib/im/add_friend.dart
  2. 77
      lib/im/chat_details_page.dart
  3. 33
      lib/im/database/contact.dart
  4. 77
      lib/im/database/hx_database.dart
  5. 0
      lib/im/im_search.dart
  6. 94
      lib/im/im_view/im_page.dart
  7. 20
      lib/im/im_view/time_formatter.dart
  8. 61
      lib/retrofit/data/im_user_list.dart
  9. 10
      lib/retrofit/retrofit_api.dart
  10. 48
      lib/retrofit/retrofit_api.g.dart

105
lib/im/add_friend.dart

@ -96,7 +96,7 @@ class _AddFriend extends State<AddFriend> {
); );
} }
/// ///
Widget addFriendItem() { Widget addFriendItem() {
return Container( return Container(
margin: EdgeInsets.only(left:16.w,right:16.w,bottom: 24.h), margin: EdgeInsets.only(left:16.w,right:16.w,bottom: 24.h),
@ -122,7 +122,12 @@ class _AddFriend extends State<AddFriend> {
fontWeight: FontWeight.w500), fontWeight: FontWeight.w500),
), ),
), ),
Container( GestureDetector(
behavior: HitTestBehavior.opaque,
onTap:(){
showFriendVerificationDialog();
},
child: Container(
padding: EdgeInsets.symmetric(horizontal:18.w,vertical:6.h), padding: EdgeInsets.symmetric(horizontal:18.w,vertical:6.h),
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: BorderRadius.circular(26.5.r), borderRadius: BorderRadius.circular(26.5.r),
@ -143,11 +148,107 @@ class _AddFriend extends State<AddFriend> {
color: Colors.white, color: Colors.white,
fontWeight:MyFontWeight.regular), fontWeight:MyFontWeight.regular),
), ),
),
) )
]), ]),
); );
} }
///
showFriendVerificationDialog() {
showDialog(
context: context,
builder: (context) {
return AlertDialog(
contentPadding: EdgeInsets.zero, //
content: Container(
// width: MediaQuery.of(context).size.width - 84,
height: 130.h,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(4),
),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Padding(padding:EdgeInsets.symmetric(vertical:16.h),
child: Text(
"好友验证",
style: TextStyle(
color: Color(0xFF060606),
fontSize: 16.sp,
fontWeight: MyFontWeight.bold,
),
),),
Expanded(child:Text(
"我是秀才8856",
style: TextStyle(
color: Color(0xFF060606),
fontSize: 12.sp,
fontWeight: MyFontWeight.regular,
),
)),
// Spacer(),
Container(
margin:EdgeInsets.only(top:18.h),
height:1.h,
width: double.infinity,
color:Color(0xFFEDEDED),
),
Row(
children: [
Expanded(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).pop();
},
child: Container(
// height: 38.h,
child: Text(
"取消",
textAlign: TextAlign.center,
style: TextStyle(
fontSize: 16.sp,
color: Color(0xFF060606),
)
)
)
)
),
Container(
height:45,
width: 1.w,
color: Color(0xFFEDEDED),
),
Expanded(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
Navigator.of(context).pop();
},
child: Container(
// height: 38.h,
child: Text(
"确认",
textAlign: TextAlign.center,
style: TextStyle(
color: Color(0xFF060606),
)
)
)
)
)
],
)
],
),
),
);
},
);
}
/// ///
Widget friendGroupSearch() { Widget friendGroupSearch() {
return Container( return Container(

77
lib/im/chat_details_page.dart

@ -17,6 +17,8 @@ import 'package:shared_preferences/shared_preferences.dart';
import '../../community/release_dynamic.dart'; import '../../community/release_dynamic.dart';
import '../../generated/l10n.dart'; import '../../generated/l10n.dart';
import '../../utils/font_weight.dart'; import '../../utils/font_weight.dart';
import '../retrofit/data/im_user_list.dart';
import '../view_widget/custom_image.dart';
import 'im_view/on_chat_message.dart'; import 'im_view/on_chat_message.dart';
import 'im_view/on_chat_msg_instance.dart'; import 'im_view/on_chat_msg_instance.dart';
@ -54,6 +56,8 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
final ScrollController scrollController = ScrollController(); final ScrollController scrollController = ScrollController();
String tex = ""; String tex = "";
int copyIndex = 0; int copyIndex = 0;
String selfUserId = "";
ImUserList _toUser;
@override @override
void onMessage(txt) { void onMessage(txt) {
@ -64,11 +68,9 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
loadMessageList() async { loadMessageList() async {
selfUserId = (await SharedPreferences.getInstance()).getString("userId"); selfUserId = (await SharedPreferences.getInstance()).getString("userId");
messages = await hxDatabase.queryUList(_toUser.mid);
toUserId = widget.arguments["toId"]; socketClient.addCallback(_toUser.mid, (Message message) {
messages = await hxDatabase.queryUList(toUserId);
socketClient.addCallback(toUserId, (Message message) {
messages.add(message); messages.add(message);
refreshState(); refreshState();
@ -80,12 +82,11 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
if (mounted) setState(() {}); if (mounted) setState(() {});
} }
String selfUserId = "";
String toUserId = "";
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_toUser = widget.arguments["toUser"];
OnChatMsgInstance.instance.onChatMessage = this; OnChatMsgInstance.instance.onChatMessage = this;
WidgetsBinding.instance.addObserver(this); WidgetsBinding.instance.addObserver(this);
commentFocus.addListener(_focusNodeListener); commentFocus.addListener(_focusNodeListener);
@ -154,7 +155,7 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
WidgetsBinding.instance.removeObserver(this); WidgetsBinding.instance.removeObserver(this);
commentFocus.removeListener(_focusNodeListener); commentFocus.removeListener(_focusNodeListener);
socketClient.removeCallback(toUserId); socketClient.removeCallback(_toUser.mid);
} }
@ -250,7 +251,7 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
// resizeToAvoidBottomInset: false, // resizeToAvoidBottomInset: false,
backgroundColor: Color(0xFFF6F6F6), backgroundColor: Color(0xFFF6F6F6),
appBar: MyAppBar( appBar: MyAppBar(
title: "哈哈哈哈", title: _toUser.nickname,
titleColor: Color(0xFF0D0D0D), titleColor: Color(0xFF0D0D0D),
titleSize: 17.sp, titleSize: 17.sp,
leading: true, leading: true,
@ -367,6 +368,7 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
height: 16.h, height: 16.h,
), ),
if (copyIndex == 1) if (copyIndex == 1)
///
Stack( Stack(
alignment: Alignment.bottomCenter, alignment: Alignment.bottomCenter,
children: [ children: [
@ -456,19 +458,14 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
padding: EdgeInsets.only(left: 17.w, right: 39.w), padding: EdgeInsets.only(left: 17.w, right: 39.w),
child: Row( child: Row(
children: [ children: [
// MImage( MImage(
// "", _toUser.avatar,
// isCircle: true, isCircle: true,
// width: 44,
// height: 44,
// fit: BoxFit.cover,
// errorSrc: "assets/image/default_user.webp",
// fadeSrc: "assets/image/default_user.webp",
// ),
Image.asset(
"assets/image/fuka_zj.webp",
height: 44.h, height: 44.h,
width: 44.h, width: 44.h,
fit: BoxFit.cover,
errorSrc: "assets/image/default_1.webp",
fadeSrc: "assets/image/default_1.webp",
), ),
SizedBox( SizedBox(
width: 12.w, width: 12.w,
@ -658,19 +655,14 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
SizedBox( SizedBox(
width: 12.w, width: 12.w,
), ),
// MImage( MImage(
// "", "",
// isCircle: true, isCircle: true,
// width: 44, height: 44.h,
// height: 44, width: 44.h,
// fit: BoxFit.cover, fit: BoxFit.cover,
// errorSrc: "assets/image/default_user.webp", errorSrc: "assets/image/default_1.webp",
// fadeSrc: "assets/image/default_user.webp", fadeSrc: "assets/image/default_1.webp",
// ),
Image.asset(
"assets/image/fuka_zj.webp",
height: 44,
width: 44,
), ),
], ],
), ),
@ -682,19 +674,14 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
padding: EdgeInsets.only(left: 17.w, right: 39.w, top: 20.h), padding: EdgeInsets.only(left: 17.w, right: 39.w, top: 20.h),
child: Row( child: Row(
children: [ children: [
// MImage( MImage(
// "", _toUser.avatar,
// isCircle: true, isCircle: true,
// width: 44,
// height: 44,
// fit: BoxFit.cover,
// errorSrc: "assets/image/default_user.webp",
// fadeSrc: "assets/image/default_user.webp",
// ),
Image.asset(
"assets/image/fuka_zj.webp",
height: 44.h, height: 44.h,
width: 44.h, width: 44.h,
fit: BoxFit.cover,
errorSrc: "assets/image/default_1.webp",
fadeSrc: "assets/image/default_1.webp",
), ),
SizedBox( SizedBox(
width: 12.w, width: 12.w,
@ -786,7 +773,7 @@ class _ChatDetailsPage extends State<ChatDetailsPage>
if (commentText.trim() == "") { if (commentText.trim() == "") {
return; return;
} }
socketClient.sendMessage(toUserId, commentText).then((value) { socketClient.sendMessage(_toUser.mid, commentText).then((value) {
Message message = value; Message message = value;
messages.insert(0, message); messages.insert(0, message);
chatController.clear(); chatController.clear();

33
lib/im/database/contact.dart

@ -1,33 +0,0 @@
class Contact {
int id;
String userId;
String nickName;
String imageUrl;
int state;
int isDelete;
Contact(this.id, this.userId, this.nickName, this.imageUrl, this.state,
this.isDelete);
factory Contact.fromJson(Map<String, dynamic> json) => Contact(
json["id"],
json["userId"],
json["nickName"],
json["imageUrl"],
json["state"],
json["isDelete"]);
Map<String, dynamic> toJson() => <String, dynamic>{
"id": id,
"fromId": userId,
"toId": nickName,
"replyId": imageUrl,
"state": state,
"isDelete": isDelete == null ? 0 : isDelete
};
}

77
lib/im/database/hx_database.dart

@ -1,17 +1,14 @@
import 'package:flutter/cupertino.dart'; import 'package:flutter/cupertino.dart';
import 'package:huixiang/im/database/contact.dart';
import 'package:huixiang/im/database/message.dart'; import 'package:huixiang/im/database/message.dart';
import 'package:huixiang/im/database/migration.dart'; import 'package:huixiang/im/database/migration.dart';
import 'package:sqflite/sqflite.dart'; import 'package:sqflite/sqflite.dart';
import '../../retrofit/data/im_user_list.dart';
class HxDatabase { class HxDatabase {
Database db; Database db;
void open({String key}) async { void open({String key}) async {
// _migrations.add(Migration(1, 2, (Database database) async { // _migrations.add(Migration(1, 2, (Database database) async {
// database.execute('ALTER TABLE `Message` ADD COLUMN `replyId` VARCHAR(20) DEFAULT NULL AFTER `toId`'); // database.execute('ALTER TABLE `Message` ADD COLUMN `replyId` VARCHAR(20) DEFAULT NULL AFTER `toId`');
// })); // }));
@ -20,23 +17,19 @@ class HxDatabase {
if (key?.isNotEmpty ?? false) { if (key?.isNotEmpty ?? false) {
databaseName = 'hx_$key.db'; databaseName = 'hx_$key.db';
} }
await openDatabase( await openDatabase(databaseName, version: 2,
databaseName,
version: 2,
onCreate: (Database db, int version) async { onCreate: (Database db, int version) async {
db.execute('CREATE TABLE IF NOT EXISTS `Message` (`id` INTEGER, `fromId` VARCHAR(20), `toId` VARCHAR(20), `replyId` VARCHAR(20), `content` TEXT, `attach` TEXT, `msgType` INTEGER, `time` VARCHAR(20), `state` INTEGER, `isDelete` INTEGER, PRIMARY KEY (`id`))'); db.execute(
db.execute('CREATE TABLE IF NOT EXISTS `Contact` (`id` INTEGER, `userId` VARCHAR(20), `nickName` VARCHAR(20), `imageUrl` VARCHAR(200), `state` INTEGER, `isDelete` INTEGER, PRIMARY KEY (`id`))'); 'CREATE TABLE IF NOT EXISTS `Message` (`id` INTEGER, `fromId` VARCHAR(20), `toId` VARCHAR(20), `replyId` VARCHAR(20), `content` TEXT, `attach` TEXT, `msgType` INTEGER, `time` VARCHAR(20), `state` INTEGER, `isDelete` INTEGER, PRIMARY KEY (`id`))');
}, db.execute(
onConfigure: (database) async { 'CREATE TABLE IF NOT EXISTS `ImUser` (`id` INTEGER, `mid` VARCHAR(20), `nickname` VARCHAR(20), `avatar` VARCHAR(200), `phone` VARCHAR(200), `isDelete` INTEGER, PRIMARY KEY (`id`))');
}, onConfigure: (database) async {
await database.execute('PRAGMA foreign_keys = ON'); await database.execute('PRAGMA foreign_keys = ON');
}, }, onUpgrade: (database, startVersion, endVersion) async {
onUpgrade: (database, startVersion, endVersion) async {
await runMigrations(database, startVersion, endVersion, _migrations); await runMigrations(database, startVersion, endVersion, _migrations);
}, }, onOpen: (Database db) {
onOpen: (Database db) {
this.db = db; this.db = db;
} });
);
} }
void close() { void close() {
@ -47,8 +40,10 @@ class HxDatabase {
if (db == null) { if (db == null) {
return Future.value(); return Future.value();
} }
String sql = 'SELECT * FROM Message WHERE toId = ? OR fromId = ? ORDER BY time DESC LIMIT 1'; String sql =
List<Message> messages = await db.rawQuery(sql, [userId, userId]).then((value) { 'SELECT * FROM Message WHERE toId = ? OR fromId = ? ORDER BY time DESC LIMIT 1';
List<Message> messages =
await db.rawQuery(sql, [userId, userId]).then((value) {
return value.map((e) { return value.map((e) {
debugPrint("Message: ${e}"); debugPrint("Message: ${e}");
return Message.fromJson(e); return Message.fromJson(e);
@ -63,7 +58,8 @@ class HxDatabase {
if (db == null) { if (db == null) {
return Future.value(<Message>[]); return Future.value(<Message>[]);
} }
String sql = 'SELECT * FROM Message WHERE toId = ? OR fromId = ? GROUP BY toId,fromId ORDER BY time DESC'; String sql =
'SELECT * FROM Message WHERE toId = ? OR fromId = ? GROUP BY toId,fromId ORDER BY time DESC';
return db.rawQuery(sql, [userId, userId]).then((value) { return db.rawQuery(sql, [userId, userId]).then((value) {
return value.map((e) { return value.map((e) {
debugPrint("Message: ${e}"); debugPrint("Message: ${e}");
@ -78,7 +74,8 @@ class HxDatabase {
if (db == null) { if (db == null) {
return Future.value(<Message>[]); return Future.value(<Message>[]);
} }
String sql = 'SELECT * FROM Message WHERE toId = ? OR fromId = ? ORDER BY time DESC'; String sql =
'SELECT * FROM Message WHERE toId = ? OR fromId = ? ORDER BY time DESC';
return db.rawQuery(sql, [userId, userId]).then((value) { return db.rawQuery(sql, [userId, userId]).then((value) {
return value.map((e) => Message.fromJson(e)).toList(); return value.map((e) => Message.fromJson(e)).toList();
}, onError: (error) { }, onError: (error) {
@ -103,7 +100,8 @@ class HxDatabase {
return Future.value(0); return Future.value(0);
} }
debugPrint("Message_insert: $message"); debugPrint("Message_insert: $message");
return db.update("Message", message, where: 'id = ?', whereArgs: [message['id']]); return db.update("Message", message,
where: 'id = ?', whereArgs: [message['id']]);
} }
Future<int> insert(Map message) async { Future<int> insert(Map message) async {
@ -114,37 +112,41 @@ class HxDatabase {
return db.insert("Message", message); return db.insert("Message", message);
} }
Future<int> insertContact(Map contactMap) async { Future<int> insertOrUpdateImUser(Map imUserMap) async {
if (db == null) { if (db == null) {
return Future.value(0); return Future.value(0);
} }
debugPrint("contact_insert: $contactMap"); debugPrint("imUser_insert: $imUserMap");
return db.insert("Contact", contactMap); if ((await queryImUserById(imUserMap['mid'])) == null)
return db.insert("ImUser", imUserMap);
else
return db.update("ImUser", imUserMap,
where: 'mid = ?', whereArgs: [imUserMap['mid']]);
} }
Future<List<Contact>> queryContact(List<String> userIds) async { Future<List<ImUserList>> queryImUser(List<String> userIds) async {
if (db == null) { if (db == null) {
return Future.value(<Contact>[]); return Future.value(<ImUserList>[]);
} }
String sql = 'SELECT * FROM Contact WHERE userId IN (?) AND state = 0 AND isDelete = 0'; String query = 'SELECT * FROM ImUser WHERE mid IN (${userIds.map((mid) => "'$mid'").join(',')})';
return db.rawQuery(sql, userIds).then((value) { return db.rawQuery(query).then((value) {
return value.map((e) => Contact.fromJson(e)).toList(); return value.map((e) => ImUserList.fromJson(e)).toList();
}, onError: (error) { }, onError: (error) {
debugPrint("Contact_error: $error"); debugPrint("ImUser_error: $error");
}); });
} }
Future<Contact> queryContactById(String userId) async { Future<ImUserList> queryImUserById(String userId) async {
if (db == null) { if (db == null) {
return Future.value(); return Future.value();
} }
List<Contact> contact = await db.query("Contact", distinct: true, where: "userId = ?", whereArgs: [userId]) List<ImUserList> imUser = await db.query("ImUser",
.then((value) { distinct: true, where: "mid = ?", whereArgs: [userId]).then((value) {
return value.map((e) => Contact.fromJson(e)).toList(); return value.map((e) => ImUserList.fromJson(e)).toList();
}, onError: (error) { }, onError: (error) {
debugPrint("Contact_error: $error"); debugPrint("ImUser_error: $error");
}); });
return (contact?.isNotEmpty ?? false) ? contact.first : null; return (imUser?.isNotEmpty ?? false) ? imUser.first : null;
} }
final List<Migration> _migrations = []; final List<Migration> _migrations = [];
@ -178,5 +180,4 @@ class HxDatabase {
await migration.migrate(migrationDatabase); await migration.migrate(migrationDatabase);
} }
} }
} }

0
lib/im/im_search.dart

94
lib/im/im_view/im_page.dart

@ -4,9 +4,10 @@ import 'dart:collection';
import 'package:dio/dio.dart'; import 'package:dio/dio.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_easyloading/flutter_easyloading.dart'; import 'package:flutter_easyloading/flutter_easyloading.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:huixiang/generated/l10n.dart'; import 'package:huixiang/generated/l10n.dart';
import 'package:huixiang/im/database/contact.dart';
import 'package:huixiang/im/database/message.dart'; import 'package:huixiang/im/database/message.dart';
import 'package:huixiang/im/im_view/time_formatter.dart';
import 'package:huixiang/im/out/message.pb.dart'; import 'package:huixiang/im/out/message.pb.dart';
import 'package:huixiang/main.dart'; import 'package:huixiang/main.dart';
import 'package:huixiang/retrofit/data/base_data.dart'; import 'package:huixiang/retrofit/data/base_data.dart';
@ -17,9 +18,13 @@ import 'package:huixiang/utils/font_weight.dart';
import 'package:huixiang/view_widget/classic_header.dart'; import 'package:huixiang/view_widget/classic_header.dart';
import 'package:huixiang/view_widget/my_footer.dart'; import 'package:huixiang/view_widget/my_footer.dart';
import 'package:huixiang/view_widget/round_button.dart'; import 'package:huixiang/view_widget/round_button.dart';
import 'package:intl/intl.dart';
import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart';
import 'package:shared_preferences/shared_preferences.dart'; import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart';
import '../../retrofit/data/im_user_list.dart';
import '../../utils/flutter_utils.dart';
import '../../view_widget/custom_image.dart';
import 'on_chat_message.dart'; import 'on_chat_message.dart';
import 'on_chat_msg_instance.dart'; import 'on_chat_msg_instance.dart';
@ -36,6 +41,7 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
ApiService apiService; ApiService apiService;
int pageNum = 1; int pageNum = 1;
List<Message> messages = []; List<Message> messages = [];
Map<String, ImUserList> imUserList = {};
Map<String, int> msgNumber = { Map<String, int> msgNumber = {
"1": 0, "1": 0,
"2": 0, "2": 0,
@ -67,7 +73,8 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
loadMessageList(); loadMessageList();
SharedPreferences.getInstance().then((value) { SharedPreferences.getInstance().then((value) {
apiService = ApiService(Dio(), token: value.getString("token"), context: context); apiService =
ApiService(Dio(), token: value.getString("token"), context: context);
queryMsgStats(); queryMsgStats();
}); });
} }
@ -79,7 +86,6 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
} }
List<String> userIds = []; List<String> userIds = [];
Map<String, Contact> contactMap = {};
Map<String, Message> lastMessageMap = {}; Map<String, Message> lastMessageMap = {};
Stream streamSubscription; Stream streamSubscription;
@ -97,9 +103,9 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
lastMessageMap[message.fromId] = message; lastMessageMap[message.fromId] = message;
debugPrint("messages_records : ${message.toJson()}"); debugPrint("messages_records : ${message.toJson()}");
if (contactMap[message.fromId] == null) { // if (contactMap[message.fromId] == null) {
/// TODO: message.fromId request Api and setState // /// TODO: message.fromId request Api and setState
} // }
if (mounted) { if (mounted) {
setState(() {}); setState(() {});
} }
@ -112,23 +118,20 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
}); });
userIds = messages userIds = messages
.map((e) => e.toId != userId ? e.toId : e.fromId) .map((e) => e.toId != userId ? e.toId : e.fromId)
.toSet().where((element) => element != userId) .toSet()
.toList(); .where((element) => element != userId)
.toList(); //
List<ImUserList> contacts = (await hxDatabase.queryImUser(userIds)) ?? [];
lastMessageMap = groupBy(messages, (p0) => p0.toId != userId ? p0.toId : p0.fromId); if (contacts.isNotEmpty) imUserList = groupBy(contacts, (p0) => p0.mid);
List<Contact> contacts = await hxDatabase.queryContact(userIds); lastMessageMap =
if (contacts?.isEmpty ?? false) { groupBy(messages, (p0) => p0.toId != userId ? p0.toId : p0.fromId);
/// TODO: userIds request Api
} else {
List<String> queryUserIds = userIds.where((u) => contacts.where((c) => c.userId == u).isEmpty).toList();
/// TODO: queryUserIds request Api
}
contactMap = groupBy(contacts, (p0) => p0.userId);
if (mounted) { if (mounted) {
setState(() {}); setState(() {});
} }
queryMemberInfo(userIds);
} }
void updateLastMessage(String userId) async { void updateLastMessage(String userId) async {
@ -211,6 +214,25 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
EasyLoading.dismiss(); EasyLoading.dismiss();
} }
///
queryMemberInfo(List<String> mids) async {
BaseData<List<ImUserList>> baseData = await apiService.memberInfoByIds({
"mids": mids,
}).catchError((error) {
SmartDialog.showToast(AppUtils.dioErrorTypeToString(error.type),
alignment: Alignment.center);
});
if (baseData != null && baseData.isSuccess) {
baseData.data.forEach((element) async {
await hxDatabase.insertOrUpdateImUser(element.toJson());
});
imUserList = groupBy(baseData.data, (p0) => p0.mid);
setState(() {});
} else {
SmartDialog.showToast(baseData.msg, alignment: Alignment.center);
}
}
RefreshController _refreshController = RefreshController(); RefreshController _refreshController = RefreshController();
@override @override
@ -280,7 +302,8 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
onTap: () { onTap: () {
Navigator.of(context) Navigator.of(context)
.pushNamed('/router/chat_friend_group').then((value) { .pushNamed('/router/chat_friend_group')
.then((value) {
_refresh(); _refresh();
}); });
}, },
@ -377,10 +400,11 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
Navigator.of(context).pushNamed( Navigator.of(context).pushNamed(
'/router/chat_details_page', '/router/chat_details_page',
arguments: { arguments: {
"toId": userIds[position], "toUser": imUserList[userIds[position]],
}, },
).then((value) { ).then((value) {
updateLastMessage(userIds[position]); updateLastMessage(userIds[position]);
_refresh();
}); });
}, },
child: chatItem(userIds[position]), child: chatItem(userIds[position]),
@ -395,19 +419,16 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
padding: EdgeInsets.only(left: 16.w, right: 17.w, bottom: 18.h), padding: EdgeInsets.only(left: 16.w, right: 17.w, bottom: 18.h),
child: Row( child: Row(
children: [ children: [
// MImage( MImage(
// "", !imUserList.containsKey(userId)
// isCircle: true, ? null
// width: 40, : imUserList[userId]?.avatar ?? "",
// height: 40, isCircle: true,
// fit: BoxFit.cover,
// errorSrc: "assets/image/default_user.webp",
// fadeSrc: "assets/image/default_user.webp",
// ),
Image.asset(
"assets/image/fuka_zj.webp",
height: 54.h, height: 54.h,
width: 54.h, width: 54.h,
fit: BoxFit.cover,
errorSrc: "assets/image/fuka_zj.webp",
fadeSrc: "assets/image/fuka_zj.webp",
), ),
SizedBox( SizedBox(
width: 12.w, width: 12.w,
@ -420,7 +441,9 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
"喽哈 $userId", !imUserList.containsKey(userId)
? ""
: imUserList[userId]?.nickname ?? "",
// overflow: TextOverflow.fade, // overflow: TextOverflow.fade,
maxLines: 1, maxLines: 1,
style: TextStyle( style: TextStyle(
@ -431,7 +454,11 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
), ),
), ),
Text( Text(
"2021.03.08 13:22", lastMessageMap[userId]?.time != null
? TimeFormatter.formatTime(
DateTime.fromMillisecondsSinceEpoch(num.parse(
lastMessageMap[userId]?.time ?? "")))
: "",
style: TextStyle( style: TextStyle(
fontSize: 12.sp, fontSize: 12.sp,
color: Color(0xFFA29E9E), color: Color(0xFFA29E9E),
@ -447,7 +474,7 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
children: [ children: [
Expanded( Expanded(
child: Text( child: Text(
"新开的火锅店好吃得很", lastMessageMap[userId]?.content ?? "",
maxLines: 1, maxLines: 1,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
style: TextStyle( style: TextStyle(
@ -482,5 +509,4 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
), ),
); );
} }
} }

20
lib/im/im_view/time_formatter.dart

@ -0,0 +1,20 @@
import 'package:intl/intl.dart';
class TimeFormatter {
static String formatTime(DateTime time) {
final now = DateTime.now();
final diff = now.difference(time).inHours;
if (diff < 24) {
return '刚刚'; // 24
} else if (diff < 48) {
return '昨天'; //
} else if (diff < 72) {
return '前天'; //
} else if (time.year == now.year) {
return DateFormat('MM月dd日').format(time); //
} else {
return DateFormat('yyyy年MM月dd日').format(time); //
}
}
}

61
lib/retrofit/data/im_user_list.dart

@ -0,0 +1,61 @@
/// mid : "1379254113602109440"
/// nickname : "哈哈"
/// avatar : "https://pos.upload.lotus-wallet.com/admin/2022/11/d501d2cd-ffc0-49f2-967c-2e463462f500.jpeg"
/// phone : "13052919193"
/// isFollow : null
/// createTime : null
class ImUserList {
ImUserList({
String mid,
String nickname,
num isDelete,
String avatar,
String phone, }){
_mid = mid;
_nickname = nickname;
_isDelete = isDelete;
_avatar = avatar;
_phone = phone;
}
ImUserList.fromJson(dynamic json) {
_mid = json['mid'];
_nickname = json['nickname'];
_isDelete = json['isDelete'];
_avatar = json['avatar'];
_phone = json['phone'];
}
String _mid;
String _nickname;
num _isDelete;
String _avatar;
String _phone;
ImUserList copyWith({ String mid,
String nickname,
num isDelete,
String avatar,
String phone,
}) => ImUserList( mid: mid ?? _mid,
nickname: nickname ?? _nickname,
isDelete: isDelete ?? _isDelete,
avatar: avatar ?? _avatar,
phone: phone ?? _phone,
);
String get mid => _mid;
String get nickname => _nickname;
num get isDelete => _isDelete;
String get avatar => _avatar;
String get phone => _phone;
Map<String, dynamic> toJson() {
final map = <String, dynamic>{};
map['mid'] = _mid;
map['nickname'] = _nickname;
map['isDelete'] = _isDelete;
map['avatar'] = _avatar;
map['phone'] = _phone;
return map;
}
}

10
lib/retrofit/retrofit_api.dart

@ -39,6 +39,7 @@ import 'data/goods_category.dart';
import 'data/headlines_list.dart'; import 'data/headlines_list.dart';
import 'data/headlines_list_details.dart'; import 'data/headlines_list_details.dart';
import 'data/home_rank.dart'; import 'data/home_rank.dart';
import 'data/im_user_list.dart';
import 'data/invitation_list.dart'; import 'data/invitation_list.dart';
import 'data/invoice_list.dart'; import 'data/invoice_list.dart';
import 'data/invoices_detail_info.dart'; import 'data/invoices_detail_info.dart';
@ -653,4 +654,13 @@ abstract class ApiService {
/// ///
@GET("invoice/detail{id}") @GET("invoice/detail{id}")
Future<BaseData<InvoicesDetailInfo>> invoiceDetail(@Path("id") String id); Future<BaseData<InvoicesDetailInfo>> invoiceDetail(@Path("id") String id);
///
@POST("/member/memberInfoByIds")
Future<BaseData<List<ImUserList>>> memberInfoByIds(@Body() Map<String, dynamic> param);
///Im关键字搜索
@GET("/member/memberSearch?keyword={keyword}")
Future<BaseData<List<ImUserList>>> memberSearch(
@Path("keyword") String keyword);
} }

48
lib/retrofit/retrofit_api.g.dart

@ -2528,4 +2528,52 @@ class _ApiService implements ApiService {
); );
return value; return value;
} }
@override
Future<BaseData<List<ImUserList>>> memberInfoByIds(param) async {
ArgumentError.checkNotNull(param, 'param');
const _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _data = <String, dynamic>{};
_data.addAll(param ?? <String, dynamic>{});
final _result = await _dio.request<Map<String, dynamic>>(
'/member/memberInfoByIds',
queryParameters: queryParameters,
options: RequestOptions(
method: 'POST',
headers: <String, dynamic>{},
extra: _extra,
baseUrl: baseUrl),
data: _data);
final value = BaseData<List<ImUserList>>.fromJson(
_result.data,
(json) => (json as List<dynamic>)
.map<ImUserList>((i) => ImUserList.fromJson(i as Map<String, dynamic>))
.toList());
return value;
}
@override
Future<BaseData<List<ImUserList>>> memberSearch(keyword) async {
ArgumentError.checkNotNull(keyword, 'keyword');
const _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _data = <String, dynamic>{};
final _result = await _dio.request<Map<String, dynamic>>(
'/member/memberSearch?keyword=$keyword',
queryParameters: queryParameters,
options: RequestOptions(
method: 'GET',
headers: <String, dynamic>{},
extra: _extra,
baseUrl: baseUrl),
data: _data);
final value = BaseData<List<ImUserList>>.fromJson(
_result.data,
(json) => (json as List<dynamic>)
.map<ImUserList>(
(i) => ImUserList.fromJson(i as Map<String, dynamic>))
.toList());
return value;
}
} }

Loading…
Cancel
Save