mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-05-24 18:18:38 +00:00
opt: unread & zan grpc & readlist open with browser (#852)
* opt: unread * opt: zan grpc * feat: readlist open with browser
This commit is contained in:
committed by
GitHub
parent
8d34e6f340
commit
72734d4b4e
@@ -62,6 +62,7 @@ class GrpcUrl {
|
|||||||
static const keywordBlockingAdd = '$im2/KeywordBlockingAdd';
|
static const keywordBlockingAdd = '$im2/KeywordBlockingAdd';
|
||||||
static const keywordBlockingDelete = '$im2/KeywordBlockingDelete';
|
static const keywordBlockingDelete = '$im2/KeywordBlockingDelete';
|
||||||
static const syncFetchSessionMsgs = '$im/SyncFetchSessionMsgs';
|
static const syncFetchSessionMsgs = '$im/SyncFetchSessionMsgs';
|
||||||
|
static const getTotalUnread = '$im/GetTotalUnread';
|
||||||
}
|
}
|
||||||
|
|
||||||
class GrpcRepo {
|
class GrpcRepo {
|
||||||
|
|||||||
@@ -199,4 +199,13 @@ class ImGrpc {
|
|||||||
KeywordBlockingDeleteReply.fromBuffer,
|
KeywordBlockingDeleteReply.fromBuffer,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Future<LoadingState<RspTotalUnread>> getTotalUnread(
|
||||||
|
{int? unreadType}) {
|
||||||
|
return GrpcRepo.request(
|
||||||
|
GrpcUrl.getTotalUnread,
|
||||||
|
ReqTotalUnread(unreadType: unreadType, showUnfollowList: 1),
|
||||||
|
RspTotalUnread.fromBuffer,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -476,11 +476,11 @@ class Api {
|
|||||||
|
|
||||||
// 获取未读私信数
|
// 获取未读私信数
|
||||||
// https://api.vc.bilibili.com/session_svr/v1/session_svr/single_unread
|
// https://api.vc.bilibili.com/session_svr/v1/session_svr/single_unread
|
||||||
static const String msgUnread =
|
// static const String msgUnread =
|
||||||
'${HttpString.tUrl}/session_svr/v1/session_svr/single_unread';
|
// '${HttpString.tUrl}/session_svr/v1/session_svr/single_unread';
|
||||||
|
|
||||||
// 获取消息中心未读信息
|
// 获取消息中心未读信息
|
||||||
static const String msgFeedUnread = '/x/msgfeed/unread';
|
// static const String msgFeedUnread = '/x/msgfeed/unread';
|
||||||
//https://api.bilibili.com/x/msgfeed/reply?platform=web&build=0&mobi_app=web
|
//https://api.bilibili.com/x/msgfeed/reply?platform=web&build=0&mobi_app=web
|
||||||
static const String msgFeedReply = '/x/msgfeed/reply';
|
static const String msgFeedReply = '/x/msgfeed/reply';
|
||||||
//https://api.bilibili.com/x/msgfeed/at?platform=web&build=0&mobi_app=web
|
//https://api.bilibili.com/x/msgfeed/at?platform=web&build=0&mobi_app=web
|
||||||
|
|||||||
@@ -103,18 +103,6 @@ class MsgHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static Future msgFeedUnread() async {
|
|
||||||
var res = await Request().get(Api.msgFeedUnread);
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': res.data['data'],
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {'status': false, 'msg': res.data['message']};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static Future createDynamic({
|
static Future createDynamic({
|
||||||
dynamic mid,
|
dynamic mid,
|
||||||
dynamic dynIdStr, // repost dyn
|
dynamic dynIdStr, // repost dyn
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
enum MsgUnReadType { pm, reply, at, like, sysMsg }
|
enum MsgUnReadType {
|
||||||
|
pm('私信'),
|
||||||
|
reply('回复我的'),
|
||||||
|
at('@我'),
|
||||||
|
like('收到的赞'),
|
||||||
|
sysMsg('系统通知');
|
||||||
|
|
||||||
extension MsgUnReadTypeExt on MsgUnReadType {
|
final String title;
|
||||||
String get title => const ['私信', '回复我的', '@我', '收到的赞', '系统通知'][index];
|
const MsgUnReadType(this.title);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,26 +1,15 @@
|
|||||||
class MsgFeedUnread {
|
import 'package:fixnum/fixnum.dart';
|
||||||
MsgFeedUnread({
|
|
||||||
this.at = 0,
|
|
||||||
this.chat = 0,
|
|
||||||
this.like = 0,
|
|
||||||
this.reply = 0,
|
|
||||||
this.sysMsg = 0,
|
|
||||||
this.up = 0,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
class MsgFeedUnread {
|
||||||
int at = 0;
|
int at = 0;
|
||||||
int chat = 0;
|
|
||||||
int like = 0;
|
int like = 0;
|
||||||
int reply = 0;
|
int reply = 0;
|
||||||
int sysMsg = 0;
|
int sysMsg = 0;
|
||||||
int up = 0;
|
|
||||||
|
|
||||||
MsgFeedUnread.fromJson(Map<String, dynamic> json) {
|
MsgFeedUnread.fromJson(Map<String, Int64> json) {
|
||||||
at = json['at'] ?? 0;
|
at = json['at']?.toInt() ?? 0;
|
||||||
chat = json['chat'] ?? 0;
|
like = json['like']?.toInt() ?? 0;
|
||||||
like = json['like'] ?? 0;
|
reply = json['reply']?.toInt() ?? 0;
|
||||||
reply = json['reply'] ?? 0;
|
sysMsg = json['sys_msg']?.toInt() ?? 0;
|
||||||
sysMsg = json['sys_msg'] ?? 0;
|
|
||||||
up = json['up'] ?? 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import 'package:PiliPlus/common/skeleton/video_card_h.dart';
|
|||||||
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
import 'package:PiliPlus/common/widgets/image/network_img_layer.dart';
|
||||||
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
|
import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart';
|
||||||
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
import 'package:PiliPlus/common/widgets/refresh_indicator.dart';
|
||||||
|
import 'package:PiliPlus/http/constants.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/models/common/image_type.dart';
|
import 'package:PiliPlus/models/common/image_type.dart';
|
||||||
import 'package:PiliPlus/models/dynamics/article_list/list.dart';
|
import 'package:PiliPlus/models/dynamics/article_list/list.dart';
|
||||||
@@ -10,6 +11,7 @@ import 'package:PiliPlus/models/space_article/item.dart';
|
|||||||
import 'package:PiliPlus/pages/article_list/controller.dart';
|
import 'package:PiliPlus/pages/article_list/controller.dart';
|
||||||
import 'package:PiliPlus/pages/article_list/widgets/item.dart';
|
import 'package:PiliPlus/pages/article_list/widgets/item.dart';
|
||||||
import 'package:PiliPlus/utils/grid.dart';
|
import 'package:PiliPlus/utils/grid.dart';
|
||||||
|
import 'package:PiliPlus/utils/page_utils.dart';
|
||||||
import 'package:PiliPlus/utils/utils.dart';
|
import 'package:PiliPlus/utils/utils.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
@@ -188,6 +190,16 @@ class _ArticleListPageState extends State<ArticleListPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
actions: [
|
||||||
|
IconButton(
|
||||||
|
tooltip: '浏览器打开',
|
||||||
|
onPressed: () {
|
||||||
|
PageUtils.inAppWebview(
|
||||||
|
'${HttpString.baseUrl}/read/readlist/rl${_controller.id}');
|
||||||
|
},
|
||||||
|
icon: const Icon(Icons.open_in_browser_outlined, size: 19),
|
||||||
|
)
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:PiliPlus/grpc/dyn.dart';
|
import 'package:PiliPlus/grpc/dyn.dart';
|
||||||
import 'package:PiliPlus/http/api.dart';
|
import 'package:PiliPlus/grpc/im.dart';
|
||||||
import 'package:PiliPlus/http/init.dart';
|
|
||||||
import 'package:PiliPlus/models/common/dynamic/dynamic_badge_mode.dart';
|
import 'package:PiliPlus/models/common/dynamic/dynamic_badge_mode.dart';
|
||||||
import 'package:PiliPlus/models/common/msg/msg_unread_type.dart';
|
import 'package:PiliPlus/models/common/msg/msg_unread_type.dart';
|
||||||
import 'package:PiliPlus/models/common/nav_bar_config.dart';
|
import 'package:PiliPlus/models/common/nav_bar_config.dart';
|
||||||
@@ -83,92 +82,51 @@ class MainController extends GetxController {
|
|||||||
msgUnReadCount.value = '';
|
msgUnReadCount.value = '';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
bool shouldCheckPM = msgUnReadTypes.contains(MsgUnReadType.pm);
|
int count = 0;
|
||||||
bool shouldCheckFeed =
|
final res = await ImGrpc.getTotalUnread();
|
||||||
shouldCheckPM ? msgUnReadTypes.length > 1 : msgUnReadTypes.isNotEmpty;
|
if (res.isSuccess) {
|
||||||
List res = await Future.wait([
|
final data = res.data;
|
||||||
if (shouldCheckPM) _queryPMUnread(),
|
if (msgUnReadTypes.length == MsgUnReadType.values.length) {
|
||||||
if (shouldCheckFeed) _queryMsgFeedUnread(),
|
count = data.hasTotalUnread() ? data.totalUnread : 0;
|
||||||
]);
|
} else {
|
||||||
dynamic count = 0;
|
final msgUnread = data.msgFeedUnread.unread;
|
||||||
if (shouldCheckPM && res.firstOrNull?['status'] == true) {
|
|
||||||
count = (res.first['data'] as int?) ?? 0;
|
|
||||||
}
|
|
||||||
if ((shouldCheckPM.not && res.firstOrNull?['status'] == true) ||
|
|
||||||
(shouldCheckPM && res.getOrNull(1)?['status'] == true)) {
|
|
||||||
int index = shouldCheckPM.not ? 0 : 1;
|
|
||||||
dynamic data = res[index]['data'];
|
|
||||||
for (final item in msgUnReadTypes) {
|
for (final item in msgUnReadTypes) {
|
||||||
switch (item) {
|
switch (item) {
|
||||||
case MsgUnReadType.pm:
|
case MsgUnReadType.pm:
|
||||||
|
final pmUnread = data.sessionSingleUnread;
|
||||||
|
count += (pmUnread.followUnread +
|
||||||
|
pmUnread.unfollowUnread +
|
||||||
|
pmUnread.dustbinUnread)
|
||||||
|
.toInt();
|
||||||
break;
|
break;
|
||||||
case MsgUnReadType.reply:
|
case MsgUnReadType.reply:
|
||||||
count += (data['reply'] as int?) ?? 0;
|
count += msgUnread['reply']?.toInt() ?? 0;
|
||||||
break;
|
break;
|
||||||
case MsgUnReadType.at:
|
case MsgUnReadType.at:
|
||||||
count += (data['at'] as int?) ?? 0;
|
count += msgUnread['at']?.toInt() ?? 0;
|
||||||
break;
|
break;
|
||||||
case MsgUnReadType.like:
|
case MsgUnReadType.like:
|
||||||
count += (data['like'] as int?) ?? 0;
|
count += msgUnread['like']?.toInt() ?? 0;
|
||||||
break;
|
break;
|
||||||
case MsgUnReadType.sysMsg:
|
case MsgUnReadType.sysMsg:
|
||||||
count += (data['sys_msg'] as int?) ?? 0;
|
count += msgUnread['sys_msg']?.toInt() ?? 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
count = count == 0
|
|
||||||
? ''
|
|
||||||
: count > 99
|
|
||||||
? '99+'
|
|
||||||
: count.toString();
|
|
||||||
if (msgUnReadCount.value == count) {
|
|
||||||
msgUnReadCount.refresh();
|
|
||||||
} else {
|
|
||||||
msgUnReadCount.value = count;
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
debugPrint('failed to get unread count: $e');
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Future _queryPMUnread() async {
|
final countStr = count == 0
|
||||||
try {
|
? ''
|
||||||
dynamic res = await Request().get(Api.msgUnread);
|
: count > 99
|
||||||
if (res.data['code'] == 0) {
|
? '99+'
|
||||||
return {
|
: count.toString();
|
||||||
'status': true,
|
if (msgUnReadCount.value == countStr) {
|
||||||
'data': ((res.data['data']?['unfollow_unread'] as int?) ?? 0) +
|
msgUnReadCount.refresh();
|
||||||
((res.data['data']?['follow_unread'] as int?) ?? 0),
|
} else {
|
||||||
};
|
msgUnReadCount.value = countStr;
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future _queryMsgFeedUnread() async {
|
|
||||||
if (isLogin.value.not) {
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
dynamic res = await Request().get(Api.msgFeedUnread);
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {
|
|
||||||
'status': true,
|
|
||||||
'data': res.data['data'],
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
'status': false,
|
|
||||||
'msg': res.data['message'],
|
|
||||||
};
|
|
||||||
}
|
|
||||||
} catch (_) {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> getUnreadDynamic() async {
|
Future<void> getUnreadDynamic() async {
|
||||||
|
|||||||
@@ -22,13 +22,16 @@ class ZanButtonGrpc extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
|
class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
|
||||||
|
bool get isLike => widget.replyItem.replyControl.action == $fixnum.Int64.ONE;
|
||||||
|
bool get isDislike =>
|
||||||
|
widget.replyItem.replyControl.action == $fixnum.Int64.TWO;
|
||||||
|
|
||||||
Future<void> onHateReply() async {
|
Future<void> onHateReply() async {
|
||||||
feedBack();
|
feedBack();
|
||||||
final int oid = widget.replyItem.oid.toInt();
|
final int oid = widget.replyItem.oid.toInt();
|
||||||
final int rpid = widget.replyItem.id.toInt();
|
final int rpid = widget.replyItem.id.toInt();
|
||||||
// 1 已点赞 2 不喜欢 0 未操作
|
// 1 已点赞 2 不喜欢 0 未操作
|
||||||
final int action =
|
final int action = isDislike ? 0 : 2;
|
||||||
widget.replyItem.replyControl.action.toInt() != 2 ? 2 : 0;
|
|
||||||
final res = await ReplyHttp.hateReply(
|
final res = await ReplyHttp.hateReply(
|
||||||
type: widget.replyItem.type.toInt(),
|
type: widget.replyItem.type.toInt(),
|
||||||
action: action == 2 ? 1 : 0,
|
action: action == 2 ? 1 : 0,
|
||||||
@@ -37,13 +40,9 @@ class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
|
|||||||
);
|
);
|
||||||
// SmartDialog.dismiss();
|
// SmartDialog.dismiss();
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
SmartDialog.showToast(
|
SmartDialog.showToast(isDislike ? '取消踩' : '点踩成功');
|
||||||
widget.replyItem.replyControl.action.toInt() != 2 ? '点踩成功' : '取消踩');
|
|
||||||
if (action == 2) {
|
if (action == 2) {
|
||||||
if (widget.replyItem.replyControl.action.toInt() == 1) {
|
if (isLike) widget.replyItem.like -= $fixnum.Int64.ONE;
|
||||||
widget.replyItem.like =
|
|
||||||
$fixnum.Int64(widget.replyItem.like.toInt() - 1);
|
|
||||||
}
|
|
||||||
widget.replyItem.replyControl.action = $fixnum.Int64.TWO;
|
widget.replyItem.replyControl.action = $fixnum.Int64.TWO;
|
||||||
} else {
|
} else {
|
||||||
widget.replyItem.replyControl.action = $fixnum.Int64.ZERO;
|
widget.replyItem.replyControl.action = $fixnum.Int64.ZERO;
|
||||||
@@ -60,8 +59,7 @@ class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
|
|||||||
final int oid = widget.replyItem.oid.toInt();
|
final int oid = widget.replyItem.oid.toInt();
|
||||||
final int rpid = widget.replyItem.id.toInt();
|
final int rpid = widget.replyItem.id.toInt();
|
||||||
// 1 已点赞 2 不喜欢 0 未操作
|
// 1 已点赞 2 不喜欢 0 未操作
|
||||||
final int action =
|
final int action = isLike ? 0 : 1;
|
||||||
widget.replyItem.replyControl.action.toInt() != 1 ? 1 : 0;
|
|
||||||
final res = await ReplyHttp.likeReply(
|
final res = await ReplyHttp.likeReply(
|
||||||
type: widget.replyItem.type.toInt(),
|
type: widget.replyItem.type.toInt(),
|
||||||
oid: oid,
|
oid: oid,
|
||||||
@@ -69,15 +67,12 @@ class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
|
|||||||
action: action,
|
action: action,
|
||||||
);
|
);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
SmartDialog.showToast(
|
SmartDialog.showToast(isLike ? '取消赞' : '点赞成功');
|
||||||
widget.replyItem.replyControl.action.toInt() != 1 ? '点赞成功' : '取消赞');
|
|
||||||
if (action == 1) {
|
if (action == 1) {
|
||||||
widget.replyItem.like =
|
widget.replyItem.like += $fixnum.Int64.ONE;
|
||||||
$fixnum.Int64(widget.replyItem.like.toInt() + 1);
|
|
||||||
widget.replyItem.replyControl.action = $fixnum.Int64.ONE;
|
widget.replyItem.replyControl.action = $fixnum.Int64.ONE;
|
||||||
} else {
|
} else {
|
||||||
widget.replyItem.like =
|
widget.replyItem.like -= $fixnum.Int64.ONE;
|
||||||
$fixnum.Int64(widget.replyItem.like.toInt() - 1);
|
|
||||||
widget.replyItem.replyControl.action = $fixnum.Int64.ZERO;
|
widget.replyItem.replyControl.action = $fixnum.Int64.ZERO;
|
||||||
}
|
}
|
||||||
setState(() {});
|
setState(() {});
|
||||||
@@ -115,16 +110,12 @@ class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
|
|||||||
style: _style,
|
style: _style,
|
||||||
onPressed: () => handleState(onHateReply),
|
onPressed: () => handleState(onHateReply),
|
||||||
child: Icon(
|
child: Icon(
|
||||||
widget.replyItem.replyControl.action.toInt() == 2
|
isDislike
|
||||||
? FontAwesomeIcons.solidThumbsDown
|
? FontAwesomeIcons.solidThumbsDown
|
||||||
: FontAwesomeIcons.thumbsDown,
|
: FontAwesomeIcons.thumbsDown,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: widget.replyItem.replyControl.action.toInt() == 2
|
color: isDislike ? primary : color,
|
||||||
? primary
|
semanticLabel: isDislike ? '已踩' : '点踩',
|
||||||
: color,
|
|
||||||
semanticLabel: widget.replyItem.replyControl.action.toInt() == 2
|
|
||||||
? '已踩'
|
|
||||||
: '点踩',
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -136,17 +127,12 @@ class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
Icon(
|
Icon(
|
||||||
widget.replyItem.replyControl.action.toInt() == 1
|
isLike
|
||||||
? FontAwesomeIcons.solidThumbsUp
|
? FontAwesomeIcons.solidThumbsUp
|
||||||
: FontAwesomeIcons.thumbsUp,
|
: FontAwesomeIcons.thumbsUp,
|
||||||
size: 16,
|
size: 16,
|
||||||
color: widget.replyItem.replyControl.action.toInt() == 1
|
color: isLike ? primary : color,
|
||||||
? primary
|
semanticLabel: isLike ? '已赞' : '点赞',
|
||||||
: color,
|
|
||||||
semanticLabel:
|
|
||||||
widget.replyItem.replyControl.action.toInt() == 1
|
|
||||||
? '已赞'
|
|
||||||
: '点赞',
|
|
||||||
),
|
),
|
||||||
const SizedBox(width: 4),
|
const SizedBox(width: 4),
|
||||||
AnimatedSwitcher(
|
AnimatedSwitcher(
|
||||||
@@ -158,9 +144,7 @@ class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
|
|||||||
child: Text(
|
child: Text(
|
||||||
Utils.numFormat(widget.replyItem.like.toInt()),
|
Utils.numFormat(widget.replyItem.like.toInt()),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
color: widget.replyItem.replyControl.action.toInt() == 1
|
color: isLike ? primary : color,
|
||||||
? primary
|
|
||||||
: color,
|
|
||||||
fontSize: theme.textTheme.labelSmall!.fontSize,
|
fontSize: theme.textTheme.labelSmall!.fontSize,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -2,12 +2,11 @@ import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart'
|
|||||||
show Offset, Session, SessionMainReply, SessionPageType, ThreeDotItem;
|
show Offset, Session, SessionMainReply, SessionPageType, ThreeDotItem;
|
||||||
import 'package:PiliPlus/grpc/im.dart';
|
import 'package:PiliPlus/grpc/im.dart';
|
||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/http/msg.dart';
|
|
||||||
import 'package:PiliPlus/models/msg/msgfeed_unread.dart';
|
import 'package:PiliPlus/models/msg/msgfeed_unread.dart';
|
||||||
import 'package:PiliPlus/pages/common/common_whisper_controller.dart';
|
import 'package:PiliPlus/pages/common/common_whisper_controller.dart';
|
||||||
import 'package:PiliPlus/utils/storage.dart';
|
import 'package:PiliPlus/utils/storage.dart';
|
||||||
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:protobuf/protobuf.dart' show PbMap;
|
import 'package:protobuf/protobuf.dart' show PbMap;
|
||||||
|
|
||||||
@@ -15,7 +14,8 @@ class WhisperController extends CommonWhisperController<SessionMainReply> {
|
|||||||
@override
|
@override
|
||||||
SessionPageType sessionPageType = SessionPageType.SESSION_PAGE_TYPE_HOME;
|
SessionPageType sessionPageType = SessionPageType.SESSION_PAGE_TYPE_HOME;
|
||||||
|
|
||||||
late final List msgFeedTopItems;
|
late final List<({bool enabled, IconData icon, String name, String route})>
|
||||||
|
msgFeedTopItems;
|
||||||
late final RxList<int> unreadCounts;
|
late final RxList<int> unreadCounts;
|
||||||
|
|
||||||
PbMap<int, Offset>? offset;
|
PbMap<int, Offset>? offset;
|
||||||
@@ -29,44 +29,46 @@ class WhisperController extends CommonWhisperController<SessionMainReply> {
|
|||||||
final disableLikeMsg =
|
final disableLikeMsg =
|
||||||
GStorage.setting.get(SettingBoxKey.disableLikeMsg, defaultValue: false);
|
GStorage.setting.get(SettingBoxKey.disableLikeMsg, defaultValue: false);
|
||||||
msgFeedTopItems = [
|
msgFeedTopItems = [
|
||||||
{
|
const (
|
||||||
"name": "回复我的",
|
name: "回复我的",
|
||||||
"icon": Icons.message_outlined,
|
icon: Icons.message_outlined,
|
||||||
"route": "/replyMe",
|
route: "/replyMe",
|
||||||
"enabled": true,
|
enabled: true,
|
||||||
},
|
),
|
||||||
{
|
const (
|
||||||
"name": "@我",
|
name: "@我",
|
||||||
"icon": Icons.alternate_email_outlined,
|
icon: Icons.alternate_email_outlined,
|
||||||
"route": "/atMe",
|
route: "/atMe",
|
||||||
"enabled": true,
|
enabled: true,
|
||||||
},
|
),
|
||||||
{
|
(
|
||||||
"name": "收到的赞",
|
name: "收到的赞",
|
||||||
"icon": Icons.favorite_border_outlined,
|
icon: Icons.favorite_border_outlined,
|
||||||
"route": "/likeMe",
|
route: "/likeMe",
|
||||||
"enabled": !disableLikeMsg,
|
enabled: !disableLikeMsg,
|
||||||
},
|
),
|
||||||
{
|
const (
|
||||||
"name": "系统通知",
|
name: "系统通知",
|
||||||
"icon": Icons.notifications_none_outlined,
|
icon: Icons.notifications_none_outlined,
|
||||||
"route": "/sysMsg",
|
route: "/sysMsg",
|
||||||
"enabled": true,
|
enabled: true,
|
||||||
},
|
),
|
||||||
];
|
];
|
||||||
unreadCounts =
|
unreadCounts = List.filled(msgFeedTopItems.length, 0).obs;
|
||||||
List.generate(msgFeedTopItems.length, (index) => 0).toList().obs;
|
|
||||||
queryMsgFeedUnread();
|
queryMsgFeedUnread();
|
||||||
queryData();
|
queryData();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> queryMsgFeedUnread() async {
|
Future<void> queryMsgFeedUnread() async {
|
||||||
var res = await MsgHttp.msgFeedUnread();
|
var res = await ImGrpc.getTotalUnread(unreadType: 2);
|
||||||
if (res['status']) {
|
if (res.isSuccess) {
|
||||||
final data = MsgFeedUnread.fromJson(res['data']);
|
final data = MsgFeedUnread.fromJson(res.data.msgFeedUnread.unread);
|
||||||
unreadCounts.value = [data.reply, data.at, data.like, data.sysMsg];
|
final unreadCounts = [data.reply, data.at, data.like, data.sysMsg];
|
||||||
|
if (!listEquals(this.unreadCounts, unreadCounts)) {
|
||||||
|
this.unreadCounts.value = unreadCounts;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
SmartDialog.showToast(res['msg']);
|
res.toast();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ class _WhisperPageState extends State<WhisperPage> {
|
|||||||
radius: 22,
|
radius: 22,
|
||||||
backgroundColor: theme.colorScheme.onInverseSurface,
|
backgroundColor: theme.colorScheme.onInverseSurface,
|
||||||
child: Icon(
|
child: Icon(
|
||||||
_controller.msgFeedTopItems[index]['icon'],
|
_controller.msgFeedTopItems[index].icon,
|
||||||
size: 20,
|
size: 20,
|
||||||
color: theme.colorScheme.primary,
|
color: theme.colorScheme.primary,
|
||||||
),
|
),
|
||||||
@@ -164,20 +164,20 @@ class _WhisperPageState extends State<WhisperPage> {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 6),
|
const SizedBox(height: 6),
|
||||||
Text(
|
Text(
|
||||||
_controller.msgFeedTopItems[index]['name'],
|
_controller.msgFeedTopItems[index].name,
|
||||||
style: const TextStyle(fontSize: 13),
|
style: const TextStyle(fontSize: 13),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (!_controller.msgFeedTopItems[index]['enabled']) {
|
if (!_controller.msgFeedTopItems[index].enabled) {
|
||||||
SmartDialog.showToast('已禁用');
|
SmartDialog.showToast('已禁用');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_controller.unreadCounts[index] = 0;
|
_controller.unreadCounts[index] = 0;
|
||||||
Get.toNamed(
|
Get.toNamed(
|
||||||
_controller.msgFeedTopItems[index]['route'],
|
_controller.msgFeedTopItems[index].route,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -20,8 +20,7 @@ import 'package:get/get.dart';
|
|||||||
|
|
||||||
class ChatItem extends StatelessWidget {
|
class ChatItem extends StatelessWidget {
|
||||||
static MsgType msgTypeFromValue(int value) {
|
static MsgType msgTypeFromValue(int value) {
|
||||||
return MsgType.values.firstWhere((e) => e.value == value,
|
return MsgType.valueOf(value) ?? MsgType.EN_INVALID_MSG_TYPE;
|
||||||
orElse: () => MsgType.EN_INVALID_MSG_TYPE);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const ChatItem({
|
const ChatItem({
|
||||||
|
|||||||
@@ -57,23 +57,6 @@ extension ListExt<T> on List<T>? {
|
|||||||
T getOrElse(int index, {required T Function() orElse}) {
|
T getOrElse(int index, {required T Function() orElse}) {
|
||||||
return getOrNull(index) ?? orElse();
|
return getOrNull(index) ?? orElse();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool eq(List<T>? other) {
|
|
||||||
if (this == null) {
|
|
||||||
return other == null;
|
|
||||||
}
|
|
||||||
if (other == null || this!.length != other.length) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
for (int index = 0; index < this!.length; index += 1) {
|
|
||||||
if (this![index] != other[index]) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool ne(List<T>? other) => !eq(other);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final _regExp = RegExp("^(http:)?//", caseSensitive: false);
|
final _regExp = RegExp("^(http:)?//", caseSensitive: false);
|
||||||
@@ -128,17 +111,6 @@ extension ColorExtension on Color {
|
|||||||
assert(amount >= 0 && amount <= 1, 'Amount must be between 0 and 1');
|
assert(amount >= 0 && amount <= 1, 'Amount must be between 0 and 1');
|
||||||
return Color.lerp(this, Colors.black, amount)!;
|
return Color.lerp(this, Colors.black, amount)!;
|
||||||
}
|
}
|
||||||
|
|
||||||
Color blend(Color color, [double fraction = 0.5]) {
|
|
||||||
assert(fraction >= 0 && fraction <= 1, 'Fraction must be between 0 and 1');
|
|
||||||
final blendedRed = (red * (1 - fraction) + color.red * fraction).toInt();
|
|
||||||
final blendedGreen =
|
|
||||||
(green * (1 - fraction) + color.green * fraction).toInt();
|
|
||||||
final blendedBlue = (blue * (1 - fraction) + color.blue * fraction).toInt();
|
|
||||||
final blendedAlpha =
|
|
||||||
(alpha * (1 - fraction) + color.alpha * fraction).toInt();
|
|
||||||
return Color.fromARGB(blendedAlpha, blendedRed, blendedGreen, blendedBlue);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extension BrightnessExt on Brightness {
|
extension BrightnessExt on Brightness {
|
||||||
|
|||||||
Reference in New Issue
Block a user