feat: 未读消息计数
This commit is contained in:
@ -539,4 +539,7 @@ class Api {
|
|||||||
/// 关闭会话
|
/// 关闭会话
|
||||||
static const String removeSession =
|
static const String removeSession =
|
||||||
'${HttpString.tUrl}/session_svr/v1/session_svr/remove_session';
|
'${HttpString.tUrl}/session_svr/v1/session_svr/remove_session';
|
||||||
|
|
||||||
|
/// 消息未读数
|
||||||
|
static const String unread = '${HttpString.tUrl}/x/im/web/msgfeed/unread';
|
||||||
}
|
}
|
||||||
|
|||||||
@ -225,4 +225,16 @@ class MsgHttp {
|
|||||||
return {'status': false, 'date': [], 'msg': res.data['message']};
|
return {'status': false, 'date': [], 'msg': res.data['message']};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future unread() async {
|
||||||
|
var res = await Request().get(Api.unread);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': res.data['data'],
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {'status': false, 'date': [], 'msg': res.data['message']};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/http/msg.dart';
|
import 'package:pilipala/http/msg.dart';
|
||||||
import 'package:pilipala/models/msg/account.dart';
|
import 'package:pilipala/models/msg/account.dart';
|
||||||
@ -7,6 +8,38 @@ class WhisperController extends GetxController {
|
|||||||
RxList<SessionList> sessionList = <SessionList>[].obs;
|
RxList<SessionList> sessionList = <SessionList>[].obs;
|
||||||
RxList<AccountListModel> accountList = <AccountListModel>[].obs;
|
RxList<AccountListModel> accountList = <AccountListModel>[].obs;
|
||||||
bool isLoading = false;
|
bool isLoading = false;
|
||||||
|
RxList noticesList = [
|
||||||
|
{
|
||||||
|
'icon': Icons.message_outlined,
|
||||||
|
'title': '回复我的',
|
||||||
|
'path': '',
|
||||||
|
'count': 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon': Icons.alternate_email,
|
||||||
|
'title': '@ 我的',
|
||||||
|
'path': '',
|
||||||
|
'count': 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon': Icons.thumb_up_outlined,
|
||||||
|
'title': '收到的赞',
|
||||||
|
'path': '',
|
||||||
|
'count': 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'icon': Icons.notifications_none_outlined,
|
||||||
|
'title': '系统通知',
|
||||||
|
'path': '',
|
||||||
|
'count': 0,
|
||||||
|
}
|
||||||
|
].obs;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
unread();
|
||||||
|
super.onInit();
|
||||||
|
}
|
||||||
|
|
||||||
Future querySessionList(String? type) async {
|
Future querySessionList(String? type) async {
|
||||||
if (isLoading) return;
|
if (isLoading) return;
|
||||||
@ -77,4 +110,16 @@ class WhisperController extends GetxController {
|
|||||||
sessionList.removeWhere((p0) => p0.talkerId == talkerId);
|
sessionList.removeWhere((p0) => p0.talkerId == talkerId);
|
||||||
sessionList.refresh();
|
sessionList.refresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 消息未读数
|
||||||
|
void unread() async {
|
||||||
|
var res = await MsgHttp.unread();
|
||||||
|
if (res['status']) {
|
||||||
|
noticesList[0]['count'] = res['data']['reply'];
|
||||||
|
noticesList[1]['count'] = res['data']['at'];
|
||||||
|
noticesList[2]['count'] = res['data']['like'];
|
||||||
|
noticesList[3]['count'] = res['data']['sys_msg'];
|
||||||
|
noticesList.refresh();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:easy_debounce/easy_throttle.dart';
|
import 'package:easy_debounce/easy_throttle.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/common/constants.dart';
|
||||||
import 'package:pilipala/common/skeleton/skeleton.dart';
|
import 'package:pilipala/common/skeleton/skeleton.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/utils/utils.dart';
|
import 'package:pilipala/utils/utils.dart';
|
||||||
@ -44,147 +45,145 @@ class _WhisperPageState extends State<WhisperPage> {
|
|||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: const Text('消息'),
|
title: const Text('消息'),
|
||||||
),
|
),
|
||||||
body: Column(
|
body: RefreshIndicator(
|
||||||
children: [
|
onRefresh: () async {
|
||||||
// LayoutBuilder(
|
_whisperController.unread();
|
||||||
// builder: (BuildContext context, BoxConstraints constraints) {
|
await _whisperController.onRefresh();
|
||||||
// // 在这里根据父级容器的约束条件构建小部件树
|
},
|
||||||
// return Padding(
|
child: SingleChildScrollView(
|
||||||
// padding: const EdgeInsets.only(left: 20, right: 20),
|
controller: _scrollController,
|
||||||
// child: SizedBox(
|
child: Column(
|
||||||
// height: constraints.maxWidth / 5,
|
children: [
|
||||||
// child: GridView.count(
|
LayoutBuilder(
|
||||||
// primary: false,
|
builder: (BuildContext context, BoxConstraints constraints) {
|
||||||
// crossAxisCount: 4,
|
// 在这里根据父级容器的约束条件构建小部件树
|
||||||
// padding: const EdgeInsets.all(0),
|
return Padding(
|
||||||
// childAspectRatio: 1.25,
|
padding: const EdgeInsets.only(left: 20, right: 20),
|
||||||
// children: [
|
child: SizedBox(
|
||||||
// Column(
|
height: constraints.maxWidth / 4,
|
||||||
// crossAxisAlignment: CrossAxisAlignment.center,
|
child: Obx(
|
||||||
// mainAxisAlignment: MainAxisAlignment.center,
|
() => GridView.count(
|
||||||
// children: [
|
primary: false,
|
||||||
// SizedBox(
|
crossAxisCount: 4,
|
||||||
// width: 36,
|
padding: const EdgeInsets.all(0),
|
||||||
// height: 36,
|
children: [
|
||||||
// child: IconButton(
|
..._whisperController.noticesList.map((element) {
|
||||||
// style: ButtonStyle(
|
return InkWell(
|
||||||
// padding:
|
onTap: () => {},
|
||||||
// MaterialStateProperty.all(EdgeInsets.zero),
|
onLongPress: () {},
|
||||||
// backgroundColor:
|
borderRadius: StyleString.mdRadius,
|
||||||
// MaterialStateProperty.resolveWith((states) {
|
child: Column(
|
||||||
// return Theme.of(context)
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
// .colorScheme
|
children: [
|
||||||
// .primary
|
Badge(
|
||||||
// .withOpacity(0.1);
|
isLabelVisible: element['count'] > 0,
|
||||||
// }),
|
label: Text(element['count'] > 99
|
||||||
// ),
|
? '99+'
|
||||||
// onPressed: () {},
|
: element['count'].toString()),
|
||||||
// icon: Icon(
|
child: Padding(
|
||||||
// Icons.message_outlined,
|
padding: const EdgeInsets.all(10),
|
||||||
// size: 18,
|
child: Icon(
|
||||||
// color: Theme.of(context).colorScheme.primary,
|
element['icon'],
|
||||||
// ),
|
size: 21,
|
||||||
// ),
|
color: Theme.of(context)
|
||||||
// ),
|
.colorScheme
|
||||||
// const SizedBox(height: 6),
|
.primary,
|
||||||
// const Text('回复我的', style: TextStyle(fontSize: 13))
|
),
|
||||||
// ],
|
),
|
||||||
// ),
|
),
|
||||||
// ],
|
const SizedBox(height: 4),
|
||||||
// ),
|
Text(element['title'])
|
||||||
// ),
|
],
|
||||||
// );
|
|
||||||
// },
|
|
||||||
// ),
|
|
||||||
Expanded(
|
|
||||||
child: RefreshIndicator(
|
|
||||||
onRefresh: () async {
|
|
||||||
await _whisperController.onRefresh();
|
|
||||||
},
|
|
||||||
child: SingleChildScrollView(
|
|
||||||
controller: _scrollController,
|
|
||||||
child: FutureBuilder(
|
|
||||||
future: _futureBuilderFuture,
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (snapshot.connectionState == ConnectionState.done) {
|
|
||||||
Map? data = snapshot.data;
|
|
||||||
if (data != null && data['status']) {
|
|
||||||
RxList sessionList = _whisperController.sessionList;
|
|
||||||
return Obx(
|
|
||||||
() => sessionList.isEmpty
|
|
||||||
? const SizedBox()
|
|
||||||
: ListView.separated(
|
|
||||||
itemCount: sessionList.length,
|
|
||||||
shrinkWrap: true,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
itemBuilder: (_, int i) {
|
|
||||||
return SessionItem(
|
|
||||||
sessionItem: sessionList[i],
|
|
||||||
changeFucCall: () =>
|
|
||||||
sessionList.refresh(),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
separatorBuilder:
|
|
||||||
(BuildContext context, int index) {
|
|
||||||
return Divider(
|
|
||||||
indent: 72,
|
|
||||||
endIndent: 20,
|
|
||||||
height: 6,
|
|
||||||
color: Colors.grey.withOpacity(0.1),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
}).toList(),
|
||||||
// 请求错误
|
],
|
||||||
return Center(
|
),
|
||||||
child: Text(data?['msg'] ?? '请求异常'),
|
),
|
||||||
);
|
),
|
||||||
}
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
FutureBuilder(
|
||||||
|
future: _futureBuilderFuture,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
|
Map? data = snapshot.data;
|
||||||
|
if (data != null && data['status']) {
|
||||||
|
RxList sessionList = _whisperController.sessionList;
|
||||||
|
return Obx(
|
||||||
|
() => sessionList.isEmpty
|
||||||
|
? const SizedBox()
|
||||||
|
: ListView.separated(
|
||||||
|
itemCount: sessionList.length,
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemBuilder: (_, int i) {
|
||||||
|
return SessionItem(
|
||||||
|
sessionItem: sessionList[i],
|
||||||
|
changeFucCall: () => sessionList.refresh(),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder:
|
||||||
|
(BuildContext context, int index) {
|
||||||
|
return Divider(
|
||||||
|
indent: 72,
|
||||||
|
endIndent: 20,
|
||||||
|
height: 6,
|
||||||
|
color: Colors.grey.withOpacity(0.1),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// 骨架屏
|
// 请求错误
|
||||||
return ListView.builder(
|
return Center(
|
||||||
itemCount: 15,
|
child: Text(data?['msg'] ?? '请求异常'),
|
||||||
shrinkWrap: true,
|
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
|
||||||
itemBuilder: (context, int i) {
|
|
||||||
return Skeleton(
|
|
||||||
child: ListTile(
|
|
||||||
leading: Container(
|
|
||||||
width: 45,
|
|
||||||
height: 45,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.onInverseSurface,
|
|
||||||
borderRadius: BorderRadius.circular(25),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
title: Container(
|
|
||||||
width: 100,
|
|
||||||
height: 14,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.onInverseSurface,
|
|
||||||
),
|
|
||||||
subtitle: Container(
|
|
||||||
width: 80,
|
|
||||||
height: 14,
|
|
||||||
color: Theme.of(context)
|
|
||||||
.colorScheme
|
|
||||||
.onInverseSurface,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
} else {
|
||||||
),
|
// 骨架屏
|
||||||
|
return ListView.builder(
|
||||||
|
itemCount: 15,
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
|
itemBuilder: (context, int i) {
|
||||||
|
return Skeleton(
|
||||||
|
child: ListTile(
|
||||||
|
leading: Container(
|
||||||
|
width: 45,
|
||||||
|
height: 45,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onInverseSurface,
|
||||||
|
borderRadius: BorderRadius.circular(25),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Container(
|
||||||
|
width: 100,
|
||||||
|
height: 14,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onInverseSurface,
|
||||||
|
),
|
||||||
|
subtitle: Container(
|
||||||
|
width: 80,
|
||||||
|
height: 14,
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onInverseSurface,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
],
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user