import 'package:dio/dio.dart'; import 'package:flutter/material.dart'; import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:huixiang/constant.dart'; import 'package:huixiang/generated/l10n.dart'; import 'package:huixiang/im/database/message.dart'; import 'package:huixiang/main.dart'; import 'package:huixiang/retrofit/data/base_data.dart'; import 'package:huixiang/retrofit/retrofit_api.dart'; import 'package:huixiang/utils/font_weight.dart'; import 'package:huixiang/view_widget/classic_header.dart'; import 'package:huixiang/view_widget/my_footer.dart'; import 'package:huixiang/view_widget/round_button.dart'; import 'package:pull_to_refresh/pull_to_refresh.dart'; import 'package:shared_preferences/shared_preferences.dart'; import 'package:flutter_screenutil/flutter_screenutil.dart'; import '../../retrofit/data/im_user.dart'; import '../../utils/flutter_utils.dart'; import '../../view_widget/custom_image.dart'; import 'on_chat_message.dart'; import 'on_chat_msg_instance.dart'; class IMPage extends StatefulWidget { IMPage(Key key) : super(key: key); @override State createState() { return _IMPage(); } } class _IMPage extends State implements OnChatMessage { ApiService apiService; int pageNum = 1; List messages = []; Map msgNumber = { "1": 0, "2": 0, "3": 0, "4": 0, "5": 0, "6": 0, }; int state = 0; List userIds = []; Map lastMessageMap = {}; Map unreadCountMap = {}; Map contactMap = {}; @override void onMessage(txt) { // SmartDialog.showToast("列表 $txt", alignment: Alignment.center); } @override void dispose() { super.dispose(); OnChatMsgInstance.instance.onChatMessage = null; socketClient.removeCallback(socketClient.userId); } @override void initState() { super.initState(); OnChatMsgInstance.instance.onChatMessage = this; initSocketClient(); SharedPreferences.getInstance().then((value) { apiService = ApiService(Dio(), token: value.getString("token"), context: context); // queryMsgStats(); }); } initSocketClient() async { SharedPreferences shared = await SharedPreferences.getInstance(); String userId = shared.getString("userId"); socketClient.addCallback(userId, (Message message) { if (userIds.contains(message.fromId)) { userIds.remove(message.fromId); } userIds.insert(0, message.fromId); lastMessageMap[message.fromId] = message; listenerRefresh(message); }); loadMessageList(); } _refresh() { pageNum = 1; loadMessageList(); // queryMsgStats(); } listenerRefresh(Message message) async { SharedPreferences shared = await SharedPreferences.getInstance(); String userId = shared.getString("userId"); await sortConversation(lastMessageMap); await queryUnreadCount(userIds, userId); debugPrint("messages_records : ${message.toJson()}"); if (contactMap[message.fromId] == null) { queryMemberInfo([message.fromId]); return; } refreshState(); } loadMessageList() async { SharedPreferences shared = await SharedPreferences.getInstance(); String userId = shared.getString("userId"); messages = await hxDatabase.queryList(userId); lastMessageMap = messages.lGroupBy((p0) => p0.toId != userId ? p0.toId : p0.fromId).mGroupItem(key: (p1) => num.parse(p1.time)); await sortConversation(lastMessageMap); await queryUnreadCount(userIds, userId); await queryImUserInfo(userIds); refreshState(); } /// update conversation by time sort sortConversation(lastMessageMap) async { SharedPreferences shared = await SharedPreferences.getInstance(); String userId = shared.getString("userId"); List sortMessages = lastMessageMap.values.toList(); sortMessages.sort((a, b) => (num.parse(b.time)).compareTo(num.parse(a.time))); userIds = sortMessages .map((e) => e.toId != userId ? e.toId : e.fromId) .toSet() .where((element) => element != userId) .toList(); } /// update conversation unreadcount queryUnreadCount(userIds, userId) async { unreadCountMap = await hxDatabase.messageUnreadCount(userIds, userId); debugPrint("unreadCount: $unreadCountMap"); } /// update imuser info by mids queryImUserInfo(userIds) async { List contacts = (await hxDatabase.queryImUser(userIds)) ?? []; if (contacts?.isEmpty ?? true) { await queryMemberInfo(userIds); return; } else { List queryUserIds = userIds.where((u) => contacts.where((c) => c.mid == u).isEmpty).toList(); if (queryUserIds.isNotEmpty) { await queryMemberInfo(queryUserIds); return; } } contactMap = contacts.lGroupBy((p0) => p0.mid).mGroupItem(); } /// update one conversation last message ,and update conversation sort void updateLastMessage(String userId) async { Message message = await hxDatabase.lastMessage(userId); debugPrint("lastmessage: $userId ${message.content} ${message.toJson()}"); if (message != null) { lastMessageMap[userId] = message; await sortConversation(lastMessageMap); refreshState(); } } void updateUnreadCount() async { SharedPreferences shared = await SharedPreferences.getInstance(); String userId = shared.getString("userId"); unreadCountMap = await hxDatabase.messageUnreadCount(userIds, userId); refreshState(); } refreshState() { if(_refreshController.isRefresh)_refreshController.refreshCompleted(); if (mounted) setState(() {}); } // queryMessage() async { // BaseData> baseData = await apiService.msgList({ // "pageNum": pageNum, // "pageSize": 10, // "searchKey": "", // "state": "", // "typed": "" // }).catchError((onError) { // _refreshController.loadFailed(); // _refreshController.refreshFailed(); // }); // // if (baseData != null && baseData.isSuccess) { // if (pageNum == 1) { // messages.clear(); // } // List message = []; // message.addAll(baseData.data.list); // message.forEach((element) { // if (element.typed == 2 || element.typed == 3) { // messages.add(element); // } // }); // _refreshController.loadComplete(); // _refreshController.refreshCompleted(); // if (mounted) setState(() {}); // if (pageNum * 10 > int.tryParse(baseData.data.total)) { // _refreshController.loadNoData(); // } else { // pageNum += 1; // } // } else { // _refreshController.loadFailed(); // _refreshController.refreshFailed(); // } // } // queryMsgStats() async { // if (apiService == null) { // SharedPreferences value = await SharedPreferences.getInstance(); // apiService = ApiService( // Dio(), // context: context, // token: value.getString("token"), // ); // } // BaseData> baseData = await apiService.stats().catchError((onError) { // debugPrint("stats.error: $onError"); // }); // if (baseData != null && baseData.isSuccess) { // setState(() { // msgNumber.forEach((key, value) { // msgNumber[key] = 0; // }); // baseData.data.forEach((element) { // if (msgNumber.containsKey(element.name)) { // msgNumber[element.name] = element.number; // } // }); // }); // _refreshController.loadComplete(); // _refreshController.refreshCompleted(); // } // EasyLoading.dismiss(); // } ///批量查询用户信息 queryMemberInfo(List mids) async { if (mids.isEmpty) { return; } BaseData> baseData = await apiService.memberInfoByIds({ "mids": mids, }).catchError((error) { SmartDialog.showToast(AppUtils.dioErrorTypeToString(error.type), alignment: Alignment.center); }); if (baseData != null && baseData.isSuccess) { if (baseData.data.isNotEmpty) { baseData.data.forEach((element) async { await hxDatabase.insertOrUpdateImUser(element.toJson()); }); baseData.data.forEach((element) { if (contactMap[element.mid] == null) { contactMap[element.mid] = element; } }); refreshState(); } } else { SmartDialog.showToast(baseData.msg, alignment: Alignment.center); } } final RefreshController _refreshController = RefreshController(); @override Widget build(BuildContext context) { return Scaffold( backgroundColor: Color(0xFFFFFFFF), body: SmartRefresher( enablePullDown: true, enablePullUp: false, header: MyHeader(), physics: BouncingScrollPhysics(), footer: CustomFooter( loadStyle: LoadStyle.ShowWhenLoading, builder: (BuildContext context, LoadStatus mode) { return (messages.length == 0) ? Container() : MyFooter(mode); }, ), controller: _refreshController, onRefresh: _refresh, onLoading: () { _refresh(); }, child: Container( // color: Colors.white, decoration: BoxDecoration( gradient: LinearGradient( begin: Alignment.topCenter, end: Alignment.bottomCenter, colors: [ Color(0xFFD9FFDE), Color(0xFFD9FFDE), Color(0xFFFFFFFF), Color(0xFFFFFFFF), ], stops: [0, 0.2, 0.4, 1], ), ), child: SingleChildScrollView( physics: BouncingScrollPhysics(), child: Container( padding: EdgeInsets.only(bottom: 30.h), child: Column( children: [ Container( padding: EdgeInsets.only( top: MediaQuery.of(context).padding.top + 12.h, bottom: 15.h, right: 16.w, left: 16.w), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, crossAxisAlignment: CrossAxisAlignment.center, children: [ Expanded( child: Text( S.of(context).xiaoxi, style: TextStyle( color: Colors.black, fontSize: 18.sp, fontWeight: MyFontWeight.bold, ), ), ), GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { Navigator.of(context) .pushNamed('/router/chat_friend_group').then((value) { _refresh(); }); }, child: Container( padding: EdgeInsets.all(12), decoration: BoxDecoration( color: Color(0xFFFFFFFF), borderRadius: BorderRadius.circular(20.r), ), child: Image.asset( "assets/image/friend_grouping.webp", fit: BoxFit.fill, height: 14.h, width: 14.h, ), ), ), ], ), ), imPageSearch(), chatList(), // buildMessage(),fgg ], ), ), ), ), ), ); } ///搜索 Widget imPageSearch() { return GestureDetector( behavior: HitTestBehavior.opaque, onTap:(){ Navigator.of(context).pushNamed('/router/im_search'); }, child: Container( margin: EdgeInsets.fromLTRB(16.w, 0, 16.w, 0), padding: EdgeInsets.symmetric(vertical: 13.h), decoration: BoxDecoration( color: Color(0xFFFDFCFC), borderRadius: BorderRadius.circular(4), ), child: Row( children: [ Padding( padding: EdgeInsets.only(left: 15.w, right: 5.w), child: Image.asset( "assets/image/icon_search.webp", width: 14.h, height: 14.h, color: Color(0xFF353535), ), ), Text( "搜索", style: TextStyle( color: Color(0xFFA29E9E), fontSize: 16.sp, fontWeight: MyFontWeight.regular, ), ), ], ) ), ); } ///聊天列表 Widget chatList() { return Container( child: ListView.builder( padding: EdgeInsets.only(top: 16), itemCount: userIds.length, shrinkWrap: true, physics: NeverScrollableScrollPhysics(), itemBuilder: (context, position) { return GestureDetector( behavior: HitTestBehavior.opaque, onTap: () { if (userIds[position] == sharedPreferences.getString("userId")) { SmartDialog.showToast("不能跟自己聊天", alignment: Alignment.center); return; } Navigator.of(context).pushNamed( '/router/chat_details_page', arguments: { "toUser": contactMap[userIds[position]], }, ).then((value) { unreadCountMap[userIds[position]] = 0; updateLastMessage(userIds[position]); }); }, child: chatItem(userIds[position]), ); }, ), ); } Widget chatItem(userId) { return Container( padding: EdgeInsets.only(left: 16.w, right: 17.w, bottom: 18.h), child: Row( children: [ MImage( !contactMap.containsKey(userId) ? null : contactMap[userId]?.avatar ?? "", isCircle: true, height: 54.h, width: 54.h, fit: BoxFit.cover, errorSrc: "assets/image/fuka_zj.webp", fadeSrc: "assets/image/fuka_zj.webp", ), SizedBox( width: 12.w, ), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Expanded( child: Text( !contactMap.containsKey(userId) ? "" : contactMap[userId]?.nickname ?? "", // overflow: TextOverflow.fade, maxLines: 1, style: TextStyle( fontSize: 16.sp, color: Color(0xFF060606), fontWeight: MyFontWeight.semi_bold, ), ), ), Text( lastMessageMap[userId]?.time != null ? AppUtils.timeFormatter( DateTime.fromMillisecondsSinceEpoch(num.parse( lastMessageMap[userId]?.time ?? ""))) : "", style: TextStyle( fontSize: 12.sp, color: Color(0xFFA29E9E), fontWeight: MyFontWeight.regular, ), ), ], ), SizedBox( height: 7.h, ), Row( children: [ Expanded( child: Text( lastMessageMap[userId]?.content ?? "", maxLines: 1, overflow: TextOverflow.ellipsis, style: TextStyle( fontSize: 12.sp, color: Color(0xFF353535), fontWeight: MyFontWeight.regular, ), ), ), if (unreadCountMap[userId] != null && unreadCountMap[userId] > 0) Container( width: 16, height: 16, decoration: BoxDecoration( borderRadius: BorderRadius.circular(100), color: Color(0xFFFF441A), ), child: RoundButton( text: "${unreadCountMap[userId]}", textColor: Colors.white, fontWeight: MyFontWeight.regular, backgroup: Color(0xFFFF441A), fontSize: 10.sp, radius: 100, ), ), ], ), ], ), ), ], ), ); } }