|
|
|
@ -1,10 +1,11 @@
|
|
|
|
|
import 'package:dio/dio.dart'; |
|
|
|
|
import 'package:flutter/material.dart'; |
|
|
|
|
import 'package:flutter_slidable/flutter_slidable.dart'; |
|
|
|
|
import 'package:flutter_easyloading/flutter_easyloading.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/retrofit/data/msg_stats.dart'; |
|
|
|
|
import 'package:huixiang/main.dart'; |
|
|
|
|
import 'package:huixiang/retrofit/data/base_data.dart'; |
|
|
|
|
import 'package:huixiang/retrofit/retrofit_api.dart'; |
|
|
|
@ -16,6 +17,7 @@ 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 '../../retrofit/data/page.dart'; |
|
|
|
|
import '../../utils/flutter_utils.dart'; |
|
|
|
|
import '../../view_widget/custom_image.dart'; |
|
|
|
|
import 'on_chat_message.dart'; |
|
|
|
@ -49,6 +51,7 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
|
|
|
|
|
Map<String, ImUser> contactMap = {}; |
|
|
|
|
int insertIndex = 0; |
|
|
|
|
String selfUserId; |
|
|
|
|
final RefreshController _refreshController = RefreshController(); |
|
|
|
|
|
|
|
|
|
@override |
|
|
|
|
void onMessage(txt) { |
|
|
|
@ -72,7 +75,7 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
|
|
|
|
|
|
|
|
|
|
SharedPreferences.getInstance().then((value) { |
|
|
|
|
apiService = ApiService(Dio(), token: value.getString("token"), context: context); |
|
|
|
|
// queryMsgStats(); |
|
|
|
|
queryMsgStats(); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -96,7 +99,7 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
|
|
|
|
|
_refresh() { |
|
|
|
|
pageNum = 1; |
|
|
|
|
loadMessageList(); |
|
|
|
|
// queryMsgStats(); |
|
|
|
|
queryMsgStats(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
listenerRefresh(Message message) async { |
|
|
|
@ -218,7 +221,34 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
final RefreshController _refreshController = RefreshController(); |
|
|
|
|
///App消息 统计各类消息数量 |
|
|
|
|
queryMsgStats() async { |
|
|
|
|
if (apiService == null) { |
|
|
|
|
SharedPreferences value = await SharedPreferences.getInstance(); |
|
|
|
|
apiService = ApiService( |
|
|
|
|
Dio(), |
|
|
|
|
context: context, |
|
|
|
|
token: value.getString("token"), |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
BaseData<List<MsgStats>> baseData = |
|
|
|
|
await apiService.stats().catchError((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(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@override |
|
|
|
|
Widget build(BuildContext context) { |
|
|
|
@ -305,7 +335,56 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
|
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
imPageSearch(), |
|
|
|
|
GestureDetector( |
|
|
|
|
behavior: HitTestBehavior.opaque, |
|
|
|
|
onTap: (){ |
|
|
|
|
Navigator.of(context).pushNamed('/router/system_notice').then((value) { |
|
|
|
|
setState(() { |
|
|
|
|
msgNumber["2"] = 0; |
|
|
|
|
msgNumber["3"] = 0; |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
child:messageItem("assets/image/icon_system_message_new.webp", S.of(context).xitongxiaoxi, (msgNumber["2"]+msgNumber["3"]).toString()), |
|
|
|
|
), |
|
|
|
|
GestureDetector( |
|
|
|
|
behavior: HitTestBehavior.opaque, |
|
|
|
|
onTap: (){ |
|
|
|
|
Navigator.of(context).pushNamed('/router/system_details', |
|
|
|
|
arguments: {"msgType": 4}).then((value) { |
|
|
|
|
setState(() { |
|
|
|
|
msgNumber["4"] = 0; |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
child:messageItem("assets/image/icon_gz.webp", S.of(context).guanzhu,msgNumber["4"].toString()), |
|
|
|
|
), |
|
|
|
|
GestureDetector( |
|
|
|
|
behavior: HitTestBehavior.opaque, |
|
|
|
|
onTap: (){ |
|
|
|
|
Navigator.of(context).pushNamed('/router/system_details', |
|
|
|
|
arguments: {"msgType": 6}).then((value) { |
|
|
|
|
setState(() { |
|
|
|
|
msgNumber["6"] = 0; |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
child:messageItem("assets/image/icon_pl.webp", S.of(context).pinglun, msgNumber["6"].toString()), |
|
|
|
|
), |
|
|
|
|
GestureDetector( |
|
|
|
|
behavior: HitTestBehavior.opaque, |
|
|
|
|
onTap: (){ |
|
|
|
|
Navigator.of(context).pushNamed('/router/system_details', |
|
|
|
|
arguments: {"msgType": 5}).then((value) { |
|
|
|
|
setState(() { |
|
|
|
|
msgNumber["5"] = 0; |
|
|
|
|
}); |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
child: messageItem("assets/image/icon_z.webp", S.of(context).dianzan, msgNumber["5"].toString()), |
|
|
|
|
), |
|
|
|
|
chatList(), |
|
|
|
|
SizedBox(height:100.h) |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
@ -324,7 +403,7 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
|
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
child: Container( |
|
|
|
|
margin: EdgeInsets.fromLTRB(16.w, 0, 16.w, 0), |
|
|
|
|
margin: EdgeInsets.fromLTRB(16.w, 0, 16.w, 16.h), |
|
|
|
|
padding: EdgeInsets.symmetric(vertical: 13.h), |
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
color: Color(0xFFFDFCFC), |
|
|
|
@ -355,36 +434,86 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
|
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
bool _isDelEnter = false; |
|
|
|
|
Map<String, ScrollController> idsController = {}; |
|
|
|
|
String lastScrollId; |
|
|
|
|
double lastScrollOffset = 0; |
|
|
|
|
bool _isScrollOpen = false; |
|
|
|
|
|
|
|
|
|
///聊天列表 |
|
|
|
|
Widget chatList() { |
|
|
|
|
return Container( |
|
|
|
|
child: SlidableAutoCloseBehavior( |
|
|
|
|
child: ListView( |
|
|
|
|
padding: EdgeInsets.only(top: 16), |
|
|
|
|
return ListView( |
|
|
|
|
padding: EdgeInsets.only(top:8.h), |
|
|
|
|
shrinkWrap: true, |
|
|
|
|
physics: NeverScrollableScrollPhysics(), |
|
|
|
|
children: conversationIds.map((e) { |
|
|
|
|
ScrollController scrollController; |
|
|
|
|
if (idsController.containsKey(e)) |
|
|
|
|
scrollController = idsController[e]; |
|
|
|
|
else { |
|
|
|
|
scrollController = ScrollController(); |
|
|
|
|
idsController[e] = scrollController; |
|
|
|
|
} |
|
|
|
|
scrollController.addListener(() { |
|
|
|
|
if (scrollController.offset > 0) { |
|
|
|
|
if (lastScrollId != null && lastScrollId != e) |
|
|
|
|
idsController[lastScrollId].jumpTo(0); |
|
|
|
|
if(lastScrollOffset < scrollController.offset){ |
|
|
|
|
scrollController.jumpTo(scrollController.position.maxScrollExtent); |
|
|
|
|
_isScrollOpen = true; |
|
|
|
|
}else if(lastScrollOffset > scrollController.offset && _isScrollOpen){ |
|
|
|
|
scrollController.jumpTo(0); |
|
|
|
|
} |
|
|
|
|
lastScrollId = e; |
|
|
|
|
// scrollController.animateTo( |
|
|
|
|
// lastScrollOffset == scrollController.position.maxScrollExtent |
|
|
|
|
// ? 0 |
|
|
|
|
// : scrollController.position.maxScrollExtent, |
|
|
|
|
// duration: Duration(milliseconds: 100), |
|
|
|
|
// curve: Curves.ease); |
|
|
|
|
lastScrollOffset = scrollController.offset; |
|
|
|
|
} else { |
|
|
|
|
if (lastScrollId == e) { |
|
|
|
|
setState(() { |
|
|
|
|
_isDelEnter = false; |
|
|
|
|
_isScrollOpen = false; |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
int position = conversationIds.indexOf(e); |
|
|
|
|
return ClipRRect( |
|
|
|
|
// borderRadius: BorderRadius.all(Radius.circular(4)), |
|
|
|
|
child: Slidable( |
|
|
|
|
groupTag: true, |
|
|
|
|
endActionPane: ActionPane( |
|
|
|
|
extentRatio:0.16, |
|
|
|
|
motion: ScrollMotion(), |
|
|
|
|
return SingleChildScrollView( |
|
|
|
|
physics: ClampingScrollPhysics(), |
|
|
|
|
controller: scrollController, |
|
|
|
|
scrollDirection: Axis.horizontal, |
|
|
|
|
child: Row( |
|
|
|
|
children: [ |
|
|
|
|
CustomSlidableAction( |
|
|
|
|
onPressed: (bc) { |
|
|
|
|
showDelDialog(conversationIds[position]); |
|
|
|
|
GestureDetector( |
|
|
|
|
behavior: HitTestBehavior.opaque, |
|
|
|
|
onTap: () { |
|
|
|
|
Navigator.of(context).pushNamed( |
|
|
|
|
'/router/chat_details_page', |
|
|
|
|
arguments: { |
|
|
|
|
"toUser": contactMap[conversationIds[position]], |
|
|
|
|
}, |
|
|
|
|
).then((value) { |
|
|
|
|
unreadCountMap[conversationIds[position]] = 0; |
|
|
|
|
updateLastMessage(conversationIds[position]); |
|
|
|
|
_refresh(); |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
backgroundColor: Color(0xFFFB312B), |
|
|
|
|
foregroundColor: Colors.white, |
|
|
|
|
child: chatItem(conversationIds[position]), |
|
|
|
|
), |
|
|
|
|
GestureDetector( |
|
|
|
|
child: Container( |
|
|
|
|
color: Colors.red, |
|
|
|
|
height: double.infinity, |
|
|
|
|
alignment: Alignment.center, |
|
|
|
|
padding: |
|
|
|
|
EdgeInsets.symmetric(vertical: 25.h, horizontal: 14.w), |
|
|
|
|
child: Text( |
|
|
|
|
S.of(context).shanchu, |
|
|
|
|
_isDelEnter && lastScrollId == e |
|
|
|
|
? "删除并清空" |
|
|
|
|
: S.of(context).shanchu, |
|
|
|
|
style: TextStyle( |
|
|
|
|
color: Colors.white, |
|
|
|
|
fontSize: 14.sp, |
|
|
|
@ -392,30 +521,29 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
|
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
child: GestureDetector( |
|
|
|
|
behavior: HitTestBehavior.opaque, |
|
|
|
|
onTap: () { |
|
|
|
|
Navigator.of(context).pushNamed( |
|
|
|
|
'/router/chat_details_page', |
|
|
|
|
arguments: { |
|
|
|
|
"toUser": contactMap[conversationIds[position]], |
|
|
|
|
}, |
|
|
|
|
).then((value) { |
|
|
|
|
unreadCountMap[conversationIds[position]] = 0; |
|
|
|
|
updateLastMessage(conversationIds[position]); |
|
|
|
|
onTap: () async{ |
|
|
|
|
// showDelDialog(conversationIds[position]); |
|
|
|
|
if (_isDelEnter) { |
|
|
|
|
await hxDatabase.deleteByUser(conversationIds[position]); |
|
|
|
|
lastScrollId = null; |
|
|
|
|
_refresh(); |
|
|
|
|
} else { |
|
|
|
|
Future.delayed(Duration(milliseconds: 100), () { |
|
|
|
|
idsController[lastScrollId].animateTo( |
|
|
|
|
idsController[lastScrollId].position.maxScrollExtent, |
|
|
|
|
duration: Duration(milliseconds: 100), |
|
|
|
|
curve: Curves.ease); |
|
|
|
|
}); |
|
|
|
|
} |
|
|
|
|
setState(() { |
|
|
|
|
_isDelEnter = !_isDelEnter; |
|
|
|
|
}); |
|
|
|
|
}, |
|
|
|
|
child: chatItem(conversationIds[position]), |
|
|
|
|
), |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
); |
|
|
|
|
}).toList(), |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -424,6 +552,7 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
|
|
|
|
|
padding: EdgeInsets.only( |
|
|
|
|
left: 16.w, right: 17.w, bottom: 18.h, |
|
|
|
|
), |
|
|
|
|
width: MediaQuery.of(context).size.width, |
|
|
|
|
child: Row( |
|
|
|
|
children: [ |
|
|
|
|
MImage( |
|
|
|
@ -518,6 +647,66 @@ class _IMPage extends State<IMPage> implements OnChatMessage {
|
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
Widget messageItem(img, title, messageNum) { |
|
|
|
|
return Container( |
|
|
|
|
padding: EdgeInsets.only(top:8.h,bottom:8.h, left:16.w,right:15.w), |
|
|
|
|
child: Column( |
|
|
|
|
children: [ |
|
|
|
|
Row( |
|
|
|
|
children: [ |
|
|
|
|
Image.asset( |
|
|
|
|
img, |
|
|
|
|
fit: BoxFit.fill, |
|
|
|
|
), |
|
|
|
|
SizedBox( |
|
|
|
|
width: 12.w, |
|
|
|
|
), |
|
|
|
|
Text( |
|
|
|
|
title, |
|
|
|
|
style: TextStyle( |
|
|
|
|
fontSize: 14.sp, |
|
|
|
|
color: Color(0xFF060606), |
|
|
|
|
fontWeight: MyFontWeight.semi_bold, |
|
|
|
|
), |
|
|
|
|
), |
|
|
|
|
Spacer(), |
|
|
|
|
if(messageNum != "0") |
|
|
|
|
((double.tryParse(messageNum) < 100)? |
|
|
|
|
Container( |
|
|
|
|
width: 16, |
|
|
|
|
height: 16, |
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
borderRadius: BorderRadius.circular(100), |
|
|
|
|
color: Color(0xFFFF441A), |
|
|
|
|
), |
|
|
|
|
child: RoundButton( |
|
|
|
|
text:messageNum, |
|
|
|
|
textColor: Colors.white, |
|
|
|
|
fontWeight: MyFontWeight.regular, |
|
|
|
|
backgroup: Color(0xFFFF441A), |
|
|
|
|
fontSize: 10.sp, |
|
|
|
|
radius: 100, |
|
|
|
|
)): |
|
|
|
|
Container( |
|
|
|
|
padding: EdgeInsets.symmetric(horizontal:4.w,vertical:2.h), |
|
|
|
|
decoration: BoxDecoration( |
|
|
|
|
borderRadius: BorderRadius.circular(100), |
|
|
|
|
color: Color(0xFFFF441A), |
|
|
|
|
), |
|
|
|
|
child: RoundButton( |
|
|
|
|
text:"99+", |
|
|
|
|
textColor: Colors.white, |
|
|
|
|
fontWeight: MyFontWeight.regular, |
|
|
|
|
backgroup: Color(0xFFFF441A), |
|
|
|
|
fontSize: 10.sp, |
|
|
|
|
radius: 100, |
|
|
|
|
))), |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
], |
|
|
|
|
), |
|
|
|
|
); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
///确认删除弹窗 |
|
|
|
|
showDelDialog(conversationId) { |
|
|
|
|