Merge branch 'main' into fix
This commit is contained in:
@ -333,7 +333,9 @@ class VideoStat extends StatelessWidget {
|
|||||||
color: Theme.of(context).colorScheme.outline,
|
color: Theme.of(context).colorScheme.outline,
|
||||||
),
|
),
|
||||||
children: [
|
children: [
|
||||||
|
if (videoItem.stat.view != '-')
|
||||||
TextSpan(text: '${videoItem.stat.view}观看'),
|
TextSpan(text: '${videoItem.stat.view}观看'),
|
||||||
|
if (videoItem.stat.danmu != '-')
|
||||||
TextSpan(text: ' • ${videoItem.stat.danmu}弹幕'),
|
TextSpan(text: ' • ${videoItem.stat.danmu}弹幕'),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
|||||||
@ -326,6 +326,51 @@ class Api {
|
|||||||
// 获取指定分组下的up
|
// 获取指定分组下的up
|
||||||
static const String followUpGroup = '/x/relation/tag';
|
static const String followUpGroup = '/x/relation/tag';
|
||||||
|
|
||||||
|
/// 私聊
|
||||||
|
/// 'https://api.vc.bilibili.com/session_svr/v1/session_svr/get_sessions?
|
||||||
|
/// session_type=1&
|
||||||
|
/// group_fold=1&
|
||||||
|
/// unfollow_fold=0&
|
||||||
|
/// sort_rule=2&
|
||||||
|
/// build=0&
|
||||||
|
/// mobi_app=web&
|
||||||
|
/// w_rid=8641d157fb9a9255eb2159f316ee39e2&
|
||||||
|
/// wts=1697305010
|
||||||
|
|
||||||
|
static const String sessionList =
|
||||||
|
'https://api.vc.bilibili.com/session_svr/v1/session_svr/get_sessions';
|
||||||
|
|
||||||
|
/// 私聊用户信息
|
||||||
|
/// uids
|
||||||
|
/// build=0&mobi_app=web
|
||||||
|
static const String sessionAccountList =
|
||||||
|
'https://api.vc.bilibili.com/account/v1/user/cards';
|
||||||
|
|
||||||
|
/// https://api.vc.bilibili.com/svr_sync/v1/svr_sync/fetch_session_msgs?
|
||||||
|
/// talker_id=400787461&
|
||||||
|
/// session_type=1&
|
||||||
|
/// size=20&
|
||||||
|
/// sender_device_id=1&
|
||||||
|
/// build=0&
|
||||||
|
/// mobi_app=web&
|
||||||
|
/// web_location=333.1296&
|
||||||
|
/// w_rid=cfe3bf58c9fe181bbf4dd6c75175e6b0&
|
||||||
|
/// wts=1697350697
|
||||||
|
|
||||||
|
static const String sessionMsg =
|
||||||
|
'https://api.vc.bilibili.com/svr_sync/v1/svr_sync/fetch_session_msgs';
|
||||||
|
|
||||||
|
/// 标记已读 POST
|
||||||
|
/// talker_id:
|
||||||
|
/// session_type: 1
|
||||||
|
/// ack_seqno: 920224140918926
|
||||||
|
/// build: 0
|
||||||
|
/// mobi_app: web
|
||||||
|
/// csrf_token:
|
||||||
|
/// csrf:
|
||||||
|
static const String updateAck =
|
||||||
|
'https://api.vc.bilibili.com/session_svr/v1/session_svr/update_ack';
|
||||||
|
|
||||||
// 获取某个动态详情
|
// 获取某个动态详情
|
||||||
// timezone_offset=-480
|
// timezone_offset=-480
|
||||||
// id=849312409672744983
|
// id=849312409672744983
|
||||||
@ -410,6 +455,7 @@ class Api {
|
|||||||
static const getMemberSeasonsApi = '/x/polymer/web-space/home/seasons_series';
|
static const getMemberSeasonsApi = '/x/polymer/web-space/home/seasons_series';
|
||||||
|
|
||||||
/// 获赞数 播放数
|
/// 获赞数 播放数
|
||||||
|
/// mid
|
||||||
static const getMemberViewApi = '/x/space/upstat';
|
static const getMemberViewApi = '/x/space/upstat';
|
||||||
|
|
||||||
/// 查询某个专栏
|
/// 查询某个专栏
|
||||||
|
|||||||
@ -403,7 +403,7 @@ class MemberHttp {
|
|||||||
'csrf': await Request.getCsrf(),
|
'csrf': await Request.getCsrf(),
|
||||||
});
|
});
|
||||||
await Future.delayed(const Duration(milliseconds: 300));
|
await Future.delayed(const Duration(milliseconds: 300));
|
||||||
qrcodePoll(authCodeRes['data']);
|
await qrcodePoll(authCodeRes['data']);
|
||||||
if (res.data['code'] == 0) {
|
if (res.data['code'] == 0) {
|
||||||
return {'status': true, 'data': [], 'msg': '操作成功'};
|
return {'status': true, 'data': [], 'msg': '操作成功'};
|
||||||
} else {
|
} else {
|
||||||
@ -447,4 +447,18 @@ class MemberHttp {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取up播放数、点赞数
|
||||||
|
static Future memberView({required int mid}) async {
|
||||||
|
var res = await Request().get(Api.getMemberViewApi, data: {'mid': mid});
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {'status': true, 'data': res.data['data']};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
'status': false,
|
||||||
|
'data': [],
|
||||||
|
'msg': res.data['message'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
85
lib/http/msg.dart
Normal file
85
lib/http/msg.dart
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
import 'package:pilipala/http/api.dart';
|
||||||
|
import 'package:pilipala/http/init.dart';
|
||||||
|
import 'package:pilipala/models/msg/account.dart';
|
||||||
|
import 'package:pilipala/models/msg/session.dart';
|
||||||
|
import 'package:pilipala/utils/wbi_sign.dart';
|
||||||
|
|
||||||
|
class MsgHttp {
|
||||||
|
// 会话列表
|
||||||
|
static Future sessionList({int? endTs}) async {
|
||||||
|
Map<String, dynamic> params = {
|
||||||
|
'session_type': 1,
|
||||||
|
'group_fold': 1,
|
||||||
|
'unfollow_fold': 0,
|
||||||
|
'sort_rule': 2,
|
||||||
|
'build': 0,
|
||||||
|
'mobi_app': 'web',
|
||||||
|
};
|
||||||
|
if (endTs != null) {
|
||||||
|
params['end_ts'] = endTs;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map signParams = await WbiSign().makSign(params);
|
||||||
|
var res = await Request().get(Api.sessionList, data: signParams);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': SessionDataModel.fromJson(res.data['data']),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
'status': false,
|
||||||
|
'date': [],
|
||||||
|
'msg': res.data['message'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future accountList(uids) async {
|
||||||
|
var res = await Request().get(Api.sessionAccountList, data: {
|
||||||
|
'uids': uids,
|
||||||
|
'build': 0,
|
||||||
|
'mobi_app': 'web',
|
||||||
|
});
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': res.data['data']
|
||||||
|
.map<AccountListModel>((e) => AccountListModel.fromJson(e))
|
||||||
|
.toList(),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
'status': false,
|
||||||
|
'date': [],
|
||||||
|
'msg': res.data['message'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static Future sessionMsg({
|
||||||
|
int? talkerId,
|
||||||
|
}) async {
|
||||||
|
Map params = await WbiSign().makSign({
|
||||||
|
'talker_id': talkerId,
|
||||||
|
'session_type': 1,
|
||||||
|
'size': 20,
|
||||||
|
'sender_device_id': 1,
|
||||||
|
'build': 0,
|
||||||
|
'mobi_app': 'web',
|
||||||
|
});
|
||||||
|
var res = await Request().get(Api.sessionMsg, data: params);
|
||||||
|
if (res.data['code'] == 0) {
|
||||||
|
return {
|
||||||
|
'status': true,
|
||||||
|
'data': SessionMsgDataModel.fromJson(res.data['data']),
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
'status': false,
|
||||||
|
'date': [],
|
||||||
|
'msg': res.data['message'],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -199,7 +199,7 @@ class UserHttp {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取用户凭证
|
// 获取用户凭证 失效
|
||||||
static Future thirdLogin() async {
|
static Future thirdLogin() async {
|
||||||
var res = await Request().get(
|
var res = await Request().get(
|
||||||
'https://passport.bilibili.com/login/app/third',
|
'https://passport.bilibili.com/login/app/third',
|
||||||
|
|||||||
@ -118,7 +118,7 @@ class RcmdStat {
|
|||||||
|
|
||||||
RcmdStat.fromJson(Map<String, dynamic> json) {
|
RcmdStat.fromJson(Map<String, dynamic> json) {
|
||||||
view = json["cover_left_text_1"];
|
view = json["cover_left_text_1"];
|
||||||
danmu = json['cover_left_text_2'];
|
danmu = json['cover_left_text_2'] ?? '-';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
80
lib/models/msg/account.dart
Normal file
80
lib/models/msg/account.dart
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
class AccountListModel {
|
||||||
|
AccountListModel({
|
||||||
|
this.mid,
|
||||||
|
this.name,
|
||||||
|
this.sex,
|
||||||
|
this.face,
|
||||||
|
this.sign,
|
||||||
|
this.rank,
|
||||||
|
this.level,
|
||||||
|
this.silence,
|
||||||
|
this.vip,
|
||||||
|
this.pendant,
|
||||||
|
this.nameplate,
|
||||||
|
this.official,
|
||||||
|
this.birthday,
|
||||||
|
this.isFakeAccount,
|
||||||
|
this.isDeleted,
|
||||||
|
this.inRegAudit,
|
||||||
|
this.faceNft,
|
||||||
|
this.faceNftNew,
|
||||||
|
this.isSeniorMember,
|
||||||
|
this.digitalId,
|
||||||
|
this.digitalType,
|
||||||
|
this.attestation,
|
||||||
|
this.expertInfo,
|
||||||
|
this.honours,
|
||||||
|
});
|
||||||
|
|
||||||
|
int? mid;
|
||||||
|
String? name;
|
||||||
|
String? sex;
|
||||||
|
String? face;
|
||||||
|
String? sign;
|
||||||
|
int? rank;
|
||||||
|
int? level;
|
||||||
|
int? silence;
|
||||||
|
Map? vip;
|
||||||
|
Map? pendant;
|
||||||
|
Map? nameplate;
|
||||||
|
Map? official;
|
||||||
|
int? birthday;
|
||||||
|
int? isFakeAccount;
|
||||||
|
int? isDeleted;
|
||||||
|
int? inRegAudit;
|
||||||
|
int? faceNft;
|
||||||
|
int? faceNftNew;
|
||||||
|
int? isSeniorMember;
|
||||||
|
String? digitalId;
|
||||||
|
int? digitalType;
|
||||||
|
Map? attestation;
|
||||||
|
Map? expertInfo;
|
||||||
|
Map? honours;
|
||||||
|
|
||||||
|
AccountListModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
mid = json['mid'];
|
||||||
|
name = json['name'] ?? '';
|
||||||
|
sex = json['sex'];
|
||||||
|
face = json['face'];
|
||||||
|
sign = json['sign'];
|
||||||
|
rank = json['rank'];
|
||||||
|
level = json['level'];
|
||||||
|
silence = json['silence'];
|
||||||
|
vip = json['vip'];
|
||||||
|
pendant = json['pendant'];
|
||||||
|
nameplate = json['nameplate'];
|
||||||
|
official = json['official'];
|
||||||
|
birthday = json['birthday'];
|
||||||
|
isFakeAccount = json['is_fake_account'];
|
||||||
|
isDeleted = json['is_deleted'];
|
||||||
|
inRegAudit = json['in_reg_audit'];
|
||||||
|
faceNft = json['face_nft'];
|
||||||
|
faceNftNew = json['face_nft_new'];
|
||||||
|
isSeniorMember = json['is_senior_member'];
|
||||||
|
digitalId = json['digital_id'];
|
||||||
|
digitalType = json['digital_type'];
|
||||||
|
attestation = json['attestation'];
|
||||||
|
expertInfo = json['expert_info'];
|
||||||
|
honours = json['honours'];
|
||||||
|
}
|
||||||
|
}
|
||||||
226
lib/models/msg/session.dart
Normal file
226
lib/models/msg/session.dart
Normal file
@ -0,0 +1,226 @@
|
|||||||
|
import 'dart:convert';
|
||||||
|
|
||||||
|
import 'package:pilipala/models/msg/account.dart';
|
||||||
|
|
||||||
|
class SessionDataModel {
|
||||||
|
SessionDataModel({
|
||||||
|
this.sessionList,
|
||||||
|
this.hasMore,
|
||||||
|
});
|
||||||
|
|
||||||
|
List? sessionList;
|
||||||
|
int? hasMore;
|
||||||
|
|
||||||
|
SessionDataModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
sessionList = json['session_list']
|
||||||
|
?.map<SessionList>((e) => SessionList.fromJson(e))
|
||||||
|
.toList();
|
||||||
|
hasMore = json['has_more'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SessionList {
|
||||||
|
SessionList({
|
||||||
|
this.talkerId,
|
||||||
|
this.sessionType,
|
||||||
|
this.atSeqno,
|
||||||
|
this.topTs,
|
||||||
|
this.groupName,
|
||||||
|
this.groupCover,
|
||||||
|
this.isFollow,
|
||||||
|
this.isDnd,
|
||||||
|
this.ackSeqno,
|
||||||
|
this.ackTs,
|
||||||
|
this.sessionTs,
|
||||||
|
this.unreadCount,
|
||||||
|
this.lastMsg,
|
||||||
|
this.groupType,
|
||||||
|
this.canFold,
|
||||||
|
this.status,
|
||||||
|
this.maxSeqno,
|
||||||
|
this.newPushMsg,
|
||||||
|
this.setting,
|
||||||
|
this.isGuardian,
|
||||||
|
this.isIntercept,
|
||||||
|
this.isTrust,
|
||||||
|
this.systemMsgType,
|
||||||
|
this.liveStatus,
|
||||||
|
this.bizMsgUnreadCount,
|
||||||
|
// this.userLabel,
|
||||||
|
});
|
||||||
|
|
||||||
|
int? talkerId;
|
||||||
|
int? sessionType;
|
||||||
|
int? atSeqno;
|
||||||
|
int? topTs;
|
||||||
|
String? groupName;
|
||||||
|
String? groupCover;
|
||||||
|
int? isFollow;
|
||||||
|
int? isDnd;
|
||||||
|
int? ackSeqno;
|
||||||
|
int? ackTs;
|
||||||
|
int? sessionTs;
|
||||||
|
int? unreadCount;
|
||||||
|
LastMsg? lastMsg;
|
||||||
|
int? groupType;
|
||||||
|
int? canFold;
|
||||||
|
int? status;
|
||||||
|
int? maxSeqno;
|
||||||
|
int? newPushMsg;
|
||||||
|
int? setting;
|
||||||
|
int? isGuardian;
|
||||||
|
int? isIntercept;
|
||||||
|
int? isTrust;
|
||||||
|
int? systemMsgType;
|
||||||
|
int? liveStatus;
|
||||||
|
int? bizMsgUnreadCount;
|
||||||
|
// int? userLabel;
|
||||||
|
AccountListModel? accountInfo;
|
||||||
|
|
||||||
|
SessionList.fromJson(Map<String, dynamic> json) {
|
||||||
|
talkerId = json["talker_id"];
|
||||||
|
sessionType = json["session_type"];
|
||||||
|
atSeqno = json["at_seqno"];
|
||||||
|
topTs = json["top_ts"];
|
||||||
|
groupName = json["group_name"];
|
||||||
|
groupCover = json["group_cover"];
|
||||||
|
isFollow = json["is_follow"];
|
||||||
|
isDnd = json["is_dnd"];
|
||||||
|
ackSeqno = json["ack_seqno"];
|
||||||
|
ackTs = json["ack_ts"];
|
||||||
|
sessionTs = json["session_ts"];
|
||||||
|
unreadCount = json["unread_count"];
|
||||||
|
lastMsg =
|
||||||
|
json["last_msg"] != null ? LastMsg.fromJson(json["last_msg"]) : null;
|
||||||
|
groupType = json["group_type"];
|
||||||
|
canFold = json["can_fold"];
|
||||||
|
status = json["status"];
|
||||||
|
maxSeqno = json["max_seqno"];
|
||||||
|
newPushMsg = json["new_push_msg"];
|
||||||
|
setting = json["setting"];
|
||||||
|
isGuardian = json["is_guardian"];
|
||||||
|
isIntercept = json["is_intercept"];
|
||||||
|
isTrust = json["is_trust"];
|
||||||
|
systemMsgType = json["system_msg_type"];
|
||||||
|
liveStatus = json["live_status"];
|
||||||
|
bizMsgUnreadCount = json["biz_msg_unread_count"];
|
||||||
|
// userLabel = json["user_label"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class LastMsg {
|
||||||
|
LastMsg({
|
||||||
|
this.senderIid,
|
||||||
|
this.receiverType,
|
||||||
|
this.receiverId,
|
||||||
|
this.msgType,
|
||||||
|
this.content,
|
||||||
|
this.msgSeqno,
|
||||||
|
this.timestamp,
|
||||||
|
this.atUids,
|
||||||
|
this.msgKey,
|
||||||
|
this.msgStatus,
|
||||||
|
this.notifyCode,
|
||||||
|
this.newFaceVersion,
|
||||||
|
});
|
||||||
|
|
||||||
|
int? senderIid;
|
||||||
|
int? receiverType;
|
||||||
|
int? receiverId;
|
||||||
|
int? msgType;
|
||||||
|
Map? content;
|
||||||
|
int? msgSeqno;
|
||||||
|
int? timestamp;
|
||||||
|
String? atUids;
|
||||||
|
int? msgKey;
|
||||||
|
int? msgStatus;
|
||||||
|
String? notifyCode;
|
||||||
|
int? newFaceVersion;
|
||||||
|
|
||||||
|
LastMsg.fromJson(Map<String, dynamic> json) {
|
||||||
|
senderIid = json['sender_uid'];
|
||||||
|
receiverType = json['receiver_type'];
|
||||||
|
receiverId = json['receiver_id'];
|
||||||
|
msgType = json['msg_type'];
|
||||||
|
content = jsonDecode(json['content']);
|
||||||
|
msgSeqno = json['msg_seqno'];
|
||||||
|
timestamp = json['timestamp'];
|
||||||
|
atUids = json['at_uids'];
|
||||||
|
msgKey = json['msg_key'];
|
||||||
|
msgStatus = json['msg_status'];
|
||||||
|
notifyCode = json['notify_code'];
|
||||||
|
newFaceVersion = json['new_face_version'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SessionMsgDataModel {
|
||||||
|
SessionMsgDataModel({
|
||||||
|
this.messages,
|
||||||
|
this.hasMore,
|
||||||
|
this.minSeqno,
|
||||||
|
this.maxSeqno,
|
||||||
|
this.eInfos,
|
||||||
|
});
|
||||||
|
|
||||||
|
List<MessageItem>? messages;
|
||||||
|
int? hasMore;
|
||||||
|
int? minSeqno;
|
||||||
|
int? maxSeqno;
|
||||||
|
List? eInfos;
|
||||||
|
|
||||||
|
SessionMsgDataModel.fromJson(Map<String, dynamic> json) {
|
||||||
|
messages = json['messages']
|
||||||
|
.map<MessageItem>((e) => MessageItem.fromJson(e))
|
||||||
|
.toList();
|
||||||
|
hasMore = json['has_more'];
|
||||||
|
minSeqno = json['min_seqno'];
|
||||||
|
maxSeqno = json['max_seqno'];
|
||||||
|
eInfos = json['e_infos'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class MessageItem {
|
||||||
|
MessageItem({
|
||||||
|
this.senderUid,
|
||||||
|
this.receiverType,
|
||||||
|
this.receiverId,
|
||||||
|
this.msgType,
|
||||||
|
this.content,
|
||||||
|
this.msgSeqno,
|
||||||
|
this.timestamp,
|
||||||
|
this.atUids,
|
||||||
|
this.msgKey,
|
||||||
|
this.msgStatus,
|
||||||
|
this.notifyCode,
|
||||||
|
this.newFaceVersion,
|
||||||
|
});
|
||||||
|
|
||||||
|
int? senderUid;
|
||||||
|
int? receiverType;
|
||||||
|
int? receiverId;
|
||||||
|
int? msgType;
|
||||||
|
Map? content;
|
||||||
|
int? msgSeqno;
|
||||||
|
int? timestamp;
|
||||||
|
List? atUids;
|
||||||
|
int? msgKey;
|
||||||
|
int? msgStatus;
|
||||||
|
String? notifyCode;
|
||||||
|
int? newFaceVersion;
|
||||||
|
|
||||||
|
MessageItem.fromJson(Map<String, dynamic> json) {
|
||||||
|
senderUid = json['sender_uid'];
|
||||||
|
receiverType = json['receiver_type'];
|
||||||
|
receiverId = json['receiver_id'];
|
||||||
|
// 1 文本 2 图片 18 系统提示 10 系统通知
|
||||||
|
msgType = json['msg_type'];
|
||||||
|
content = jsonDecode(json['content']);
|
||||||
|
msgSeqno = json['msg_seqno'];
|
||||||
|
timestamp = json['timestamp'];
|
||||||
|
atUids = json['at_uids'];
|
||||||
|
msgKey = json['msg_key'];
|
||||||
|
msgStatus = json['msg_status'];
|
||||||
|
notifyCode = json['notify_code'];
|
||||||
|
newFaceVersion = json['new_face_version'];
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,3 @@
|
|||||||
import 'dart:developer';
|
|
||||||
|
|
||||||
import 'package:pilipala/models/video/play/quality.dart';
|
import 'package:pilipala/models/video/play/quality.dart';
|
||||||
|
|
||||||
class PlayUrlModel {
|
class PlayUrlModel {
|
||||||
|
|||||||
@ -1,6 +1,3 @@
|
|||||||
import 'dart:io';
|
|
||||||
|
|
||||||
import 'package:device_info_plus/device_info_plus.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
|
|||||||
@ -5,7 +5,6 @@ import 'package:get/get.dart';
|
|||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:pilipala/common/constants.dart';
|
import 'package:pilipala/common/constants.dart';
|
||||||
import 'package:pilipala/common/widgets/badge.dart';
|
import 'package:pilipala/common/widgets/badge.dart';
|
||||||
import 'package:pilipala/common/widgets/http_error.dart';
|
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/common/widgets/stat/danmu.dart';
|
import 'package:pilipala/common/widgets/stat/danmu.dart';
|
||||||
import 'package:pilipala/common/widgets/stat/view.dart';
|
import 'package:pilipala/common/widgets/stat/view.dart';
|
||||||
|
|||||||
@ -1,8 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/models/dynamics/result.dart';
|
|
||||||
import 'package:pilipala/pages/preview/index.dart';
|
|
||||||
|
|
||||||
// 富文本
|
// 富文本
|
||||||
InlineSpan richNode(item, context) {
|
InlineSpan richNode(item, context) {
|
||||||
@ -11,13 +9,11 @@ InlineSpan richNode(item, context) {
|
|||||||
TextStyle authorStyle =
|
TextStyle authorStyle =
|
||||||
TextStyle(color: Theme.of(context).colorScheme.primary);
|
TextStyle(color: Theme.of(context).colorScheme.primary);
|
||||||
List<InlineSpan> spanChilds = [];
|
List<InlineSpan> spanChilds = [];
|
||||||
String contentType = 'desc';
|
|
||||||
|
|
||||||
dynamic richTextNodes;
|
dynamic richTextNodes;
|
||||||
if (item.modules.moduleDynamic.desc != null) {
|
if (item.modules.moduleDynamic.desc != null) {
|
||||||
richTextNodes = item.modules.moduleDynamic.desc.richTextNodes;
|
richTextNodes = item.modules.moduleDynamic.desc.richTextNodes;
|
||||||
} else if (item.modules.moduleDynamic.major != null) {
|
} else if (item.modules.moduleDynamic.major != null) {
|
||||||
contentType = 'major';
|
|
||||||
// 动态页面 richTextNodes 层级可能与主页动态层级不同
|
// 动态页面 richTextNodes 层级可能与主页动态层级不同
|
||||||
richTextNodes =
|
richTextNodes =
|
||||||
item.modules.moduleDynamic.major.opus.summary.richTextNodes;
|
item.modules.moduleDynamic.major.opus.summary.richTextNodes;
|
||||||
|
|||||||
@ -1,5 +1,4 @@
|
|||||||
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:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/models/follow/result.dart';
|
import 'package:pilipala/models/follow/result.dart';
|
||||||
|
|||||||
@ -1,5 +1,3 @@
|
|||||||
import 'dart:math';
|
|
||||||
|
|
||||||
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';
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import 'package:pilipala/models/bangumi/info.dart';
|
|||||||
import 'package:pilipala/models/common/business_type.dart';
|
import 'package:pilipala/models/common/business_type.dart';
|
||||||
import 'package:pilipala/models/common/search_type.dart';
|
import 'package:pilipala/models/common/search_type.dart';
|
||||||
import 'package:pilipala/models/live/item.dart';
|
import 'package:pilipala/models/live/item.dart';
|
||||||
import 'package:pilipala/pages/history/index.dart';
|
|
||||||
import 'package:pilipala/pages/history_search/index.dart';
|
import 'package:pilipala/pages/history_search/index.dart';
|
||||||
import 'package:pilipala/utils/feed_back.dart';
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
import 'package:pilipala/utils/id_utils.dart';
|
import 'package:pilipala/utils/id_utils.dart';
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import 'dart:async';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/pages/main/index.dart';
|
|
||||||
import 'package:pilipala/pages/mine/index.dart';
|
import 'package:pilipala/pages/mine/index.dart';
|
||||||
import 'package:pilipala/pages/search/index.dart';
|
import 'package:pilipala/pages/search/index.dart';
|
||||||
import 'package:pilipala/utils/feed_back.dart';
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
@ -140,7 +139,13 @@ class CustomAppBar extends StatelessWidget implements PreferredSizeWidget {
|
|||||||
child: Row(
|
child: Row(
|
||||||
children: [
|
children: [
|
||||||
const Expanded(child: SearchPage()),
|
const Expanded(child: SearchPage()),
|
||||||
const SizedBox(width: 10),
|
if (ctr!.userLogin.value) ...[
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () => Get.toNamed('/whisper'),
|
||||||
|
icon: const Icon(Icons.notifications_none))
|
||||||
|
],
|
||||||
|
const SizedBox(width: 6),
|
||||||
Obx(
|
Obx(
|
||||||
() => ctr!.userLogin.value
|
() => ctr!.userLogin.value
|
||||||
? Stack(
|
? Stack(
|
||||||
|
|||||||
@ -9,7 +9,6 @@ import 'package:pilipala/common/widgets/html_render.dart';
|
|||||||
import 'package:pilipala/common/widgets/http_error.dart';
|
import 'package:pilipala/common/widgets/http_error.dart';
|
||||||
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
import 'package:pilipala/models/common/reply_type.dart';
|
import 'package:pilipala/models/common/reply_type.dart';
|
||||||
import 'package:pilipala/pages/mine/index.dart';
|
|
||||||
import 'package:pilipala/pages/video/detail/reply/widgets/reply_item.dart';
|
import 'package:pilipala/pages/video/detail/reply/widgets/reply_item.dart';
|
||||||
import 'package:pilipala/pages/video/detail/replyNew/index.dart';
|
import 'package:pilipala/pages/video/detail/replyNew/index.dart';
|
||||||
import 'package:pilipala/pages/video/detail/replyReply/index.dart';
|
import 'package:pilipala/pages/video/detail/replyReply/index.dart';
|
||||||
|
|||||||
@ -72,6 +72,7 @@ class _LivePageState extends State<LivePage>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
super.build(context);
|
||||||
return Container(
|
return Container(
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
margin: const EdgeInsets.only(
|
margin: const EdgeInsets.only(
|
||||||
|
|||||||
@ -52,7 +52,6 @@ class _LiveRoomPageState extends State<LiveRoomPage> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final videoHeight = MediaQuery.of(context).size.width * 9 / 16;
|
|
||||||
Widget childWhenDisabled = Scaffold(
|
Widget childWhenDisabled = Scaffold(
|
||||||
primary: true,
|
primary: true,
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
|
|||||||
@ -3,7 +3,6 @@ import 'dart:io';
|
|||||||
import 'package:floating/floating.dart';
|
import 'package:floating/floating.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:get/get.dart';
|
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:pilipala/models/video/play/url.dart';
|
import 'package:pilipala/models/video/play/url.dart';
|
||||||
import 'package:pilipala/pages/liveRoom/index.dart';
|
import 'package:pilipala/pages/liveRoom/index.dart';
|
||||||
@ -43,10 +42,6 @@ class _BottomControlState extends State<BottomControl> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
const textStyle = TextStyle(
|
|
||||||
color: Colors.white,
|
|
||||||
fontSize: 12,
|
|
||||||
);
|
|
||||||
return AppBar(
|
return AppBar(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
foregroundColor: Colors.white,
|
foregroundColor: Colors.white,
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import 'package:share_plus/share_plus.dart';
|
|||||||
class MemberController extends GetxController {
|
class MemberController extends GetxController {
|
||||||
late int mid;
|
late int mid;
|
||||||
Rx<MemberInfoModel> memberInfo = MemberInfoModel().obs;
|
Rx<MemberInfoModel> memberInfo = MemberInfoModel().obs;
|
||||||
Map? userStat;
|
late Map userStat;
|
||||||
RxString face = ''.obs;
|
RxString face = ''.obs;
|
||||||
String? heroTag;
|
String? heroTag;
|
||||||
Box userInfoCache = GStrorage.userInfo;
|
Box userInfoCache = GStrorage.userInfo;
|
||||||
@ -40,6 +40,7 @@ class MemberController extends GetxController {
|
|||||||
// 获取用户信息
|
// 获取用户信息
|
||||||
Future<Map<String, dynamic>> getInfo() async {
|
Future<Map<String, dynamic>> getInfo() async {
|
||||||
await getMemberStat();
|
await getMemberStat();
|
||||||
|
await getMemberView();
|
||||||
var res = await MemberHttp.memberInfo(mid: mid);
|
var res = await MemberHttp.memberInfo(mid: mid);
|
||||||
if (res['status']) {
|
if (res['status']) {
|
||||||
memberInfo.value = res['data'];
|
memberInfo.value = res['data'];
|
||||||
@ -57,6 +58,15 @@ class MemberController extends GetxController {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 获取用户播放数 获赞数
|
||||||
|
Future<Map<String, dynamic>> getMemberView() async {
|
||||||
|
var res = await MemberHttp.memberView(mid: mid);
|
||||||
|
if (res['status']) {
|
||||||
|
userStat.addAll(res['data']);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
// 关注/取关up
|
// 关注/取关up
|
||||||
Future actionRelationMod() async {
|
Future actionRelationMod() async {
|
||||||
if (userInfo == null) {
|
if (userInfo == null) {
|
||||||
|
|||||||
@ -137,8 +137,14 @@ Widget profile(ctr, {loadingStatus = false}) {
|
|||||||
),
|
),
|
||||||
Column(
|
Column(
|
||||||
children: [
|
children: [
|
||||||
const Text('-',
|
Text(
|
||||||
style: TextStyle(fontWeight: FontWeight.bold)),
|
!loadingStatus
|
||||||
|
? Utils.numFormat(
|
||||||
|
ctr.userStat!['likes'],
|
||||||
|
)
|
||||||
|
: '-',
|
||||||
|
style: const TextStyle(
|
||||||
|
fontWeight: FontWeight.bold)),
|
||||||
Text(
|
Text(
|
||||||
'获赞',
|
'获赞',
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
|||||||
@ -160,25 +160,25 @@ class _SearchPageState extends State<SearchPage> with RouteAware {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Widget _searchSuggest() {
|
Widget _searchSuggest() {
|
||||||
SSearchController _ssCtr = _searchController;
|
SSearchController ssCtr = _searchController;
|
||||||
return Obx(
|
return Obx(
|
||||||
() => _ssCtr.searchSuggestList.isNotEmpty &&
|
() => ssCtr.searchSuggestList.isNotEmpty &&
|
||||||
_ssCtr.searchSuggestList.first.term != null &&
|
ssCtr.searchSuggestList.first.term != null &&
|
||||||
_ssCtr.controller.value.text != ''
|
ssCtr.controller.value.text != ''
|
||||||
? ListView.builder(
|
? ListView.builder(
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
shrinkWrap: true,
|
shrinkWrap: true,
|
||||||
itemCount: _ssCtr.searchSuggestList.length,
|
itemCount: ssCtr.searchSuggestList.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return InkWell(
|
return InkWell(
|
||||||
customBorder: RoundedRectangleBorder(
|
customBorder: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(4),
|
borderRadius: BorderRadius.circular(4),
|
||||||
),
|
),
|
||||||
onTap: () => _ssCtr
|
onTap: () => ssCtr
|
||||||
.onClickKeyword(_ssCtr.searchSuggestList[index].term!),
|
.onClickKeyword(ssCtr.searchSuggestList[index].term!),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.only(left: 20, top: 9, bottom: 9),
|
padding: const EdgeInsets.only(left: 20, top: 9, bottom: 9),
|
||||||
child: _ssCtr.searchSuggestList[index].textRich,
|
child: ssCtr.searchSuggestList[index].textRich,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -235,6 +235,7 @@ class _SearchPageState extends State<SearchPage> with RouteAware {
|
|||||||
return Obx(
|
return Obx(
|
||||||
() => HotKeyword(
|
() => HotKeyword(
|
||||||
width: width,
|
width: width,
|
||||||
|
// ignore: invalid_use_of_protected_member
|
||||||
hotSearchList: _searchController.hotSearchList.value,
|
hotSearchList: _searchController.hotSearchList.value,
|
||||||
onClick: (keyword) async {
|
onClick: (keyword) async {
|
||||||
_searchController.searchFocusNode.unfocus();
|
_searchController.searchFocusNode.unfocus();
|
||||||
|
|||||||
@ -83,6 +83,7 @@ class _SearchPanelState extends State<SearchPanel>
|
|||||||
case SearchType.video:
|
case SearchType.video:
|
||||||
return SearchVideoPanel(
|
return SearchVideoPanel(
|
||||||
ctr: _searchPanelController,
|
ctr: _searchPanelController,
|
||||||
|
// ignore: invalid_use_of_protected_member
|
||||||
list: list.value,
|
list: list.value,
|
||||||
);
|
);
|
||||||
case SearchType.media_bangumi:
|
case SearchType.media_bangumi:
|
||||||
|
|||||||
@ -1,6 +1,8 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
|
import 'package:pilipala/pages/setting/widgets/switch_item.dart';
|
||||||
|
import 'package:pilipala/plugin/pl_player/index.dart';
|
||||||
import 'package:pilipala/plugin/pl_player/models/play_speed.dart';
|
import 'package:pilipala/plugin/pl_player/models/play_speed.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
|
|
||||||
@ -13,9 +15,11 @@ class PlaySpeedPage extends StatefulWidget {
|
|||||||
|
|
||||||
class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
||||||
Box videoStorage = GStrorage.video;
|
Box videoStorage = GStrorage.video;
|
||||||
|
Box settingStorage = GStrorage.setting;
|
||||||
late double playSpeedDefault;
|
late double playSpeedDefault;
|
||||||
late double longPressSpeedDefault;
|
late double longPressSpeedDefault;
|
||||||
late List customSpeedsList;
|
late List customSpeedsList;
|
||||||
|
late bool enableAutoLongPressSpeed;
|
||||||
List<Map<dynamic, dynamic>> sheetMenu = [
|
List<Map<dynamic, dynamic>> sheetMenu = [
|
||||||
{
|
{
|
||||||
'id': 1,
|
'id': 1,
|
||||||
@ -24,6 +28,7 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
|||||||
Icons.speed,
|
Icons.speed,
|
||||||
size: 21,
|
size: 21,
|
||||||
),
|
),
|
||||||
|
'show': true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id': 2,
|
'id': 2,
|
||||||
@ -32,6 +37,7 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
|||||||
Icons.speed_sharp,
|
Icons.speed_sharp,
|
||||||
size: 21,
|
size: 21,
|
||||||
),
|
),
|
||||||
|
'show': true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id': -1,
|
'id': -1,
|
||||||
@ -40,6 +46,7 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
|||||||
Icons.delete_outline,
|
Icons.delete_outline,
|
||||||
size: 21,
|
size: 21,
|
||||||
),
|
),
|
||||||
|
'show': true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -55,6 +62,15 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
|||||||
// 自定义倍速
|
// 自定义倍速
|
||||||
customSpeedsList =
|
customSpeedsList =
|
||||||
videoStorage.get(VideoBoxKey.customSpeedsList, defaultValue: []);
|
videoStorage.get(VideoBoxKey.customSpeedsList, defaultValue: []);
|
||||||
|
enableAutoLongPressSpeed = settingStorage
|
||||||
|
.get(SettingBoxKey.enableAutoLongPressSpeed, defaultValue: false);
|
||||||
|
if (enableAutoLongPressSpeed) {
|
||||||
|
Map newItem = sheetMenu[1];
|
||||||
|
newItem['show'] = false;
|
||||||
|
setState(() {
|
||||||
|
sheetMenu[1] = newItem;
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加自定义倍速
|
// 添加自定义倍速
|
||||||
@ -120,7 +136,8 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
|||||||
//重要
|
//重要
|
||||||
itemCount: sheetMenu.length,
|
itemCount: sheetMenu.length,
|
||||||
itemBuilder: (BuildContext context, int index) {
|
itemBuilder: (BuildContext context, int index) {
|
||||||
return ListTile(
|
return sheetMenu[index]['show']
|
||||||
|
? ListTile(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
menuAction(type, i, sheetMenu[index]['id']);
|
menuAction(type, i, sheetMenu[index]['id']);
|
||||||
@ -132,7 +149,8 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
|||||||
sheetMenu[index]['title'],
|
sheetMenu[index]['title'],
|
||||||
style: Theme.of(context).textTheme.titleSmall,
|
style: Theme.of(context).textTheme.titleSmall,
|
||||||
),
|
),
|
||||||
);
|
)
|
||||||
|
: const SizedBox();
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -210,11 +228,27 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
|||||||
title: const Text('默认倍速'),
|
title: const Text('默认倍速'),
|
||||||
subtitle: Text(playSpeedDefault.toString()),
|
subtitle: Text(playSpeedDefault.toString()),
|
||||||
),
|
),
|
||||||
ListTile(
|
SetSwitchItem(
|
||||||
|
title: '动态长按倍速',
|
||||||
|
subTitle: '根据默认倍速长按时自动双倍',
|
||||||
|
setKey: SettingBoxKey.enableAutoLongPressSpeed,
|
||||||
|
defaultVal: enableAutoLongPressSpeed,
|
||||||
|
callFn: (val) {
|
||||||
|
Map newItem = sheetMenu[1];
|
||||||
|
val ? newItem['show'] = false : newItem['show'] = true;
|
||||||
|
setState(() {
|
||||||
|
sheetMenu[1] = newItem;
|
||||||
|
enableAutoLongPressSpeed = val;
|
||||||
|
});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
!enableAutoLongPressSpeed
|
||||||
|
? ListTile(
|
||||||
dense: false,
|
dense: false,
|
||||||
title: const Text('默认长按倍速'),
|
title: const Text('默认长按倍速'),
|
||||||
subtitle: Text(longPressSpeedDefault.toString()),
|
subtitle: Text(longPressSpeedDefault.toString()),
|
||||||
),
|
)
|
||||||
|
: const SizedBox(),
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
left: 14,
|
left: 14,
|
||||||
|
|||||||
@ -12,7 +12,6 @@ import 'package:pilipala/common/widgets/stat/view.dart';
|
|||||||
import 'package:pilipala/models/video_detail_res.dart';
|
import 'package:pilipala/models/video_detail_res.dart';
|
||||||
import 'package:pilipala/pages/video/detail/introduction/controller.dart';
|
import 'package:pilipala/pages/video/detail/introduction/controller.dart';
|
||||||
import 'package:pilipala/pages/video/detail/widgets/ai_detail.dart';
|
import 'package:pilipala/pages/video/detail/widgets/ai_detail.dart';
|
||||||
import 'package:pilipala/services/service_locator.dart';
|
|
||||||
import 'package:pilipala/utils/feed_back.dart';
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
import 'package:pilipala/utils/utils.dart';
|
import 'package:pilipala/utils/utils.dart';
|
||||||
|
|||||||
@ -27,6 +27,7 @@ class _PagesPanelState extends State<PagesPanel> {
|
|||||||
late int currentIndex;
|
late int currentIndex;
|
||||||
String heroTag = Get.arguments['heroTag'];
|
String heroTag = Get.arguments['heroTag'];
|
||||||
late VideoDetailController _videoDetailController;
|
late VideoDetailController _videoDetailController;
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -50,6 +51,12 @@ class _PagesPanelState extends State<PagesPanel> {
|
|||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
@ -80,23 +87,33 @@ class _PagesPanelState extends State<PagesPanel> {
|
|||||||
onPressed: () {
|
onPressed: () {
|
||||||
showBottomSheet(
|
showBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => Container(
|
builder: (BuildContext context) {
|
||||||
|
return StatefulBuilder(builder:
|
||||||
|
(BuildContext context, StateSetter setState) {
|
||||||
|
WidgetsBinding.instance
|
||||||
|
.addPostFrameCallback((_) async {
|
||||||
|
await Future.delayed(
|
||||||
|
const Duration(milliseconds: 200));
|
||||||
|
_scrollController.jumpTo(currentIndex * 56);
|
||||||
|
});
|
||||||
|
return Container(
|
||||||
height: widget.sheetHeight,
|
height: widget.sheetHeight,
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.background,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
Container(
|
Container(
|
||||||
height: 45,
|
height: 45,
|
||||||
padding:
|
padding: const EdgeInsets.only(
|
||||||
const EdgeInsets.only(left: 14, right: 14),
|
left: 14, right: 14),
|
||||||
child: Row(
|
child: Row(
|
||||||
mainAxisAlignment:
|
mainAxisAlignment:
|
||||||
MainAxisAlignment.spaceBetween,
|
MainAxisAlignment.spaceBetween,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
'合集(${episodes.length})',
|
'合集(${episodes.length})',
|
||||||
style:
|
style: Theme.of(context)
|
||||||
Theme.of(context).textTheme.titleMedium,
|
.textTheme
|
||||||
|
.titleMedium,
|
||||||
),
|
),
|
||||||
IconButton(
|
IconButton(
|
||||||
icon: const Icon(Icons.close),
|
icon: const Icon(Icons.close),
|
||||||
@ -114,29 +131,36 @@ class _PagesPanelState extends State<PagesPanel> {
|
|||||||
Expanded(
|
Expanded(
|
||||||
child: Material(
|
child: Material(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
|
controller: _scrollController,
|
||||||
itemCount: episodes.length,
|
itemCount: episodes.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return InkWell(
|
return ListTile(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
changeFucCall(episodes[index], index);
|
changeFucCall(
|
||||||
|
episodes[index], index);
|
||||||
Get.back();
|
Get.back();
|
||||||
},
|
},
|
||||||
child: Padding(
|
dense: false,
|
||||||
padding: const EdgeInsets.only(
|
leading: index == currentIndex
|
||||||
top: 10,
|
? Image.asset(
|
||||||
bottom: 10,
|
'assets/images/live.gif',
|
||||||
left: 15,
|
color: Theme.of(context)
|
||||||
right: 15),
|
.colorScheme
|
||||||
child: Text(
|
.primary,
|
||||||
|
height: 12,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
title: Text(
|
||||||
episodes[index].pagePart!,
|
episodes[index].pagePart!,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
color: index == currentIndex
|
color: index == currentIndex
|
||||||
? Theme.of(context)
|
? Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.primary
|
.primary
|
||||||
: Theme.of(context)
|
: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.onSurface),
|
.onSurface,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -146,7 +170,9 @@ class _PagesPanelState extends State<PagesPanel> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
|
|||||||
@ -28,6 +28,7 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
|||||||
late int currentIndex;
|
late int currentIndex;
|
||||||
String heroTag = Get.arguments['heroTag'];
|
String heroTag = Get.arguments['heroTag'];
|
||||||
late VideoDetailController _videoDetailController;
|
late VideoDetailController _videoDetailController;
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -73,6 +74,12 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
|||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Builder(builder: (context) {
|
return Builder(builder: (context) {
|
||||||
@ -90,7 +97,14 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () => showBottomSheet(
|
onTap: () => showBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => Container(
|
builder: (BuildContext context) {
|
||||||
|
return StatefulBuilder(
|
||||||
|
builder: (BuildContext context, StateSetter setState) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||||
|
await Future.delayed(const Duration(milliseconds: 200));
|
||||||
|
_scrollController.jumpTo(currentIndex * 56);
|
||||||
|
});
|
||||||
|
return Container(
|
||||||
height: widget.sheetHeight,
|
height: widget.sheetHeight,
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.background,
|
||||||
child: Column(
|
child: Column(
|
||||||
@ -114,29 +128,39 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
|||||||
),
|
),
|
||||||
Divider(
|
Divider(
|
||||||
height: 1,
|
height: 1,
|
||||||
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
color:
|
||||||
|
Theme.of(context).dividerColor.withOpacity(0.1),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Material(
|
child: Material(
|
||||||
child: ListView.builder(
|
child: ListView.builder(
|
||||||
|
controller: _scrollController,
|
||||||
itemCount: episodes.length,
|
itemCount: episodes.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return InkWell(
|
return ListTile(
|
||||||
onTap: () =>
|
onTap: () =>
|
||||||
changeFucCall(episodes[index], index),
|
changeFucCall(episodes[index], index),
|
||||||
child: Padding(
|
dense: false,
|
||||||
padding: const EdgeInsets.only(
|
leading: index == currentIndex
|
||||||
top: 10, bottom: 10, left: 15, right: 15),
|
? Image.asset(
|
||||||
child: Text(
|
'assets/images/live.gif',
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.primary,
|
||||||
|
height: 12,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
title: Text(
|
||||||
episodes[index].title!,
|
episodes[index].title!,
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
|
fontSize: 14,
|
||||||
color: index == currentIndex
|
color: index == currentIndex
|
||||||
? Theme.of(context)
|
? Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.primary
|
.primary
|
||||||
: Theme.of(context)
|
: Theme.of(context)
|
||||||
.colorScheme
|
.colorScheme
|
||||||
.onSurface),
|
.onSurface,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -146,7 +170,9 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
|
});
|
||||||
|
},
|
||||||
),
|
),
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(8, 12, 8, 12),
|
padding: const EdgeInsets.fromLTRB(8, 12, 8, 12),
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:pilipala/http/init.dart';
|
import 'package:pilipala/http/init.dart';
|
||||||
|
import 'package:pilipala/http/member.dart';
|
||||||
import 'package:pilipala/http/user.dart';
|
import 'package:pilipala/http/user.dart';
|
||||||
import 'package:pilipala/pages/home/index.dart';
|
import 'package:pilipala/pages/home/index.dart';
|
||||||
import 'package:pilipala/pages/media/index.dart';
|
import 'package:pilipala/pages/media/index.dart';
|
||||||
@ -102,7 +103,6 @@ class WebviewController extends GetxController {
|
|||||||
try {
|
try {
|
||||||
await SetCookie.onSet();
|
await SetCookie.onSet();
|
||||||
var result = await UserHttp.userInfo();
|
var result = await UserHttp.userInfo();
|
||||||
UserHttp.thirdLogin();
|
|
||||||
if (result['status'] && result['data'].isLogin) {
|
if (result['status'] && result['data'].isLogin) {
|
||||||
SmartDialog.showToast('登录成功');
|
SmartDialog.showToast('登录成功');
|
||||||
try {
|
try {
|
||||||
@ -115,6 +115,7 @@ class WebviewController extends GetxController {
|
|||||||
MediaController mediaCtr = Get.find<MediaController>();
|
MediaController mediaCtr = Get.find<MediaController>();
|
||||||
mediaCtr.mid = result['data'].mid;
|
mediaCtr.mid = result['data'].mid;
|
||||||
await LoginUtils.refreshLoginStatus(true);
|
await LoginUtils.refreshLoginStatus(true);
|
||||||
|
MemberHttp.cookieToKey();
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
SmartDialog.show(builder: (context) {
|
SmartDialog.show(builder: (context) {
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
|
|||||||
65
lib/pages/whisper/controller.dart
Normal file
65
lib/pages/whisper/controller.dart
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/http/msg.dart';
|
||||||
|
import 'package:pilipala/models/msg/account.dart';
|
||||||
|
import 'package:pilipala/models/msg/session.dart';
|
||||||
|
|
||||||
|
class WhisperController extends GetxController {
|
||||||
|
RxList<SessionList> sessionList = <SessionList>[].obs;
|
||||||
|
RxList<AccountListModel> accountList = <AccountListModel>[].obs;
|
||||||
|
bool isLoading = false;
|
||||||
|
|
||||||
|
Future querySessionList(String? type) async {
|
||||||
|
if (isLoading) return;
|
||||||
|
var res = await MsgHttp.sessionList(
|
||||||
|
endTs: type == 'onLoad' ? sessionList.last.sessionTs : null);
|
||||||
|
if (res['data'].sessionList != null && res['data'].sessionList.isNotEmpty) {
|
||||||
|
await queryAccountList(res['data'].sessionList);
|
||||||
|
// 将 accountList 转换为 Map 结构
|
||||||
|
Map<int, dynamic> accountMap = {};
|
||||||
|
for (var j in accountList) {
|
||||||
|
accountMap[j.mid!] = j;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 遍历 sessionList,通过 mid 查找并赋值 accountInfo
|
||||||
|
for (var i in res['data'].sessionList) {
|
||||||
|
var accountInfo = accountMap[i.talkerId];
|
||||||
|
if (accountInfo != null) {
|
||||||
|
i.accountInfo = accountInfo;
|
||||||
|
}
|
||||||
|
if (i.talkerId == 844424930131966) {
|
||||||
|
i.accountInfo = AccountListModel(
|
||||||
|
name: 'UP主小助手',
|
||||||
|
face:
|
||||||
|
'https://message.biliimg.com/bfs/im/489a63efadfb202366c2f88853d2217b5ddc7a13.png',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (res['status'] && res['data'].sessionList != null) {
|
||||||
|
if (type == 'onLoad') {
|
||||||
|
sessionList.addAll(res['data'].sessionList);
|
||||||
|
} else {
|
||||||
|
sessionList.value = res['data'].sessionList;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
isLoading = false;
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future queryAccountList(sessionList) async {
|
||||||
|
List midsList = sessionList.map((e) => e.talkerId!).toList();
|
||||||
|
var res = await MsgHttp.accountList(midsList.join(','));
|
||||||
|
if (res['status']) {
|
||||||
|
accountList.value = res['data'];
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future onLoad() async {
|
||||||
|
querySessionList('onLoad');
|
||||||
|
}
|
||||||
|
|
||||||
|
Future onRefresh() async {
|
||||||
|
querySessionList('onRefresh');
|
||||||
|
}
|
||||||
|
}
|
||||||
4
lib/pages/whisper/index.dart
Normal file
4
lib/pages/whisper/index.dart
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
library whisper;
|
||||||
|
|
||||||
|
export './controller.dart';
|
||||||
|
export './view.dart';
|
||||||
230
lib/pages/whisper/view.dart
Normal file
230
lib/pages/whisper/view.dart
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
import 'package:easy_debounce/easy_throttle.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
|
import 'package:pilipala/utils/utils.dart';
|
||||||
|
|
||||||
|
import 'controller.dart';
|
||||||
|
|
||||||
|
class WhisperPage extends StatefulWidget {
|
||||||
|
const WhisperPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<WhisperPage> createState() => _WhisperPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _WhisperPageState extends State<WhisperPage> {
|
||||||
|
late final WhisperController _whisperController =
|
||||||
|
Get.put(WhisperController());
|
||||||
|
late Future _futureBuilderFuture;
|
||||||
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_futureBuilderFuture = _whisperController.querySessionList('init');
|
||||||
|
_scrollController.addListener(_scrollListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future _scrollListener() async {
|
||||||
|
if (_scrollController.position.pixels >=
|
||||||
|
_scrollController.position.maxScrollExtent - 200) {
|
||||||
|
EasyThrottle.throttle('my-throttler', const Duration(milliseconds: 800),
|
||||||
|
() async {
|
||||||
|
await _whisperController.onLoad();
|
||||||
|
_whisperController.isLoading = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: const Text('消息'),
|
||||||
|
),
|
||||||
|
body: Column(
|
||||||
|
children: [
|
||||||
|
// LayoutBuilder(
|
||||||
|
// builder: (BuildContext context, BoxConstraints constraints) {
|
||||||
|
// // 在这里根据父级容器的约束条件构建小部件树
|
||||||
|
// return Padding(
|
||||||
|
// padding: const EdgeInsets.only(left: 20, right: 20),
|
||||||
|
// child: SizedBox(
|
||||||
|
// height: constraints.maxWidth / 5,
|
||||||
|
// child: GridView.count(
|
||||||
|
// primary: false,
|
||||||
|
// crossAxisCount: 4,
|
||||||
|
// padding: const EdgeInsets.all(0),
|
||||||
|
// childAspectRatio: 1.25,
|
||||||
|
// children: [
|
||||||
|
// Column(
|
||||||
|
// crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
|
// mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
// children: [
|
||||||
|
// SizedBox(
|
||||||
|
// width: 36,
|
||||||
|
// height: 36,
|
||||||
|
// child: IconButton(
|
||||||
|
// style: ButtonStyle(
|
||||||
|
// padding:
|
||||||
|
// MaterialStateProperty.all(EdgeInsets.zero),
|
||||||
|
// backgroundColor:
|
||||||
|
// MaterialStateProperty.resolveWith((states) {
|
||||||
|
// return Theme.of(context)
|
||||||
|
// .colorScheme
|
||||||
|
// .primary
|
||||||
|
// .withOpacity(0.1);
|
||||||
|
// }),
|
||||||
|
// ),
|
||||||
|
// onPressed: () {},
|
||||||
|
// icon: Icon(
|
||||||
|
// Icons.message_outlined,
|
||||||
|
// size: 18,
|
||||||
|
// color: Theme.of(context).colorScheme.primary,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// const SizedBox(height: 6),
|
||||||
|
// const Text('回复我的', style: TextStyle(fontSize: 13))
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ],
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
// );
|
||||||
|
// },
|
||||||
|
// ),
|
||||||
|
Expanded(
|
||||||
|
child: RefreshIndicator(
|
||||||
|
onRefresh: () async {
|
||||||
|
await _whisperController.onRefresh();
|
||||||
|
},
|
||||||
|
child: SingleChildScrollView(
|
||||||
|
controller: _scrollController,
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
FutureBuilder(
|
||||||
|
future: _futureBuilderFuture,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
|
Map data = snapshot.data as Map;
|
||||||
|
if (data['status']) {
|
||||||
|
List sessionList = _whisperController.sessionList;
|
||||||
|
return Obx(
|
||||||
|
() => sessionList.isEmpty
|
||||||
|
? const SizedBox()
|
||||||
|
: ListView.separated(
|
||||||
|
itemCount: sessionList.length,
|
||||||
|
shrinkWrap: true,
|
||||||
|
physics:
|
||||||
|
const NeverScrollableScrollPhysics(),
|
||||||
|
itemBuilder: (_, int i) {
|
||||||
|
return ListTile(
|
||||||
|
onTap: () => Get.toNamed(
|
||||||
|
'/whisperDetail',
|
||||||
|
parameters: {
|
||||||
|
'talkerId': sessionList[i]
|
||||||
|
.talkerId
|
||||||
|
.toString(),
|
||||||
|
'name': sessionList[i]
|
||||||
|
.accountInfo
|
||||||
|
.name,
|
||||||
|
'face': sessionList[i]
|
||||||
|
.accountInfo
|
||||||
|
.face,
|
||||||
|
'mid': sessionList[i]
|
||||||
|
.accountInfo
|
||||||
|
.mid
|
||||||
|
.toString(),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
leading: Badge(
|
||||||
|
isLabelVisible: false,
|
||||||
|
backgroundColor: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.primary,
|
||||||
|
label: Text(sessionList[i]
|
||||||
|
.unreadCount
|
||||||
|
.toString()),
|
||||||
|
alignment: Alignment.bottomRight,
|
||||||
|
child: NetworkImgLayer(
|
||||||
|
width: 45,
|
||||||
|
height: 45,
|
||||||
|
type: 'avatar',
|
||||||
|
src: sessionList[i]
|
||||||
|
.accountInfo
|
||||||
|
.face,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
title: Text(
|
||||||
|
sessionList[i].accountInfo.name),
|
||||||
|
subtitle: Text(
|
||||||
|
sessionList[i]
|
||||||
|
.lastMsg
|
||||||
|
.content['text'] ??
|
||||||
|
sessionList[i]
|
||||||
|
.lastMsg
|
||||||
|
.content['content'] ??
|
||||||
|
sessionList[i]
|
||||||
|
.lastMsg
|
||||||
|
.content['title'] ??
|
||||||
|
sessionList[i]
|
||||||
|
.lastMsg
|
||||||
|
.content[
|
||||||
|
'reply_content'] ??
|
||||||
|
'',
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.labelMedium!
|
||||||
|
.copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.outline)),
|
||||||
|
trailing: Text(
|
||||||
|
Utils.dateFormat(sessionList[i]
|
||||||
|
.lastMsg
|
||||||
|
.timestamp),
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.labelSmall!
|
||||||
|
.copyWith(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.outline),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
separatorBuilder:
|
||||||
|
(BuildContext context, int index) {
|
||||||
|
return Divider(
|
||||||
|
indent: 72,
|
||||||
|
endIndent: 20,
|
||||||
|
height: 6,
|
||||||
|
color: Colors.grey.withOpacity(0.1),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 请求错误
|
||||||
|
return SizedBox();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 骨架屏
|
||||||
|
return SizedBox();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
28
lib/pages/whisperDetail/controller.dart
Normal file
28
lib/pages/whisperDetail/controller.dart
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/http/msg.dart';
|
||||||
|
import 'package:pilipala/models/msg/session.dart';
|
||||||
|
|
||||||
|
class WhisperDetailController extends GetxController {
|
||||||
|
late int talkerId;
|
||||||
|
late String name;
|
||||||
|
late String face;
|
||||||
|
late String mid;
|
||||||
|
RxList<MessageItem> messageList = <MessageItem>[].obs;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void onInit() {
|
||||||
|
super.onInit();
|
||||||
|
talkerId = int.parse(Get.parameters['talkerId']!);
|
||||||
|
name = Get.parameters['name']!;
|
||||||
|
face = Get.parameters['face']!;
|
||||||
|
mid = Get.parameters['mid']!;
|
||||||
|
}
|
||||||
|
|
||||||
|
Future querySessionMsg() async {
|
||||||
|
var res = await MsgHttp.sessionMsg(talkerId: talkerId);
|
||||||
|
if (res['status']) {
|
||||||
|
messageList.value = res['data'].messages;
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
}
|
||||||
4
lib/pages/whisperDetail/index.dart
Normal file
4
lib/pages/whisperDetail/index.dart
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
library whisper_detail;
|
||||||
|
|
||||||
|
export './controller.dart';
|
||||||
|
export './view.dart';
|
||||||
193
lib/pages/whisperDetail/view.dart
Normal file
193
lib/pages/whisperDetail/view.dart
Normal file
@ -0,0 +1,193 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
|
import 'package:pilipala/pages/whisperDetail/controller.dart';
|
||||||
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
|
|
||||||
|
import 'widget/chat_item.dart';
|
||||||
|
|
||||||
|
class WhisperDetailPage extends StatefulWidget {
|
||||||
|
const WhisperDetailPage({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<WhisperDetailPage> createState() => _WhisperDetailPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _WhisperDetailPageState extends State<WhisperDetailPage> {
|
||||||
|
final WhisperDetailController _whisperDetailController =
|
||||||
|
Get.put(WhisperDetailController());
|
||||||
|
late Future _futureBuilderFuture;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
_futureBuilderFuture = _whisperDetailController.querySessionMsg();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
automaticallyImplyLeading: false,
|
||||||
|
title: SizedBox(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 50,
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
width: 34,
|
||||||
|
height: 34,
|
||||||
|
child: IconButton(
|
||||||
|
style: ButtonStyle(
|
||||||
|
padding: MaterialStateProperty.all(EdgeInsets.zero),
|
||||||
|
backgroundColor:
|
||||||
|
MaterialStateProperty.resolveWith((states) {
|
||||||
|
return Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.primaryContainer
|
||||||
|
.withOpacity(0.6);
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
onPressed: () => Get.back(),
|
||||||
|
icon: Icon(
|
||||||
|
Icons.arrow_back_outlined,
|
||||||
|
size: 18,
|
||||||
|
color: Theme.of(context).colorScheme.onPrimaryContainer,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
GestureDetector(
|
||||||
|
onTap: () {
|
||||||
|
feedBack();
|
||||||
|
Get.toNamed(
|
||||||
|
'/member?mid=${_whisperDetailController.mid}',
|
||||||
|
arguments: {
|
||||||
|
'face': _whisperDetailController.face,
|
||||||
|
'heroTag': null
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
child: Row(
|
||||||
|
children: [
|
||||||
|
NetworkImgLayer(
|
||||||
|
width: 34,
|
||||||
|
height: 34,
|
||||||
|
type: 'avatar',
|
||||||
|
src: _whisperDetailController.face,
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
Text(
|
||||||
|
_whisperDetailController.name,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 36, height: 36),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
body: FutureBuilder(
|
||||||
|
future: _futureBuilderFuture,
|
||||||
|
builder: (context, snapshot) {
|
||||||
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
|
Map data = snapshot.data as Map;
|
||||||
|
if (data['status']) {
|
||||||
|
List messageList = _whisperDetailController.messageList;
|
||||||
|
return Obx(
|
||||||
|
() => messageList.isEmpty
|
||||||
|
? const SizedBox()
|
||||||
|
: ListView.builder(
|
||||||
|
itemCount: messageList.length,
|
||||||
|
shrinkWrap: true,
|
||||||
|
reverse: true,
|
||||||
|
itemBuilder: (_, int i) {
|
||||||
|
if (i == 0) {
|
||||||
|
return Column(
|
||||||
|
children: [
|
||||||
|
ChatItem(item: messageList[i]),
|
||||||
|
const SizedBox(height: 12),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
return ChatItem(item: messageList[i]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
// 请求错误
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// 骨架屏
|
||||||
|
return const SizedBox();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
// resizeToAvoidBottomInset: true,
|
||||||
|
bottomNavigationBar: Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: MediaQuery.of(context).padding.bottom + 70,
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
left: 8,
|
||||||
|
right: 12,
|
||||||
|
top: 12,
|
||||||
|
bottom: MediaQuery.of(context).padding.bottom,
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Colors.white,
|
||||||
|
border: Border(
|
||||||
|
top: BorderSide(
|
||||||
|
width: 4,
|
||||||
|
color: Theme.of(context).colorScheme.primary.withOpacity(0.1),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
// IconButton(
|
||||||
|
// onPressed: () {},
|
||||||
|
// icon: Icon(
|
||||||
|
// Icons.add_circle_outline,
|
||||||
|
// color: Theme.of(context).colorScheme.outline,
|
||||||
|
// ),
|
||||||
|
// ),
|
||||||
|
IconButton(
|
||||||
|
onPressed: () {},
|
||||||
|
icon: Icon(
|
||||||
|
Icons.emoji_emotions_outlined,
|
||||||
|
color: Theme.of(context).colorScheme.outline,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
height: 45,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color:
|
||||||
|
Theme.of(context).colorScheme.primary.withOpacity(0.08),
|
||||||
|
borderRadius: BorderRadius.circular(40.0),
|
||||||
|
),
|
||||||
|
child: TextField(
|
||||||
|
readOnly: true,
|
||||||
|
style: Theme.of(context).textTheme.titleMedium,
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: InputBorder.none, // 移除默认边框
|
||||||
|
hintText: '开发中 ...', // 提示文本
|
||||||
|
contentPadding: EdgeInsets.symmetric(
|
||||||
|
horizontal: 16.0, vertical: 12.0), // 内边距
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
190
lib/pages/whisperDetail/widget/chat_item.dart
Normal file
190
lib/pages/whisperDetail/widget/chat_item.dart
Normal file
@ -0,0 +1,190 @@
|
|||||||
|
// ignore_for_file: must_be_immutable
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:pilipala/common/widgets/network_img_layer.dart';
|
||||||
|
import 'package:pilipala/utils/utils.dart';
|
||||||
|
|
||||||
|
class ChatItem extends StatelessWidget {
|
||||||
|
dynamic item;
|
||||||
|
|
||||||
|
ChatItem({
|
||||||
|
super.key,
|
||||||
|
this.item,
|
||||||
|
});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
bool isOwner = item.senderUid == 17340771;
|
||||||
|
bool isPic = item.msgType == 2;
|
||||||
|
bool isText = item.msgType == 1;
|
||||||
|
bool isAchive = item.msgType == 11;
|
||||||
|
bool isArticle = item.msgType == 12;
|
||||||
|
|
||||||
|
bool isSystem =
|
||||||
|
item.msgType == 18 || item.msgType == 10 || item.msgType == 13;
|
||||||
|
int msgType = item.msgType;
|
||||||
|
Map content = item.content ?? '';
|
||||||
|
return isSystem
|
||||||
|
? (msgType == 10
|
||||||
|
? SystemNotice(item: item)
|
||||||
|
: msgType == 13
|
||||||
|
? SystemNotice2(item: item)
|
||||||
|
: const SizedBox())
|
||||||
|
: Row(
|
||||||
|
children: [
|
||||||
|
if (!isOwner) const SizedBox(width: 12),
|
||||||
|
if (isOwner) const Spacer(),
|
||||||
|
Container(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 300.0, // 设置最大宽度为200.0
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: isOwner
|
||||||
|
? Theme.of(context).colorScheme.primary
|
||||||
|
: Theme.of(context).colorScheme.secondaryContainer,
|
||||||
|
borderRadius: BorderRadius.only(
|
||||||
|
topLeft: const Radius.circular(16),
|
||||||
|
topRight: const Radius.circular(16),
|
||||||
|
bottomLeft: Radius.circular(isOwner ? 16 : 6),
|
||||||
|
bottomRight: Radius.circular(isOwner ? 6 : 16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
margin: const EdgeInsets.only(top: 12),
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
top: 8,
|
||||||
|
bottom: 6,
|
||||||
|
left: isPic ? 8 : 12,
|
||||||
|
right: isPic ? 8 : 12,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: isOwner
|
||||||
|
? CrossAxisAlignment.end
|
||||||
|
: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
isText
|
||||||
|
? Text(
|
||||||
|
content['content'],
|
||||||
|
style: TextStyle(
|
||||||
|
color: isOwner
|
||||||
|
? Theme.of(context).colorScheme.onPrimary
|
||||||
|
: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSecondaryContainer),
|
||||||
|
)
|
||||||
|
: isPic
|
||||||
|
? NetworkImgLayer(
|
||||||
|
width: 220,
|
||||||
|
height:
|
||||||
|
220 * content['height'] / content['width'],
|
||||||
|
src: content['url'],
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
|
SizedBox(height: isPic ? 7 : 2),
|
||||||
|
Text(
|
||||||
|
Utils.dateFormat(item.timestamp),
|
||||||
|
style: Theme.of(context).textTheme.labelSmall!.copyWith(
|
||||||
|
color: isOwner
|
||||||
|
? Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onPrimary
|
||||||
|
.withOpacity(0.8)
|
||||||
|
: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.onSecondaryContainer
|
||||||
|
.withOpacity(0.8)),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (!isOwner) const Spacer(),
|
||||||
|
if (isOwner) const SizedBox(width: 12),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SystemNotice extends StatelessWidget {
|
||||||
|
dynamic item;
|
||||||
|
SystemNotice({super.key, this.item});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Map content = item.content ?? '';
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Container(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 300.0, // 设置最大宽度为200.0
|
||||||
|
),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context)
|
||||||
|
.colorScheme
|
||||||
|
.secondaryContainer
|
||||||
|
.withOpacity(0.4),
|
||||||
|
borderRadius: const BorderRadius.only(
|
||||||
|
topLeft: Radius.circular(16),
|
||||||
|
topRight: Radius.circular(16),
|
||||||
|
bottomLeft: Radius.circular(6),
|
||||||
|
bottomRight: Radius.circular(16),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
margin: const EdgeInsets.only(top: 12),
|
||||||
|
padding: const EdgeInsets.all(12),
|
||||||
|
child: Column(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Text(content['title'],
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.titleMedium!
|
||||||
|
.copyWith(fontWeight: FontWeight.bold)),
|
||||||
|
Text(
|
||||||
|
Utils.dateFormat(item.timestamp),
|
||||||
|
style: Theme.of(context)
|
||||||
|
.textTheme
|
||||||
|
.labelSmall!
|
||||||
|
.copyWith(color: Theme.of(context).colorScheme.outline),
|
||||||
|
),
|
||||||
|
Divider(
|
||||||
|
color: Theme.of(context).colorScheme.primary.withOpacity(0.05),
|
||||||
|
),
|
||||||
|
Text(
|
||||||
|
content['text'],
|
||||||
|
)
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SystemNotice2 extends StatelessWidget {
|
||||||
|
dynamic item;
|
||||||
|
SystemNotice2({super.key, this.item});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
Map content = item.content ?? '';
|
||||||
|
return Row(
|
||||||
|
children: [
|
||||||
|
const SizedBox(width: 12),
|
||||||
|
Container(
|
||||||
|
constraints: const BoxConstraints(
|
||||||
|
maxWidth: 300.0, // 设置最大宽度为200.0
|
||||||
|
),
|
||||||
|
margin: const EdgeInsets.only(top: 12),
|
||||||
|
padding: const EdgeInsets.only(bottom: 6),
|
||||||
|
child: NetworkImgLayer(
|
||||||
|
width: 320,
|
||||||
|
height: 150,
|
||||||
|
src: content['pic_url'],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const Spacer(),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,7 +6,6 @@ import 'dart:typed_data';
|
|||||||
|
|
||||||
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:flutter_smart_dialog/flutter_smart_dialog.dart';
|
|
||||||
import 'package:flutter_volume_controller/flutter_volume_controller.dart';
|
import 'package:flutter_volume_controller/flutter_volume_controller.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
@ -221,6 +220,7 @@ class PlPlayerController {
|
|||||||
late List speedsList;
|
late List speedsList;
|
||||||
// 缓存
|
// 缓存
|
||||||
double? defaultDuration;
|
double? defaultDuration;
|
||||||
|
late bool enableAutoLongPressSpeed = false;
|
||||||
|
|
||||||
// 播放顺序相关
|
// 播放顺序相关
|
||||||
PlayRepeat playRepeat = PlayRepeat.pause;
|
PlayRepeat playRepeat = PlayRepeat.pause;
|
||||||
@ -250,8 +250,12 @@ class PlPlayerController {
|
|||||||
);
|
);
|
||||||
_playbackSpeed.value =
|
_playbackSpeed.value =
|
||||||
videoStorage.get(VideoBoxKey.playSpeedDefault, defaultValue: 1.0);
|
videoStorage.get(VideoBoxKey.playSpeedDefault, defaultValue: 1.0);
|
||||||
_longPressSpeed.value =
|
enableAutoLongPressSpeed = setting
|
||||||
videoStorage.get(VideoBoxKey.longPressSpeedDefault, defaultValue: 2.0);
|
.get(SettingBoxKey.enableAutoLongPressSpeed, defaultValue: false);
|
||||||
|
if (!enableAutoLongPressSpeed) {
|
||||||
|
_longPressSpeed.value = videoStorage
|
||||||
|
.get(VideoBoxKey.longPressSpeedDefault, defaultValue: 2.0);
|
||||||
|
}
|
||||||
List speedsListTemp =
|
List speedsListTemp =
|
||||||
videoStorage.get(VideoBoxKey.customSpeedsList, defaultValue: []);
|
videoStorage.get(VideoBoxKey.customSpeedsList, defaultValue: []);
|
||||||
speedsList = List.from(speedsListTemp);
|
speedsList = List.from(speedsListTemp);
|
||||||
@ -859,7 +863,8 @@ class PlPlayerController {
|
|||||||
}
|
}
|
||||||
_doubleSpeedStatus.value = val;
|
_doubleSpeedStatus.value = val;
|
||||||
if (val) {
|
if (val) {
|
||||||
setPlaybackSpeed(longPressSpeed);
|
setPlaybackSpeed(
|
||||||
|
enableAutoLongPressSpeed ? playbackSpeed * 2 : longPressSpeed);
|
||||||
} else {
|
} else {
|
||||||
print(playbackSpeed);
|
print(playbackSpeed);
|
||||||
setPlaybackSpeed(playbackSpeed);
|
setPlaybackSpeed(playbackSpeed);
|
||||||
|
|||||||
@ -27,7 +27,6 @@ import 'package:pilipala/pages/member_dynamics/index.dart';
|
|||||||
import 'package:pilipala/pages/member_like/index.dart';
|
import 'package:pilipala/pages/member_like/index.dart';
|
||||||
import 'package:pilipala/pages/member_search/index.dart';
|
import 'package:pilipala/pages/member_search/index.dart';
|
||||||
import 'package:pilipala/pages/member_seasons/index.dart';
|
import 'package:pilipala/pages/member_seasons/index.dart';
|
||||||
import 'package:pilipala/pages/preview/index.dart';
|
|
||||||
import 'package:pilipala/pages/search/index.dart';
|
import 'package:pilipala/pages/search/index.dart';
|
||||||
import 'package:pilipala/pages/searchResult/index.dart';
|
import 'package:pilipala/pages/searchResult/index.dart';
|
||||||
import 'package:pilipala/pages/setting/extra_setting.dart';
|
import 'package:pilipala/pages/setting/extra_setting.dart';
|
||||||
@ -43,6 +42,8 @@ import 'package:pilipala/pages/video/detail/replyReply/index.dart';
|
|||||||
import 'package:pilipala/pages/webview/index.dart';
|
import 'package:pilipala/pages/webview/index.dart';
|
||||||
import 'package:pilipala/pages/setting/index.dart';
|
import 'package:pilipala/pages/setting/index.dart';
|
||||||
import 'package:pilipala/pages/media/index.dart';
|
import 'package:pilipala/pages/media/index.dart';
|
||||||
|
import 'package:pilipala/pages/whisper/index.dart';
|
||||||
|
import 'package:pilipala/pages/whisperDetail/index.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
|
|
||||||
Box setting = GStrorage.setting;
|
Box setting = GStrorage.setting;
|
||||||
@ -128,6 +129,11 @@ class Routes {
|
|||||||
CustomGetPage(name: '/playSpeedSet', page: () => const PlaySpeedPage()),
|
CustomGetPage(name: '/playSpeedSet', page: () => const PlaySpeedPage()),
|
||||||
// 收藏搜索
|
// 收藏搜索
|
||||||
CustomGetPage(name: '/favSearch', page: () => const FavSearchPage()),
|
CustomGetPage(name: '/favSearch', page: () => const FavSearchPage()),
|
||||||
|
// 消息页面
|
||||||
|
CustomGetPage(name: '/whisper', page: () => const WhisperPage()),
|
||||||
|
// 私信详情
|
||||||
|
CustomGetPage(
|
||||||
|
name: '/whisperDetail', page: () => const WhisperDetailPage()),
|
||||||
// 登录页面
|
// 登录页面
|
||||||
CustomGetPage(name: '/loginPage', page: () => const LoginPage()),
|
CustomGetPage(name: '/loginPage', page: () => const LoginPage()),
|
||||||
// 用户动态
|
// 用户动态
|
||||||
|
|||||||
@ -107,6 +107,7 @@ class SettingBoxKey {
|
|||||||
static const String p1080 = 'p1080';
|
static const String p1080 = 'p1080';
|
||||||
static const String enableCDN = 'enableCDN';
|
static const String enableCDN = 'enableCDN';
|
||||||
static const String autoPiP = 'autoPiP';
|
static const String autoPiP = 'autoPiP';
|
||||||
|
static const String enableAutoLongPressSpeed = 'enableAutoLongPressSpeed';
|
||||||
|
|
||||||
// youtube 双击快进快退
|
// youtube 双击快进快退
|
||||||
static const String enableQuickDouble = 'enableQuickDouble';
|
static const String enableQuickDouble = 'enableQuickDouble';
|
||||||
|
|||||||
Reference in New Issue
Block a user