mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-04-20 03:06:59 +08: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 keywordBlockingDelete = '$im2/KeywordBlockingDelete';
|
||||
static const syncFetchSessionMsgs = '$im/SyncFetchSessionMsgs';
|
||||
static const getTotalUnread = '$im/GetTotalUnread';
|
||||
}
|
||||
|
||||
class GrpcRepo {
|
||||
|
||||
@@ -199,4 +199,13 @@ class ImGrpc {
|
||||
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
|
||||
static const String msgUnread =
|
||||
'${HttpString.tUrl}/session_svr/v1/session_svr/single_unread';
|
||||
// static const String msgUnread =
|
||||
// '${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
|
||||
static const String msgFeedReply = '/x/msgfeed/reply';
|
||||
//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({
|
||||
dynamic mid,
|
||||
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 {
|
||||
String get title => const ['私信', '回复我的', '@我', '收到的赞', '系统通知'][index];
|
||||
final String title;
|
||||
const MsgUnReadType(this.title);
|
||||
}
|
||||
|
||||
@@ -1,26 +1,15 @@
|
||||
class MsgFeedUnread {
|
||||
MsgFeedUnread({
|
||||
this.at = 0,
|
||||
this.chat = 0,
|
||||
this.like = 0,
|
||||
this.reply = 0,
|
||||
this.sysMsg = 0,
|
||||
this.up = 0,
|
||||
});
|
||||
import 'package:fixnum/fixnum.dart';
|
||||
|
||||
class MsgFeedUnread {
|
||||
int at = 0;
|
||||
int chat = 0;
|
||||
int like = 0;
|
||||
int reply = 0;
|
||||
int sysMsg = 0;
|
||||
int up = 0;
|
||||
|
||||
MsgFeedUnread.fromJson(Map<String, dynamic> json) {
|
||||
at = json['at'] ?? 0;
|
||||
chat = json['chat'] ?? 0;
|
||||
like = json['like'] ?? 0;
|
||||
reply = json['reply'] ?? 0;
|
||||
sysMsg = json['sys_msg'] ?? 0;
|
||||
up = json['up'] ?? 0;
|
||||
MsgFeedUnread.fromJson(Map<String, Int64> json) {
|
||||
at = json['at']?.toInt() ?? 0;
|
||||
like = json['like']?.toInt() ?? 0;
|
||||
reply = json['reply']?.toInt() ?? 0;
|
||||
sysMsg = json['sys_msg']?.toInt() ?? 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/loading_widget/http_error.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/models/common/image_type.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/widgets/item.dart';
|
||||
import 'package:PiliPlus/utils/grid.dart';
|
||||
import 'package:PiliPlus/utils/page_utils.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
import 'package:flutter/material.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 'package:PiliPlus/grpc/dyn.dart';
|
||||
import 'package:PiliPlus/http/api.dart';
|
||||
import 'package:PiliPlus/http/init.dart';
|
||||
import 'package:PiliPlus/grpc/im.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/nav_bar_config.dart';
|
||||
@@ -83,92 +82,51 @@ class MainController extends GetxController {
|
||||
msgUnReadCount.value = '';
|
||||
return;
|
||||
}
|
||||
try {
|
||||
bool shouldCheckPM = msgUnReadTypes.contains(MsgUnReadType.pm);
|
||||
bool shouldCheckFeed =
|
||||
shouldCheckPM ? msgUnReadTypes.length > 1 : msgUnReadTypes.isNotEmpty;
|
||||
List res = await Future.wait([
|
||||
if (shouldCheckPM) _queryPMUnread(),
|
||||
if (shouldCheckFeed) _queryMsgFeedUnread(),
|
||||
]);
|
||||
dynamic count = 0;
|
||||
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'];
|
||||
|
||||
int count = 0;
|
||||
final res = await ImGrpc.getTotalUnread();
|
||||
if (res.isSuccess) {
|
||||
final data = res.data;
|
||||
if (msgUnReadTypes.length == MsgUnReadType.values.length) {
|
||||
count = data.hasTotalUnread() ? data.totalUnread : 0;
|
||||
} else {
|
||||
final msgUnread = data.msgFeedUnread.unread;
|
||||
for (final item in msgUnReadTypes) {
|
||||
switch (item) {
|
||||
case MsgUnReadType.pm:
|
||||
final pmUnread = data.sessionSingleUnread;
|
||||
count += (pmUnread.followUnread +
|
||||
pmUnread.unfollowUnread +
|
||||
pmUnread.dustbinUnread)
|
||||
.toInt();
|
||||
break;
|
||||
case MsgUnReadType.reply:
|
||||
count += (data['reply'] as int?) ?? 0;
|
||||
count += msgUnread['reply']?.toInt() ?? 0;
|
||||
break;
|
||||
case MsgUnReadType.at:
|
||||
count += (data['at'] as int?) ?? 0;
|
||||
count += msgUnread['at']?.toInt() ?? 0;
|
||||
break;
|
||||
case MsgUnReadType.like:
|
||||
count += (data['like'] as int?) ?? 0;
|
||||
count += msgUnread['like']?.toInt() ?? 0;
|
||||
break;
|
||||
case MsgUnReadType.sysMsg:
|
||||
count += (data['sys_msg'] as int?) ?? 0;
|
||||
count += msgUnread['sys_msg']?.toInt() ?? 0;
|
||||
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 {
|
||||
try {
|
||||
dynamic res = await Request().get(Api.msgUnread);
|
||||
if (res.data['code'] == 0) {
|
||||
return {
|
||||
'status': true,
|
||||
'data': ((res.data['data']?['unfollow_unread'] as int?) ?? 0) +
|
||||
((res.data['data']?['follow_unread'] as int?) ?? 0),
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
'status': false,
|
||||
'msg': res.data['message'],
|
||||
};
|
||||
}
|
||||
} catch (_) {}
|
||||
}
|
||||
|
||||
Future _queryMsgFeedUnread() async {
|
||||
if (isLogin.value.not) {
|
||||
return;
|
||||
final countStr = count == 0
|
||||
? ''
|
||||
: count > 99
|
||||
? '99+'
|
||||
: count.toString();
|
||||
if (msgUnReadCount.value == countStr) {
|
||||
msgUnReadCount.refresh();
|
||||
} else {
|
||||
msgUnReadCount.value = countStr;
|
||||
}
|
||||
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 {
|
||||
|
||||
@@ -22,13 +22,16 @@ class ZanButtonGrpc extends StatefulWidget {
|
||||
}
|
||||
|
||||
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 {
|
||||
feedBack();
|
||||
final int oid = widget.replyItem.oid.toInt();
|
||||
final int rpid = widget.replyItem.id.toInt();
|
||||
// 1 已点赞 2 不喜欢 0 未操作
|
||||
final int action =
|
||||
widget.replyItem.replyControl.action.toInt() != 2 ? 2 : 0;
|
||||
final int action = isDislike ? 0 : 2;
|
||||
final res = await ReplyHttp.hateReply(
|
||||
type: widget.replyItem.type.toInt(),
|
||||
action: action == 2 ? 1 : 0,
|
||||
@@ -37,13 +40,9 @@ class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
|
||||
);
|
||||
// SmartDialog.dismiss();
|
||||
if (res['status']) {
|
||||
SmartDialog.showToast(
|
||||
widget.replyItem.replyControl.action.toInt() != 2 ? '点踩成功' : '取消踩');
|
||||
SmartDialog.showToast(isDislike ? '取消踩' : '点踩成功');
|
||||
if (action == 2) {
|
||||
if (widget.replyItem.replyControl.action.toInt() == 1) {
|
||||
widget.replyItem.like =
|
||||
$fixnum.Int64(widget.replyItem.like.toInt() - 1);
|
||||
}
|
||||
if (isLike) widget.replyItem.like -= $fixnum.Int64.ONE;
|
||||
widget.replyItem.replyControl.action = $fixnum.Int64.TWO;
|
||||
} else {
|
||||
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 rpid = widget.replyItem.id.toInt();
|
||||
// 1 已点赞 2 不喜欢 0 未操作
|
||||
final int action =
|
||||
widget.replyItem.replyControl.action.toInt() != 1 ? 1 : 0;
|
||||
final int action = isLike ? 0 : 1;
|
||||
final res = await ReplyHttp.likeReply(
|
||||
type: widget.replyItem.type.toInt(),
|
||||
oid: oid,
|
||||
@@ -69,15 +67,12 @@ class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
|
||||
action: action,
|
||||
);
|
||||
if (res['status']) {
|
||||
SmartDialog.showToast(
|
||||
widget.replyItem.replyControl.action.toInt() != 1 ? '点赞成功' : '取消赞');
|
||||
SmartDialog.showToast(isLike ? '取消赞' : '点赞成功');
|
||||
if (action == 1) {
|
||||
widget.replyItem.like =
|
||||
$fixnum.Int64(widget.replyItem.like.toInt() + 1);
|
||||
widget.replyItem.like += $fixnum.Int64.ONE;
|
||||
widget.replyItem.replyControl.action = $fixnum.Int64.ONE;
|
||||
} else {
|
||||
widget.replyItem.like =
|
||||
$fixnum.Int64(widget.replyItem.like.toInt() - 1);
|
||||
widget.replyItem.like -= $fixnum.Int64.ONE;
|
||||
widget.replyItem.replyControl.action = $fixnum.Int64.ZERO;
|
||||
}
|
||||
setState(() {});
|
||||
@@ -115,16 +110,12 @@ class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
|
||||
style: _style,
|
||||
onPressed: () => handleState(onHateReply),
|
||||
child: Icon(
|
||||
widget.replyItem.replyControl.action.toInt() == 2
|
||||
isDislike
|
||||
? FontAwesomeIcons.solidThumbsDown
|
||||
: FontAwesomeIcons.thumbsDown,
|
||||
size: 16,
|
||||
color: widget.replyItem.replyControl.action.toInt() == 2
|
||||
? primary
|
||||
: color,
|
||||
semanticLabel: widget.replyItem.replyControl.action.toInt() == 2
|
||||
? '已踩'
|
||||
: '点踩',
|
||||
color: isDislike ? primary : color,
|
||||
semanticLabel: isDislike ? '已踩' : '点踩',
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -136,17 +127,12 @@ class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
|
||||
child: Row(
|
||||
children: [
|
||||
Icon(
|
||||
widget.replyItem.replyControl.action.toInt() == 1
|
||||
isLike
|
||||
? FontAwesomeIcons.solidThumbsUp
|
||||
: FontAwesomeIcons.thumbsUp,
|
||||
size: 16,
|
||||
color: widget.replyItem.replyControl.action.toInt() == 1
|
||||
? primary
|
||||
: color,
|
||||
semanticLabel:
|
||||
widget.replyItem.replyControl.action.toInt() == 1
|
||||
? '已赞'
|
||||
: '点赞',
|
||||
color: isLike ? primary : color,
|
||||
semanticLabel: isLike ? '已赞' : '点赞',
|
||||
),
|
||||
const SizedBox(width: 4),
|
||||
AnimatedSwitcher(
|
||||
@@ -158,9 +144,7 @@ class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
|
||||
child: Text(
|
||||
Utils.numFormat(widget.replyItem.like.toInt()),
|
||||
style: TextStyle(
|
||||
color: widget.replyItem.replyControl.action.toInt() == 1
|
||||
? primary
|
||||
: color,
|
||||
color: isLike ? primary : color,
|
||||
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;
|
||||
import 'package:PiliPlus/grpc/im.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/pages/common/common_whisper_controller.dart';
|
||||
import 'package:PiliPlus/utils/storage.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:protobuf/protobuf.dart' show PbMap;
|
||||
|
||||
@@ -15,7 +14,8 @@ class WhisperController extends CommonWhisperController<SessionMainReply> {
|
||||
@override
|
||||
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;
|
||||
|
||||
PbMap<int, Offset>? offset;
|
||||
@@ -29,44 +29,46 @@ class WhisperController extends CommonWhisperController<SessionMainReply> {
|
||||
final disableLikeMsg =
|
||||
GStorage.setting.get(SettingBoxKey.disableLikeMsg, defaultValue: false);
|
||||
msgFeedTopItems = [
|
||||
{
|
||||
"name": "回复我的",
|
||||
"icon": Icons.message_outlined,
|
||||
"route": "/replyMe",
|
||||
"enabled": true,
|
||||
},
|
||||
{
|
||||
"name": "@我",
|
||||
"icon": Icons.alternate_email_outlined,
|
||||
"route": "/atMe",
|
||||
"enabled": true,
|
||||
},
|
||||
{
|
||||
"name": "收到的赞",
|
||||
"icon": Icons.favorite_border_outlined,
|
||||
"route": "/likeMe",
|
||||
"enabled": !disableLikeMsg,
|
||||
},
|
||||
{
|
||||
"name": "系统通知",
|
||||
"icon": Icons.notifications_none_outlined,
|
||||
"route": "/sysMsg",
|
||||
"enabled": true,
|
||||
},
|
||||
const (
|
||||
name: "回复我的",
|
||||
icon: Icons.message_outlined,
|
||||
route: "/replyMe",
|
||||
enabled: true,
|
||||
),
|
||||
const (
|
||||
name: "@我",
|
||||
icon: Icons.alternate_email_outlined,
|
||||
route: "/atMe",
|
||||
enabled: true,
|
||||
),
|
||||
(
|
||||
name: "收到的赞",
|
||||
icon: Icons.favorite_border_outlined,
|
||||
route: "/likeMe",
|
||||
enabled: !disableLikeMsg,
|
||||
),
|
||||
const (
|
||||
name: "系统通知",
|
||||
icon: Icons.notifications_none_outlined,
|
||||
route: "/sysMsg",
|
||||
enabled: true,
|
||||
),
|
||||
];
|
||||
unreadCounts =
|
||||
List.generate(msgFeedTopItems.length, (index) => 0).toList().obs;
|
||||
unreadCounts = List.filled(msgFeedTopItems.length, 0).obs;
|
||||
queryMsgFeedUnread();
|
||||
queryData();
|
||||
}
|
||||
|
||||
Future<void> queryMsgFeedUnread() async {
|
||||
var res = await MsgHttp.msgFeedUnread();
|
||||
if (res['status']) {
|
||||
final data = MsgFeedUnread.fromJson(res['data']);
|
||||
unreadCounts.value = [data.reply, data.at, data.like, data.sysMsg];
|
||||
var res = await ImGrpc.getTotalUnread(unreadType: 2);
|
||||
if (res.isSuccess) {
|
||||
final data = MsgFeedUnread.fromJson(res.data.msgFeedUnread.unread);
|
||||
final unreadCounts = [data.reply, data.at, data.like, data.sysMsg];
|
||||
if (!listEquals(this.unreadCounts, unreadCounts)) {
|
||||
this.unreadCounts.value = unreadCounts;
|
||||
}
|
||||
} else {
|
||||
SmartDialog.showToast(res['msg']);
|
||||
res.toast();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ class _WhisperPageState extends State<WhisperPage> {
|
||||
radius: 22,
|
||||
backgroundColor: theme.colorScheme.onInverseSurface,
|
||||
child: Icon(
|
||||
_controller.msgFeedTopItems[index]['icon'],
|
||||
_controller.msgFeedTopItems[index].icon,
|
||||
size: 20,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
@@ -164,20 +164,20 @@ class _WhisperPageState extends State<WhisperPage> {
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
Text(
|
||||
_controller.msgFeedTopItems[index]['name'],
|
||||
_controller.msgFeedTopItems[index].name,
|
||||
style: const TextStyle(fontSize: 13),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
onTap: () {
|
||||
if (!_controller.msgFeedTopItems[index]['enabled']) {
|
||||
if (!_controller.msgFeedTopItems[index].enabled) {
|
||||
SmartDialog.showToast('已禁用');
|
||||
return;
|
||||
}
|
||||
_controller.unreadCounts[index] = 0;
|
||||
Get.toNamed(
|
||||
_controller.msgFeedTopItems[index]['route'],
|
||||
_controller.msgFeedTopItems[index].route,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
@@ -20,8 +20,7 @@ import 'package:get/get.dart';
|
||||
|
||||
class ChatItem extends StatelessWidget {
|
||||
static MsgType msgTypeFromValue(int value) {
|
||||
return MsgType.values.firstWhere((e) => e.value == value,
|
||||
orElse: () => MsgType.EN_INVALID_MSG_TYPE);
|
||||
return MsgType.valueOf(value) ?? MsgType.EN_INVALID_MSG_TYPE;
|
||||
}
|
||||
|
||||
const ChatItem({
|
||||
|
||||
@@ -57,23 +57,6 @@ extension ListExt<T> on List<T>? {
|
||||
T getOrElse(int index, {required T Function() 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);
|
||||
@@ -128,17 +111,6 @@ extension ColorExtension on Color {
|
||||
assert(amount >= 0 && amount <= 1, 'Amount must be between 0 and 1');
|
||||
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 {
|
||||
|
||||
Reference in New Issue
Block a user