.
diff --git a/README.md b/README.md
index 46f6d986..237bd07f 100644
--- a/README.md
+++ b/README.md
@@ -14,11 +14,11 @@
使用Flutter开发的BiliBili第三方客户端
-
-
-
+
+
+
-
+
@@ -26,13 +26,15 @@
Xcode 13.4 不支持**auto_orientation**,请注释相关代码
```bash
-[✓] Flutter (Channel stable, 3.10.6, on macOS 12.1 21C52 darwin-arm64, locale
+[✓] Flutter (Channel stable, 3.16.4, on macOS 14.1.2 23B92 darwin-arm64, locale
zh-Hans-CN)
-[✓] Android toolchain - develop for Android devices (Android SDK version 33.0.2)
-[✓] Xcode - develop for iOS and macOS (Xcode 13.4)
+[✓] Android toolchain - develop for Android devices (Android SDK version 34.0.0)
+[✓] Xcode - develop for iOS and macOS (Xcode 15.1)
[✓] Chrome - develop for the web
-[✓] Android Studio (version 2022.2)
-[✓] VS Code (version 1.77.3)
+[✓] Android Studio (version 2022.3)
+[✓] VS Code (version 1.85.1)
+[✓] Connected device (3 available)
+[✓] Network resources
```
@@ -42,6 +44,7 @@ Xcode 13.4 不支持**auto_orientation**,请注释相关代码
## 技术交流
Telegram: https://t.me/+lm_oOVmF0RJiODk1
+QQ频道: https://pd.qq.com/s/365esodk3
@@ -87,7 +90,7 @@ Telegram: https://t.me/+lm_oOVmF0RJiODk1
- [x] 画质选择(高清画质未解锁)
- [x] 音质选择(视视频而定)
- [x] 解码格式选择(视视频而定)
- - [ ] 弹幕
+ - [x] 弹幕
- [ ] 字幕
- [x] 记忆播放
- [x] 视频比例:高度/宽度适应、填充、包含等
diff --git a/assets/sreenshot/174shots_so.png b/assets/screenshots/174shots_so.png
similarity index 100%
rename from assets/sreenshot/174shots_so.png
rename to assets/screenshots/174shots_so.png
diff --git a/assets/sreenshot/510shots_so.png b/assets/screenshots/510shots_so.png
similarity index 100%
rename from assets/sreenshot/510shots_so.png
rename to assets/screenshots/510shots_so.png
diff --git a/assets/sreenshot/850shots_so.png b/assets/screenshots/850shots_so.png
similarity index 100%
rename from assets/sreenshot/850shots_so.png
rename to assets/screenshots/850shots_so.png
diff --git a/assets/sreenshot/bangumi.png b/assets/screenshots/bangumi.png
similarity index 100%
rename from assets/sreenshot/bangumi.png
rename to assets/screenshots/bangumi.png
diff --git a/assets/sreenshot/bangumi_detail.png b/assets/screenshots/bangumi_detail.png
similarity index 100%
rename from assets/sreenshot/bangumi_detail.png
rename to assets/screenshots/bangumi_detail.png
diff --git a/assets/sreenshot/dynamic.png b/assets/screenshots/dynamic.png
similarity index 100%
rename from assets/sreenshot/dynamic.png
rename to assets/screenshots/dynamic.png
diff --git a/assets/sreenshot/home.png b/assets/screenshots/home.png
similarity index 100%
rename from assets/sreenshot/home.png
rename to assets/screenshots/home.png
diff --git a/assets/sreenshot/main_screen.png b/assets/screenshots/main_screen.png
similarity index 100%
rename from assets/sreenshot/main_screen.png
rename to assets/screenshots/main_screen.png
diff --git a/assets/sreenshot/media.png b/assets/screenshots/media.png
similarity index 100%
rename from assets/sreenshot/media.png
rename to assets/screenshots/media.png
diff --git a/assets/sreenshot/member.png b/assets/screenshots/member.png
similarity index 100%
rename from assets/sreenshot/member.png
rename to assets/screenshots/member.png
diff --git a/assets/sreenshot/search.png b/assets/screenshots/search.png
similarity index 100%
rename from assets/sreenshot/search.png
rename to assets/screenshots/search.png
diff --git a/assets/sreenshot/set.png b/assets/screenshots/set.png
similarity index 100%
rename from assets/sreenshot/set.png
rename to assets/screenshots/set.png
diff --git a/change_log/1.0.15.0101.md b/change_log/1.0.15.0101.md
new file mode 100644
index 00000000..184a6b3c
--- /dev/null
+++ b/change_log/1.0.15.0101.md
@@ -0,0 +1,22 @@
+## 1.0.15
+
+元旦快乐~ 🎉
+
+### 功能
++ 转发动态评论展示
++ 推荐、最热、收藏视频增肌日期显示
+
+### 修复
++ 全屏播放相关问题
++ 评论区@用户展示问题
++ 登录状态闪退问题
++ pip意外触发问题
++ 动态页tab切换样式问题
+
+### 优化
++ 首页默认使用web端推荐
++ 取消iOS路由切换效果
++ 视频分享中添加Up主
+
+更多更新日志可在Github上查看
+问题反馈、功能建议请查看「关于」页面。
diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt
new file mode 100644
index 00000000..1a6e2446
--- /dev/null
+++ b/fastlane/metadata/android/en-US/full_description.txt
@@ -0,0 +1,9 @@
+PiliPala is a third-party Bilibili client developed in Flutter.
+
+Top Features:
+
+* List of recommended videos
+* List of hottest videos
+* Popular live streams
+* List of bangumis
+* Block videos from blacklisted users
diff --git a/fastlane/metadata/android/en-US/images/featureGraphic.png b/fastlane/metadata/android/en-US/images/featureGraphic.png
new file mode 100644
index 00000000..1f72277e
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/featureGraphic.png differ
diff --git a/fastlane/metadata/android/en-US/images/icon.png b/fastlane/metadata/android/en-US/images/icon.png
new file mode 100644
index 00000000..db737743
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/icon.png differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png
new file mode 100644
index 00000000..ae00cf9f
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/1.png differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png
new file mode 100644
index 00000000..bf16b34f
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/2.png differ
diff --git a/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png b/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png
new file mode 100644
index 00000000..fbdfb88c
Binary files /dev/null and b/fastlane/metadata/android/en-US/images/phoneScreenshots/3.png differ
diff --git a/fastlane/metadata/android/en-US/short_description.txt b/fastlane/metadata/android/en-US/short_description.txt
new file mode 100644
index 00000000..429e00fb
--- /dev/null
+++ b/fastlane/metadata/android/en-US/short_description.txt
@@ -0,0 +1 @@
+A third-party Bilibili client developed in Flutter
diff --git a/fastlane/metadata/android/en-US/title.txt b/fastlane/metadata/android/en-US/title.txt
new file mode 100644
index 00000000..2b0d34f3
--- /dev/null
+++ b/fastlane/metadata/android/en-US/title.txt
@@ -0,0 +1 @@
+PiliPala
diff --git a/fastlane/metadata/android/zh-CN/changelogs/2001.txt b/fastlane/metadata/android/zh-CN/changelogs/2001.txt
new file mode 100644
index 00000000..a5e2c0a4
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/changelogs/2001.txt
@@ -0,0 +1,21 @@
+修复
+
+* 全屏弹幕消失
+* iOS 全屏/退出全屏视频暂停
+* 个人主页关注状态
+* 视频合集向下滑动UI问题
+* 媒体库滑动底栏不隐藏
+* 个人主页动态加载问题 * 2
+* 未登录状态访问个人主页异常
+* 视频搜索标题特殊字符转义
+* iOS 闪退
+* 消息页面夜间模式异常
+* 消息页面含有撤回消息时异常
+* 弹幕速度
+
+优化
+
+* 全屏播放方案优化
+* 弹幕加载逻辑优化
+* 点赞、投币逻辑优化
+* 进度条及播放时间渲染优化
diff --git a/fastlane/metadata/android/zh-CN/full_description.txt b/fastlane/metadata/android/zh-CN/full_description.txt
new file mode 100644
index 00000000..361386e6
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/full_description.txt
@@ -0,0 +1,9 @@
+PiliPala 是使用 Flutter 开发的 BiliBili 第三方客户端。
+
+主要功能:
+
+* 推荐视频列表 (app 端)
+* 最热视频列表
+* 热门直播
+* 番剧列表
+* 屏蔽黑名单内用户视频
diff --git a/fastlane/metadata/android/zh-CN/images/featureGraphic.png b/fastlane/metadata/android/zh-CN/images/featureGraphic.png
new file mode 100644
index 00000000..1f72277e
Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/featureGraphic.png differ
diff --git a/fastlane/metadata/android/zh-CN/images/icon.png b/fastlane/metadata/android/zh-CN/images/icon.png
new file mode 100644
index 00000000..db737743
Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/icon.png differ
diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/1.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/1.png
new file mode 100644
index 00000000..ae00cf9f
Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/1.png differ
diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/2.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/2.png
new file mode 100644
index 00000000..bf16b34f
Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/2.png differ
diff --git a/fastlane/metadata/android/zh-CN/images/phoneScreenshots/3.png b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/3.png
new file mode 100644
index 00000000..fbdfb88c
Binary files /dev/null and b/fastlane/metadata/android/zh-CN/images/phoneScreenshots/3.png differ
diff --git a/fastlane/metadata/android/zh-CN/short_description.txt b/fastlane/metadata/android/zh-CN/short_description.txt
new file mode 100644
index 00000000..683129cc
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/short_description.txt
@@ -0,0 +1 @@
+使用 Flutter 开发的 BiliBili 第三方客户端
diff --git a/fastlane/metadata/android/zh-CN/title.txt b/fastlane/metadata/android/zh-CN/title.txt
new file mode 100644
index 00000000..2b0d34f3
--- /dev/null
+++ b/fastlane/metadata/android/zh-CN/title.txt
@@ -0,0 +1 @@
+PiliPala
diff --git a/lib/http/api.dart b/lib/http/api.dart
index 75a121ac..c8edf863 100644
--- a/lib/http/api.dart
+++ b/lib/http/api.dart
@@ -1,15 +1,17 @@
+import 'constants.dart';
+
class Api {
// 推荐视频
static const String recommendListApp =
- 'https://app.bilibili.com/x/v2/feed/index';
- static const String recommendList = '/x/web-interface/index/top/feed/rcmd';
+ '${HttpString.appBaseUrl}/x/v2/feed/index';
+ static const String recommendListWeb = '/x/web-interface/index/top/feed/rcmd';
// 热门视频
static const String hotList = '/x/web-interface/popular';
// 视频流
// https://github.com/SocialSisterYi/bilibili-API-collect/blob/master/docs/video/videostream_url.md
- static const String videoUrl = '/x/player/playurl';
+ static const String videoUrl = '/x/player/wbi/playurl';
// 视频详情
// 竖屏 https://api.bilibili.com/x/web-interface/view?aid=527403921
@@ -152,7 +154,7 @@ class Api {
// 动态点赞
static const String likeDynamic =
- 'https://api.vc.bilibili.com/dynamic_like/v1/dynamic_like/thumb';
+ '${HttpString.tUrl}/dynamic_like/v1/dynamic_like/thumb';
// 获取稍后再看
static const String seeYouLater = '/x/v2/history/toview';
@@ -220,13 +222,13 @@ class Api {
// 直播
// ?page=1&page_size=30&platform=web
static const String liveList =
- 'https://api.live.bilibili.com/xlive/web-interface/v1/second/getUserRecommend';
+ '${HttpString.liveBaseUrl}/xlive/web-interface/v1/second/getUserRecommend';
// 直播间详情
// cid roomId
// qn 80:流畅,150:高清,400:蓝光,10000:原画,20000:4K, 30000:杜比
static const String liveRoomInfo =
- 'https://api.live.bilibili.com/xlive/web-room/v2/index/getRoomPlayInfo';
+ '${HttpString.liveBaseUrl}/xlive/web-room/v2/index/getRoomPlayInfo';
// 用户信息 需要Wbi签名
// https://api.bilibili.com/x/space/wbi/acc/info?mid=503427686&token=&platform=web&web_location=1550101&w_rid=d709892496ce93e3d94d6d37c95bde91&wts=1689301482
@@ -338,13 +340,13 @@ class Api {
/// wts=1697305010
static const String sessionList =
- 'https://api.vc.bilibili.com/session_svr/v1/session_svr/get_sessions';
+ '${HttpString.tUrl}/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';
+ '${HttpString.tUrl}/account/v1/user/cards';
/// https://api.vc.bilibili.com/svr_sync/v1/svr_sync/fetch_session_msgs?
/// talker_id=400787461&
@@ -358,7 +360,7 @@ class Api {
/// wts=1697350697
static const String sessionMsg =
- 'https://api.vc.bilibili.com/svr_sync/v1/svr_sync/fetch_session_msgs';
+ '${HttpString.tUrl}/svr_sync/v1/svr_sync/fetch_session_msgs';
/// 标记已读 POST
/// talker_id:
@@ -369,7 +371,7 @@ class Api {
/// csrf_token:
/// csrf:
static const String updateAck =
- 'https://api.vc.bilibili.com/session_svr/v1/session_svr/update_ack';
+ '${HttpString.tUrl}/session_svr/v1/session_svr/update_ack';
// 获取某个动态详情
// timezone_offset=-480
@@ -388,11 +390,11 @@ class Api {
// captcha验证码
static const String getCaptcha =
- 'https://passport.bilibili.com/x/passport-login/captcha?source=main_web';
+ '${HttpString.passBaseUrl}/x/passport-login/captcha?source=main_web';
// web端短信验证码
static const String smsCode =
- 'https://passport.bilibili.com/x/passport-login/web/sms/send';
+ '${HttpString.passBaseUrl}/x/passport-login/web/sms/send';
// web端验证码登录
@@ -400,7 +402,7 @@ class Api {
// app端短信验证码
static const String appSmsCode =
- 'https://passport.bilibili.com/x/passport-login/sms/send';
+ '${HttpString.passBaseUrl}/x/passport-login/sms/send';
// app端验证码登录
@@ -414,17 +416,16 @@ class Api {
/// key
/// rhash
static const String loginInByPwdApi =
- 'https://passport.bilibili.com/x/passport-login/oauth2/login';
+ '${HttpString.passBaseUrl}/x/passport-login/oauth2/login';
/// 密码加密密钥
/// disable_rcmd
/// local_id
- static const getWebKey =
- 'https://passport.bilibili.com/x/passport-login/web/key';
+ static const getWebKey = '${HttpString.passBaseUrl}/x/passport-login/web/key';
/// cookie转access_key
static const cookieToKey =
- 'https://passport.bilibili.com/x/passport-tv-login/h5/qrcode/confirm';
+ '${HttpString.passBaseUrl}/x/passport-tv-login/h5/qrcode/confirm';
/// 申请二维码(TV端)
static const getTVCode =
@@ -432,7 +433,7 @@ class Api {
///扫码登录(TV端)
static const qrcodePoll =
- 'https://passport.bilibili.com/x/passport-tv-login/qrcode/poll';
+ '${HttpString.passBaseUrl}/x/passport-tv-login/qrcode/poll';
/// 置顶视频
static const getTopVideoApi = '/x/space/top/arc';
diff --git a/lib/http/constants.dart b/lib/http/constants.dart
index cf10a606..3d749ee8 100644
--- a/lib/http/constants.dart
+++ b/lib/http/constants.dart
@@ -1,7 +1,10 @@
class HttpString {
static const String baseUrl = 'https://www.bilibili.com';
- static const String baseApiUrl = 'https://api.bilibili.com';
+ static const String apiBaseUrl = 'https://api.bilibili.com';
static const String tUrl = 'https://api.vc.bilibili.com';
+ static const String appBaseUrl = 'https://app.bilibili.com';
+ static const String liveBaseUrl = 'https://api.live.bilibili.com';
+ static const String passBaseUrl = 'https://passport.bilibili.com';
static const List validateStatusCodes = [
302,
304,
diff --git a/lib/http/html.dart b/lib/http/html.dart
index 41570d0a..52b228a5 100644
--- a/lib/http/html.dart
+++ b/lib/http/html.dart
@@ -40,9 +40,13 @@ class HtmlHttp {
//
String opusContent =
opusDetail.querySelector('.opus-module-content')!.innerHtml;
- String test = opusDetail
- .querySelector('.horizontal-scroll-album__pic__img')!
- .innerHtml;
+ String? test;
+ try {
+ test = opusDetail
+ .querySelector('.horizontal-scroll-album__pic__img')!
+ .innerHtml;
+ } catch (_) {}
+
String commentId = opusDetail
.querySelector('.bili-comment-container')!
.className
@@ -54,7 +58,7 @@ class HtmlHttp {
'avatar': avatar,
'uname': uname,
'updateTime': updateTime,
- 'content': test + opusContent,
+ 'content': (test ?? '') + opusContent,
'commentId': int.parse(commentId)
};
} catch (err) {
diff --git a/lib/http/init.dart b/lib/http/init.dart
index 1e55be38..69a1d0b3 100644
--- a/lib/http/init.dart
+++ b/lib/http/init.dart
@@ -65,7 +65,7 @@ class Request {
// 从cookie中获取 csrf token
static Future getCsrf() async {
var cookies = await cookieManager.cookieJar
- .loadForRequest(Uri.parse(HttpString.baseApiUrl));
+ .loadForRequest(Uri.parse(HttpString.apiBaseUrl));
String token = '';
if (cookies.where((e) => e.name == 'bili_jct').isNotEmpty) {
token = cookies.firstWhere((e) => e.name == 'bili_jct').value;
@@ -91,7 +91,7 @@ class Request {
//BaseOptions、Options、RequestOptions 都可以配置参数,优先级别依次递增,且可以根据优先级别覆盖参数
BaseOptions options = BaseOptions(
//请求基地址,可以包含子路径
- baseUrl: HttpString.baseApiUrl,
+ baseUrl: HttpString.apiBaseUrl,
//连接服务器超时时间,单位是毫秒.
connectTimeout: const Duration(milliseconds: 12000),
//响应流上前后两次接受到数据的间隔,单位为毫秒。
diff --git a/lib/http/video.dart b/lib/http/video.dart
index 9429a04b..f97ac277 100644
--- a/lib/http/video.dart
+++ b/lib/http/video.dart
@@ -30,7 +30,7 @@ class VideoHttp {
static Future rcmdVideoList({required int ps, required int freshIdx}) async {
try {
var res = await Request().get(
- Api.recommendList,
+ Api.recommendListWeb,
data: {
'version': 1,
'feed_version': 'V3',
@@ -122,27 +122,33 @@ class VideoHttp {
static Future videoUrl(
{int? avid, String? bvid, required int cid, int? qn}) async {
Map data = {
- // 'avid': avid,
- 'bvid': bvid,
'cid': cid,
- // 'qn': qn ?? 80,
+ 'qn': qn ?? 80,
// 获取所有格式的视频
'fnval': 4048,
- // 'fnver': '',
- 'fourk': 1,
- // 'session': '',
- // 'otype': '',
- // 'type': '',
- // 'platform': '',
- // 'high_quality': ''
};
+ if (avid != null) {
+ data['avid'] = avid;
+ }
+ if (bvid != null) {
+ data['bvid'] = bvid;
+ }
+
+ Map params = await WbiSign().makSign({
+ ...data,
+ 'fourk': 1,
+ 'voice_balance': 1,
+ 'gaia_source': 'pre-load',
+ 'web_location': 1550101,
+ });
+
// 免登录查看1080p
if (userInfoCache.get('userInfoCache') == null &&
setting.get(SettingBoxKey.p1080, defaultValue: true)) {
data['try_look'] = 1;
}
try {
- var res = await Request().get(Api.videoUrl, data: data);
+ var res = await Request().get(Api.videoUrl, data: params);
if (res.data['code'] == 0) {
return {
'status': true,
diff --git a/lib/models/common/rcmd_type.dart b/lib/models/common/rcmd_type.dart
new file mode 100644
index 00000000..dbb64b15
--- /dev/null
+++ b/lib/models/common/rcmd_type.dart
@@ -0,0 +1,7 @@
+// 首页推荐类型
+enum RcmdType { web, app }
+
+extension RcmdTypeExtension on RcmdType {
+ String get values => ['web', 'app'][index];
+ String get labels => ['web端', 'app端'][index];
+}
diff --git a/lib/models/dynamics/result.dart b/lib/models/dynamics/result.dart
index d8aff7b5..2f7c2d40 100644
--- a/lib/models/dynamics/result.dart
+++ b/lib/models/dynamics/result.dart
@@ -78,12 +78,14 @@ class ItemModulesModel {
this.moduleDynamic,
// this.moduleInter,
this.moduleStat,
+ this.moduleTag,
});
ModuleAuthorModel? moduleAuthor;
ModuleDynamicModel? moduleDynamic;
// ModuleInterModel? moduleInter;
ModuleStatModel? moduleStat;
+ Map? moduleTag;
ItemModulesModel.fromJson(Map json) {
moduleAuthor = json['module_author'] != null
@@ -96,6 +98,7 @@ class ItemModulesModel {
moduleStat = json['module_stat'] != null
? ModuleStatModel.fromJson(json['module_stat'])
: null;
+ moduleTag = json['module_tag'];
}
}
diff --git a/lib/models/model_rec_video_item.dart b/lib/models/model_rec_video_item.dart
index f8c1731b..f857c70f 100644
--- a/lib/models/model_rec_video_item.dart
+++ b/lib/models/model_rec_video_item.dart
@@ -1,3 +1,5 @@
+import 'package:pilipala/utils/utils.dart';
+
import './model_owner.dart';
import 'package:hive/hive.dart';
@@ -56,7 +58,7 @@ class RecVideoItemModel {
uri = json["uri"];
pic = json["pic"];
title = json["title"];
- duration = json["duration"].toString();
+ duration = Utils.tampToSeektime(json["duration"]);
pubdate = json["pubdate"];
owner = Owner.fromJson(json["owner"]);
stat = Stat.fromJson(json["stat"]);
diff --git a/lib/models/video/reply/content.dart b/lib/models/video/reply/content.dart
index ad1759ac..9180ec97 100644
--- a/lib/models/video/reply/content.dart
+++ b/lib/models/video/reply/content.dart
@@ -2,7 +2,7 @@ class ReplyContent {
ReplyContent({
this.message,
this.atNameToMid, // @的用户的mid null
- this.memebers, // 被@的用户List 如果有的话 []
+ this.members, // 被@的用户List 如果有的话 []
this.emote, // 表情包 如果有的话 null
this.jumpUrl, // {}
this.pictures, // {}
@@ -13,7 +13,7 @@ class ReplyContent {
String? message;
Map? atNameToMid;
- List? memebers;
+ List? members;
Map? emote;
Map? jumpUrl;
List? pictures;
@@ -27,7 +27,11 @@ class ReplyContent {
.replaceAll('"', '"')
.replaceAll(''', "'");
atNameToMid = json['at_name_to_mid'] ?? {};
- memebers = json['memebers'] ?? [];
+ members = json['members'] != null
+ ? json['members']
+ .map((e) => MemberItemModel.fromJson(e))
+ .toList()
+ : [];
emote = json['emote'] ?? {};
jumpUrl = json['jump_url'] ?? {};
pictures = json['pictures'] ?? [];
@@ -37,3 +41,18 @@ class ReplyContent {
isText = atNameToMid!.isEmpty && vote!.isEmpty && pictures!.isEmpty;
}
}
+
+class MemberItemModel {
+ MemberItemModel({
+ required this.mid,
+ required this.uname,
+ });
+
+ late String mid;
+ late String uname;
+
+ MemberItemModel.fromJson(Map json) {
+ mid = json['mid'];
+ uname = json['uname'];
+ }
+}
diff --git a/lib/pages/dynamics/deatil/controller.dart b/lib/pages/dynamics/deatil/controller.dart
index 62f0245d..1520377e 100644
--- a/lib/pages/dynamics/deatil/controller.dart
+++ b/lib/pages/dynamics/deatil/controller.dart
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'package:hive/hive.dart';
+import 'package:pilipala/http/html.dart';
import 'package:pilipala/http/reply.dart';
import 'package:pilipala/models/common/reply_sort_type.dart';
import 'package:pilipala/models/video/reply/item.dart';
@@ -103,4 +104,10 @@ class DynamicDetailController extends GetxController {
replyList.clear();
queryReplyList(reqType: 'init');
}
+
+ // 根据jumpUrl获取动态html
+ reqHtmlByOpusId(int id) async {
+ var res = await HtmlHttp.reqHtml(id, 'opus');
+ oid = res['commentId'];
+ }
}
diff --git a/lib/pages/dynamics/deatil/view.dart b/lib/pages/dynamics/deatil/view.dart
index 116e0d27..28f70bcf 100644
--- a/lib/pages/dynamics/deatil/view.dart
+++ b/lib/pages/dynamics/deatil/view.dart
@@ -7,6 +7,7 @@ import 'package:get/get.dart';
import 'package:pilipala/common/skeleton/video_reply.dart';
import 'package:pilipala/common/widgets/http_error.dart';
import 'package:pilipala/models/common/reply_type.dart';
+import 'package:pilipala/models/dynamics/result.dart';
import 'package:pilipala/pages/dynamics/deatil/index.dart';
import 'package:pilipala/pages/dynamics/widgets/author_panel.dart';
import 'package:pilipala/pages/video/detail/reply/widgets/reply_item.dart';
@@ -35,39 +36,17 @@ class _DynamicDetailPageState extends State
bool _visibleTitle = false;
String? action;
// 回复类型
- late int type;
+ late int replyType;
bool _isFabVisible = true;
+ int oid = 0;
+ int? opusId;
+ bool isOpusId = false;
@override
void initState() {
super.initState();
- int oid = 0;
// floor 1原创 2转发
- if (Get.arguments['floor'] == 1) {
- oid = int.parse(Get.arguments['item'].basic!['comment_id_str']);
- print(oid);
- } else {
- try {
- String type = Get.arguments['item'].modules.moduleDynamic.major.type;
-
- /// TODO
- if (type == 'MAJOR_TYPE_OPUS') {
- } else {
- oid = Get.arguments['item'].modules.moduleDynamic.major.draw.id;
- }
- } catch (_) {}
- }
- int commentType = 11;
- try {
- commentType = Get.arguments['item'].basic!['comment_type'];
- } catch (_) {}
- type = (commentType == 0) ? 11 : commentType;
-
- action =
- Get.arguments.containsKey('action') ? Get.arguments['action'] : null;
- _dynamicDetailController =
- Get.put(DynamicDetailController(oid, type), tag: oid.toString());
- _futureBuilderFuture = _dynamicDetailController.queryReplyList();
+ init();
titleStreamC = StreamController();
if (action == 'comment') {
_visibleTitle = true;
@@ -83,6 +62,49 @@ class _DynamicDetailPageState extends State
scrollListener();
}
+ // 页面初始化
+ void init() async {
+ Map args = Get.arguments;
+ // 楼层
+ int floor = args['floor'];
+ // 从action栏点击进入
+ action = args.containsKey('action') ? args['action'] : null;
+ // 评论类型
+ int commentType = args['item'].basic!['comment_type'] ?? 11;
+ replyType = (commentType == 0) ? 11 : commentType;
+
+ if (floor == 1) {
+ oid = int.parse(args['item'].basic!['comment_id_str']);
+ } else {
+ try {
+ ModuleDynamicModel moduleDynamic = args['item'].modules.moduleDynamic;
+ String majorType = moduleDynamic.major!.type!;
+
+ if (majorType == 'MAJOR_TYPE_OPUS') {
+ // 转发的动态
+ String jumpUrl = moduleDynamic.major!.opus!.jumpUrl!;
+ opusId = int.parse(jumpUrl.split('/').last);
+ if (opusId != null) {
+ isOpusId = true;
+ _dynamicDetailController = Get.put(
+ DynamicDetailController(oid, replyType),
+ tag: opusId.toString());
+ await _dynamicDetailController.reqHtmlByOpusId(opusId!);
+ setState(() {});
+ }
+ } else {
+ oid = moduleDynamic.major!.draw!.id!;
+ }
+ } catch (_) {}
+ }
+ if (!isOpusId) {
+ _dynamicDetailController =
+ Get.put(DynamicDetailController(oid, replyType), tag: oid.toString());
+ }
+ _futureBuilderFuture = _dynamicDetailController.queryReplyList();
+ }
+
+ // 查看二级评论
void replyReply(replyItem) {
int oid = replyItem.oid;
int rpid = replyItem.rpid!;
@@ -100,13 +122,14 @@ class _DynamicDetailPageState extends State
oid: oid,
rpid: rpid,
source: 'dynamic',
- replyType: ReplyType.values[type],
+ replyType: ReplyType.values[replyType],
firstFloor: replyItem,
),
),
);
}
+ // 滑动事件监听
void scrollListener() {
scrollController = _dynamicDetailController.scrollController;
scrollController.addListener(
@@ -307,7 +330,8 @@ class _DynamicDetailPageState extends State
replyLevel: '1',
replyReply: (replyItem) =>
replyReply(replyItem),
- replyType: ReplyType.values[type],
+ replyType:
+ ReplyType.values[replyType],
addReply: (replyItem) {
_dynamicDetailController
.replyList[index].replies!
@@ -365,7 +389,7 @@ class _DynamicDetailPageState extends State
IdUtils.bv2av(Get.parameters['bvid']!),
root: 0,
parent: 0,
- replyType: ReplyType.values[type],
+ replyType: ReplyType.values[replyType],
);
},
).then(
diff --git a/lib/pages/dynamics/widgets/author_panel.dart b/lib/pages/dynamics/widgets/author_panel.dart
index b6ea5eb9..c21516e5 100644
--- a/lib/pages/dynamics/widgets/author_panel.dart
+++ b/lib/pages/dynamics/widgets/author_panel.dart
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
+import 'package:pilipala/common/widgets/badge.dart';
import 'package:pilipala/common/widgets/network_img_layer.dart';
import 'package:pilipala/http/user.dart';
import 'package:pilipala/utils/feed_back.dart';
@@ -44,15 +45,27 @@ class AuthorPanel extends StatelessWidget {
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
- Text(
- item.modules.moduleAuthor.name,
- style: TextStyle(
- color: item.modules.moduleAuthor!.vip != null &&
- item.modules.moduleAuthor!.vip['status'] > 0
- ? const Color.fromARGB(255, 251, 100, 163)
- : Theme.of(context).colorScheme.onBackground,
- fontSize: Theme.of(context).textTheme.titleSmall!.fontSize,
- ),
+ Row(
+ children: [
+ Text(
+ item.modules.moduleAuthor.name,
+ style: TextStyle(
+ color: item.modules.moduleAuthor!.vip != null &&
+ item.modules.moduleAuthor!.vip['status'] > 0
+ ? const Color.fromARGB(255, 251, 100, 163)
+ : Theme.of(context).colorScheme.onBackground,
+ fontSize: Theme.of(context).textTheme.titleSmall!.fontSize,
+ ),
+ ),
+ if (item.modules.moduleTag != null) ...[
+ const SizedBox(width: 6),
+ PBadge(
+ bottom: 10,
+ right: 10,
+ text: item.modules.moduleTag['text'],
+ )
+ ]
+ ],
),
DefaultTextStyle.merge(
style: TextStyle(
diff --git a/lib/pages/favDetail/widget/fav_video_card.dart b/lib/pages/favDetail/widget/fav_video_card.dart
index 471f19bc..9394fbe3 100644
--- a/lib/pages/favDetail/widget/fav_video_card.dart
+++ b/lib/pages/favDetail/widget/fav_video_card.dart
@@ -142,6 +142,11 @@ class VideoContent extends StatelessWidget {
overflow: TextOverflow.ellipsis,
),
const Spacer(),
+ Text(
+ Utils.dateFormat(videoItem.ctime!),
+ style: TextStyle(
+ fontSize: 11, color: Theme.of(context).colorScheme.outline),
+ ),
Text(
videoItem.owner.name,
style: TextStyle(
diff --git a/lib/pages/follow/view.dart b/lib/pages/follow/view.dart
index a4f1011b..a9fcab4e 100644
--- a/lib/pages/follow/view.dart
+++ b/lib/pages/follow/view.dart
@@ -52,6 +52,7 @@ class _FollowPageState extends State {
TabBar(
controller: _followController.tabController,
isScrollable: true,
+ tabAlignment: TabAlignment.start,
tabs: [
for (var i in data['data']) ...[
Tab(text: i.name),
diff --git a/lib/pages/hot/view.dart b/lib/pages/hot/view.dart
index 4b098063..b15a6aed 100644
--- a/lib/pages/hot/view.dart
+++ b/lib/pages/hot/view.dart
@@ -94,6 +94,7 @@ class _HotPageState extends State with AutomaticKeepAliveClientMixin {
SliverChildBuilderDelegate((context, index) {
return VideoCardH(
videoItem: _hotController.videoList[index],
+ showPubdate: true,
longPress: () {
_hotController.popupDialog = _createPopupDialog(
_hotController.videoList[index]);
diff --git a/lib/pages/liveRoom/view.dart b/lib/pages/liveRoom/view.dart
index 125460b9..5ac382e6 100644
--- a/lib/pages/liveRoom/view.dart
+++ b/lib/pages/liveRoom/view.dart
@@ -54,62 +54,83 @@ class _LiveRoomPageState extends State {
Widget build(BuildContext context) {
Widget childWhenDisabled = Scaffold(
primary: true,
- appBar: AppBar(
- centerTitle: false,
- titleSpacing: 0,
- title: _liveRoomController.liveItem != null
- ? Row(
- children: [
- NetworkImgLayer(
- width: 34,
- height: 34,
- type: 'avatar',
- src: _liveRoomController.liveItem.face,
- ),
- const SizedBox(width: 10),
- Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- Text(
- _liveRoomController.liveItem.uname,
- style: const TextStyle(fontSize: 14),
- ),
- const SizedBox(height: 1),
- if (_liveRoomController.liveItem.watchedShow != null)
+ appBar: PreferredSize(
+ preferredSize: Size.fromHeight(
+ MediaQuery.of(context).orientation == Orientation.portrait ? 56 : 0,
+ ),
+ child: AppBar(
+ centerTitle: false,
+ titleSpacing: 0,
+ title: _liveRoomController.liveItem != null
+ ? Row(
+ children: [
+ NetworkImgLayer(
+ width: 34,
+ height: 34,
+ type: 'avatar',
+ src: _liveRoomController.liveItem.face,
+ ),
+ const SizedBox(width: 10),
+ Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
Text(
- _liveRoomController
- .liveItem.watchedShow['text_large'] ??
- '',
- style: const TextStyle(fontSize: 12)),
- ],
- ),
- ],
- )
- : const SizedBox(),
- // actions: [
- // SizedBox(
- // height: 34,
- // child: ElevatedButton(onPressed: () {}, child: const Text('关注')),
- // ),
- // const SizedBox(width: 12),
- // ],
+ _liveRoomController.liveItem.uname,
+ style: const TextStyle(fontSize: 14),
+ ),
+ const SizedBox(height: 1),
+ if (_liveRoomController.liveItem.watchedShow != null)
+ Text(
+ _liveRoomController
+ .liveItem.watchedShow['text_large'] ??
+ '',
+ style: const TextStyle(fontSize: 12)),
+ ],
+ ),
+ ],
+ )
+ : const SizedBox(),
+ // actions: [
+ // SizedBox(
+ // height: 34,
+ // child: ElevatedButton(onPressed: () {}, child: const Text('关注')),
+ // ),
+ // const SizedBox(width: 12),
+ // ],
+ ),
),
body: Column(
children: [
Stack(
children: [
- AspectRatio(
- aspectRatio: 16 / 9,
- child: plPlayerController!.videoPlayerController != null
- ? PLVideoPlayer(
- controller: plPlayerController!,
- bottomControl: BottomControl(
- controller: plPlayerController,
- liveRoomCtr: _liveRoomController,
- floating: floating,
- ),
- )
- : const SizedBox(),
+ PopScope(
+ canPop: plPlayerController?.isFullScreen.value != true,
+ onPopInvoked: (bool didPop) {
+ if (plPlayerController?.isFullScreen.value == true) {
+ plPlayerController!.triggerFullScreen(status: false);
+ }
+ if (MediaQuery.of(context).orientation ==
+ Orientation.landscape) {
+ verticalScreen();
+ }
+ },
+ child: SizedBox(
+ width: Get.size.width,
+ height: MediaQuery.of(context).orientation ==
+ Orientation.landscape
+ ? Get.size.height
+ : Get.size.width * 9 / 16,
+ child: plPlayerController!.videoPlayerController != null
+ ? PLVideoPlayer(
+ controller: plPlayerController!,
+ bottomControl: BottomControl(
+ controller: plPlayerController,
+ liveRoomCtr: _liveRoomController,
+ floating: floating,
+ ),
+ )
+ : const SizedBox(),
+ ),
),
// if (_liveRoomController.liveItem != null &&
// _liveRoomController.liveItem.cover != null)
diff --git a/lib/pages/main/view.dart b/lib/pages/main/view.dart
index fef5620d..6e93bcbc 100644
--- a/lib/pages/main/view.dart
+++ b/lib/pages/main/view.dart
@@ -25,10 +25,6 @@ class _MainAppState extends State with SingleTickerProviderStateMixin {
final MediaController _mediaController = Get.put(MediaController());
PageController? _pageController;
-
- late AnimationController? _animationController;
- late Animation? _fadeAnimation;
- late Animation? _slideAnimation;
int selectedIndex = 0;
int? _lastSelectTime; //上次点击时间
Box setting = GStrorage.setting;
@@ -37,16 +33,6 @@ class _MainAppState extends State with SingleTickerProviderStateMixin {
@override
void initState() {
super.initState();
- _animationController = AnimationController(
- duration: const Duration(milliseconds: 800),
- reverseDuration: const Duration(milliseconds: 0),
- value: 1,
- vsync: this,
- );
- _fadeAnimation =
- Tween(begin: 0.8, end: 1.0).animate(_animationController!);
- _slideAnimation =
- Tween(begin: 0.8, end: 1.0).animate(_animationController!);
_lastSelectTime = DateTime.now().millisecondsSinceEpoch;
_pageController = PageController(initialPage: selectedIndex);
enableMYBar = setting.get(SettingBoxKey.enableMYBar, defaultValue: true);
@@ -54,14 +40,6 @@ class _MainAppState extends State with SingleTickerProviderStateMixin {
void setIndex(int value) async {
feedBack();
- if (selectedIndex != value) {
- selectedIndex = value;
- _animationController!.reverse().then((_) {
- selectedIndex = value;
- _animationController!.forward();
- });
- setState(() {});
- }
_pageController!.jumpToPage(value);
var currentPage = _mainController.pages[value];
if (currentPage is HomePage) {
@@ -119,29 +97,14 @@ class _MainAppState extends State with SingleTickerProviderStateMixin {
onPopInvoked: (bool status) => _mainController.onBackPressed(context),
child: Scaffold(
extendBody: true,
- body: FadeTransition(
- opacity: _fadeAnimation!,
- child: SlideTransition(
- position: Tween(
- begin: const Offset(0, 0.5),
- end: Offset.zero,
- ).animate(
- CurvedAnimation(
- parent: _slideAnimation!,
- curve: Curves.fastOutSlowIn,
- reverseCurve: Curves.linear,
- ),
- ),
- child: PageView(
- physics: const NeverScrollableScrollPhysics(),
- controller: _pageController,
- onPageChanged: (index) {
- selectedIndex = index;
- setState(() {});
- },
- children: _mainController.pages,
- ),
- ),
+ body: PageView(
+ physics: const NeverScrollableScrollPhysics(),
+ controller: _pageController,
+ onPageChanged: (index) {
+ selectedIndex = index;
+ setState(() {});
+ },
+ children: _mainController.pages,
),
bottomNavigationBar: StreamBuilder(
stream: _mainController.hideTabBar
diff --git a/lib/pages/member_archive/view.dart b/lib/pages/member_archive/view.dart
index dd4c5cba..a3dd4c66 100644
--- a/lib/pages/member_archive/view.dart
+++ b/lib/pages/member_archive/view.dart
@@ -45,7 +45,9 @@ class _MemberArchivePageState extends State {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
- title: const Text('他的投稿'),
+ titleSpacing: 0,
+ centerTitle: false,
+ title: Text('他的投稿', style: Theme.of(context).textTheme.titleMedium),
// actions: [
// Obx(
// () => PopupMenuButton(
diff --git a/lib/pages/member_dynamics/view.dart b/lib/pages/member_dynamics/view.dart
index a22c94e1..fe7573fc 100644
--- a/lib/pages/member_dynamics/view.dart
+++ b/lib/pages/member_dynamics/view.dart
@@ -52,7 +52,9 @@ class _MemberDynamicsPageState extends State {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
- title: const Text('他的动态'),
+ titleSpacing: 0,
+ centerTitle: false,
+ title: Text('他的动态', style: Theme.of(context).textTheme.titleMedium),
),
body: CustomScrollView(
controller: _memberDynamicController.scrollController,
diff --git a/lib/pages/member_seasons/view.dart b/lib/pages/member_seasons/view.dart
index 97a43358..06944f10 100644
--- a/lib/pages/member_seasons/view.dart
+++ b/lib/pages/member_seasons/view.dart
@@ -41,7 +41,9 @@ class _MemberSeasonsPageState extends State {
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
- title: const Text('他的专栏'),
+ titleSpacing: 0,
+ centerTitle: false,
+ title: Text('他的专栏', style: Theme.of(context).textTheme.titleMedium),
),
body: Padding(
padding: const EdgeInsets.only(
diff --git a/lib/pages/rcmd/controller.dart b/lib/pages/rcmd/controller.dart
index ef5da13b..4ed1ade1 100644
--- a/lib/pages/rcmd/controller.dart
+++ b/lib/pages/rcmd/controller.dart
@@ -3,20 +3,21 @@ import 'package:get/get.dart';
import 'package:hive/hive.dart';
import 'package:pilipala/http/video.dart';
import 'package:pilipala/models/home/rcmd/result.dart';
-// import 'package:pilipala/models/model_rec_video_item.dart';
+import 'package:pilipala/models/model_rec_video_item.dart';
import 'package:pilipala/utils/storage.dart';
class RcmdController extends GetxController {
final ScrollController scrollController = ScrollController();
int _currentPage = 0;
- RxList videoList = [].obs;
- // RxList videoList = [].obs;
+ RxList appVideoList = [].obs;
+ RxList webVideoList = [].obs;
bool isLoadingMore = true;
OverlayEntry? popupDialog;
Box recVideo = GStrorage.recVideo;
Box setting = GStrorage.setting;
RxInt crossAxisCount = 2.obs;
late bool enableSaveLastData;
+ late String defaultRcmdType = 'web';
@override
void onInit() {
@@ -24,21 +25,29 @@ class RcmdController extends GetxController {
crossAxisCount.value =
setting.get(SettingBoxKey.customRows, defaultValue: 2);
// 读取app端缓存内容
- if (recVideo.get('cacheList') != null &&
- recVideo.get('cacheList').isNotEmpty) {
- List list = [];
- for (var i in recVideo.get('cacheList')) {
- list.add(i);
- }
- videoList.value = list;
- }
+ // if (recVideo.get('cacheList') != null &&
+ // recVideo.get('cacheList').isNotEmpty) {
+ // List list = [];
+ // for (var i in recVideo.get('cacheList')) {
+ // list.add(i);
+ // }
+ // videoList.value = list;
+ // }
enableSaveLastData =
setting.get(SettingBoxKey.enableSaveLastData, defaultValue: false);
+ defaultRcmdType =
+ setting.get(SettingBoxKey.defaultRcmdType, defaultValue: 'web');
}
// 获取推荐
Future queryRcmdFeed(type) async {
- return await queryRcmdFeedApp(type);
+ print(defaultRcmdType);
+ if (defaultRcmdType == 'app') {
+ return await queryRcmdFeedApp(type);
+ }
+ if (defaultRcmdType == 'web') {
+ return await queryRcmdFeedWeb(type);
+ }
}
// 获取app端推荐
@@ -54,19 +63,19 @@ class RcmdController extends GetxController {
);
if (res['status']) {
if (type == 'init') {
- if (videoList.isNotEmpty) {
- videoList.addAll(res['data']);
+ if (appVideoList.isNotEmpty) {
+ appVideoList.addAll(res['data']);
} else {
- videoList.value = res['data'];
+ appVideoList.value = res['data'];
}
} else if (type == 'onRefresh') {
if (enableSaveLastData) {
- videoList.insertAll(0, res['data']);
+ appVideoList.insertAll(0, res['data']);
} else {
- videoList.value = res['data'];
+ appVideoList.value = res['data'];
}
} else if (type == 'onLoad') {
- videoList.addAll(res['data']);
+ appVideoList.addAll(res['data']);
}
recVideo.put('cacheList', res['data']);
_currentPage += 1;
@@ -89,19 +98,19 @@ class RcmdController extends GetxController {
);
if (res['status']) {
if (type == 'init') {
- if (videoList.isNotEmpty) {
- videoList.addAll(res['data']);
+ if (webVideoList.isNotEmpty) {
+ webVideoList.addAll(res['data']);
} else {
- videoList.value = res['data'];
+ webVideoList.value = res['data'];
}
} else if (type == 'onRefresh') {
if (enableSaveLastData) {
- videoList.insertAll(0, res['data']);
+ webVideoList.insertAll(0, res['data']);
} else {
- videoList.value = res['data'];
+ webVideoList.value = res['data'];
}
} else if (type == 'onLoad') {
- videoList.addAll(res['data']);
+ webVideoList.addAll(res['data']);
}
_currentPage += 1;
}
diff --git a/lib/pages/rcmd/view.dart b/lib/pages/rcmd/view.dart
index 717ea9f7..bc3c4a00 100644
--- a/lib/pages/rcmd/view.dart
+++ b/lib/pages/rcmd/view.dart
@@ -98,12 +98,22 @@ class _RcmdPageState extends State
Map data = snapshot.data as Map;
if (data['status']) {
return Platform.isAndroid || Platform.isIOS
- ? Obx(() => contentGrid(
- _rcmdController, _rcmdController.videoList))
+ ? Obx(
+ () => contentGrid(
+ _rcmdController,
+ _rcmdController.defaultRcmdType == 'web'
+ ? _rcmdController.webVideoList
+ : _rcmdController.appVideoList),
+ )
: SliverLayoutBuilder(
builder: (context, boxConstraints) {
- return Obx(() => contentGrid(
- _rcmdController, _rcmdController.videoList));
+ return Obx(
+ () => contentGrid(
+ _rcmdController,
+ _rcmdController.defaultRcmdType == 'web'
+ ? _rcmdController.webVideoList
+ : _rcmdController.appVideoList),
+ );
});
} else {
return HttpError(
@@ -118,14 +128,14 @@ class _RcmdPageState extends State
}
} else {
// 缓存数据
- if (_rcmdController.videoList.isNotEmpty) {
- return contentGrid(
- _rcmdController, _rcmdController.videoList);
- }
- // 骨架屏
- else {
- return contentGrid(_rcmdController, []);
- }
+ // if (_rcmdController.videoList.isNotEmpty) {
+ // return contentGrid(
+ // _rcmdController, _rcmdController.videoList);
+ // }
+ // // 骨架屏
+ // else {
+ return contentGrid(_rcmdController, []);
+ // }
}
},
),
diff --git a/lib/pages/setting/extra_setting.dart b/lib/pages/setting/extra_setting.dart
index 57c33ff4..b4275815 100644
--- a/lib/pages/setting/extra_setting.dart
+++ b/lib/pages/setting/extra_setting.dart
@@ -1,7 +1,9 @@
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:hive/hive.dart';
+import 'package:pilipala/http/member.dart';
import 'package:pilipala/models/common/dynamics_type.dart';
+import 'package:pilipala/models/common/rcmd_type.dart';
import 'package:pilipala/models/common/reply_sort_type.dart';
import 'package:pilipala/pages/setting/widgets/select_dialog.dart';
import 'package:pilipala/utils/storage.dart';
@@ -18,15 +20,23 @@ class ExtraSetting extends StatefulWidget {
class _ExtraSettingState extends State {
Box setting = GStrorage.setting;
static Box localCache = GStrorage.localCache;
+ late dynamic defaultRcmdType;
late dynamic defaultReplySort;
late dynamic defaultDynamicType;
late dynamic enableSystemProxy;
late String defaultSystemProxyHost;
late String defaultSystemProxyPort;
+ Box userInfoCache = GStrorage.userInfo;
+ var userInfo;
+ bool userLogin = false;
+ var accessKeyInfo;
@override
void initState() {
super.initState();
+ // 首页默认推荐类型
+ defaultRcmdType =
+ setting.get(SettingBoxKey.defaultRcmdType, defaultValue: 'web');
// 默认优先显示最新评论
defaultReplySort =
setting.get(SettingBoxKey.replySortType, defaultValue: 0);
@@ -39,6 +49,9 @@ class _ExtraSettingState extends State {
localCache.get(LocalCacheKey.systemProxyHost, defaultValue: '');
defaultSystemProxyPort =
localCache.get(LocalCacheKey.systemProxyPort, defaultValue: '');
+ userInfo = userInfoCache.get('userInfoCache');
+ userLogin = userInfo != null;
+ accessKeyInfo = localCache.get(LocalCacheKey.accessKey, defaultValue: null);
}
// 设置代理
@@ -170,6 +183,44 @@ class _ExtraSettingState extends State {
setKey: SettingBoxKey.enableSaveLastData,
defaultVal: false,
),
+ ListTile(
+ dense: false,
+ title: Text('首页推荐类型', style: titleStyle),
+ subtitle: Text(
+ '当前使用「$defaultRcmdType端」推荐',
+ style: subTitleStyle,
+ ),
+ onTap: () async {
+ String? result = await showDialog(
+ context: context,
+ builder: (context) {
+ return SelectDialog(
+ title: '推荐类型',
+ value: defaultRcmdType,
+ values: RcmdType.values.map((e) {
+ return {'title': e.labels, 'value': e.values};
+ }).toList(),
+ );
+ },
+ );
+ if (result != null) {
+ if (result == 'app') {
+ // app端推荐需要access_key
+ if (accessKeyInfo == null) {
+ if (!userLogin) {
+ SmartDialog.showToast('请先登录');
+ return;
+ }
+ await MemberHttp.cookieToKey();
+ }
+ }
+ defaultRcmdType = result;
+ setting.put(SettingBoxKey.defaultRcmdType, result);
+ SmartDialog.showToast('下次启动时生效');
+ setState(() {});
+ }
+ },
+ ),
const SetSwitchItem(
title: '启用ai总结',
subTitle: '视频详情页开启ai总结',
@@ -187,9 +238,12 @@ class _ExtraSettingState extends State {
int? result = await showDialog(
context: context,
builder: (context) {
- return SelectDialog(title: '评论展示', value: defaultReplySort, values: ReplySortType.values.map((e) {
- return {'title': e.titles, 'value': e.index};
- }).toList());
+ return SelectDialog(
+ title: '评论展示',
+ value: defaultReplySort,
+ values: ReplySortType.values.map((e) {
+ return {'title': e.titles, 'value': e.index};
+ }).toList());
},
);
if (result != null) {
@@ -210,9 +264,12 @@ class _ExtraSettingState extends State {
int? result = await showDialog(
context: context,
builder: (context) {
- return SelectDialog(title: '动态展示', value: defaultDynamicType, values: DynamicsType.values.map((e) {
- return {'title': e.labels, 'value': e.index};
- }).toList());
+ return SelectDialog(
+ title: '动态展示',
+ value: defaultDynamicType,
+ values: DynamicsType.values.map((e) {
+ return {'title': e.labels, 'value': e.index};
+ }).toList());
},
);
if (result != null) {
diff --git a/lib/pages/setting/style_setting.dart b/lib/pages/setting/style_setting.dart
index 586142db..a4e39aa0 100644
--- a/lib/pages/setting/style_setting.dart
+++ b/lib/pages/setting/style_setting.dart
@@ -81,12 +81,6 @@ class _StyleSettingState extends State {
),
),
),
- const SetSwitchItem(
- title: 'iOS路由切换',
- subTitle: 'iOS路由切换样式,需重启',
- setKey: SettingBoxKey.iosTransition,
- defaultVal: false,
- ),
const SetSwitchItem(
title: 'MD3样式底栏',
subTitle: '符合Material You设计规范的底栏',
diff --git a/lib/pages/setting/widgets/select_dialog.dart b/lib/pages/setting/widgets/select_dialog.dart
index dffa4571..72119755 100644
--- a/lib/pages/setting/widgets/select_dialog.dart
+++ b/lib/pages/setting/widgets/select_dialog.dart
@@ -1,18 +1,20 @@
import 'package:flutter/material.dart';
-import 'package:pilipala/models/common/theme_type.dart';
class SelectDialog extends StatefulWidget {
final T value;
final String title;
final List values;
- const SelectDialog({super.key, required this.value, required this.values, required this.title});
+ const SelectDialog(
+ {super.key,
+ required this.value,
+ required this.values,
+ required this.title});
@override
_SelectDialogState createState() => _SelectDialogState();
}
class _SelectDialogState extends State> {
-
late T _tempValue;
@override
@@ -28,40 +30,39 @@ class _SelectDialogState extends State> {
return AlertDialog(
title: Text(widget.title),
contentPadding: const EdgeInsets.fromLTRB(0, 12, 0, 12),
- content: StatefulBuilder(
- builder: (context, StateSetter setState) {
- return SingleChildScrollView(
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- for (var i in widget.values) ...[
- RadioListTile(
- value: i['value'],
- title: Text(i['title'], style: titleStyle),
- groupValue: _tempValue,
- onChanged: (value) {
- print(value);
- setState(() {
- _tempValue = value as T;
- });
- },
- ),
- ]
- ],
- ),
- );
- }),
+ content: StatefulBuilder(builder: (context, StateSetter setState) {
+ return SingleChildScrollView(
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ for (var i in widget.values) ...[
+ RadioListTile(
+ value: i['value'],
+ title: Text(i['title'], style: titleStyle),
+ groupValue: _tempValue,
+ onChanged: (value) {
+ setState(() {
+ _tempValue = value as T;
+ });
+ },
+ ),
+ ]
+ ],
+ ),
+ );
+ }),
actions: [
TextButton(
- onPressed: () => Navigator.pop(context),
- child: Text(
- '取消',
- style: TextStyle(
- color: Theme.of(context).colorScheme.outline),
- )),
+ onPressed: () => Navigator.pop(context),
+ child: Text(
+ '取消',
+ style: TextStyle(color: Theme.of(context).colorScheme.outline),
+ ),
+ ),
TextButton(
- onPressed: () => Navigator.pop(context, _tempValue),
- child: const Text('确定'))
+ onPressed: () => Navigator.pop(context, _tempValue),
+ child: const Text('确定'),
+ )
],
);
}
diff --git a/lib/pages/video/detail/related/view.dart b/lib/pages/video/detail/related/view.dart
index e26df4d9..aea1abdc 100644
--- a/lib/pages/video/detail/related/view.dart
+++ b/lib/pages/video/detail/related/view.dart
@@ -36,6 +36,7 @@ class _RelatedVideoPanelState extends State {
return Material(
child: VideoCardH(
videoItem: snapshot.data['data'][index],
+ showPubdate: true,
longPress: () {
try {
_releatedController.popupDialog =
diff --git a/lib/pages/video/detail/reply/widgets/reply_item.dart b/lib/pages/video/detail/reply/widgets/reply_item.dart
index 58acd8ab..73784a61 100644
--- a/lib/pages/video/detail/reply/widgets/reply_item.dart
+++ b/lib/pages/video/detail/reply/widgets/reply_item.dart
@@ -628,8 +628,13 @@ InlineSpan buildContent(
// 匹配@用户
String matchMember = str;
if (content.atNameToMid.isNotEmpty) {
+ RegExp reg = RegExp(r"@.*( |:)");
+ if (content.atNameToMid.length == 1 &&
+ content.message == '@${content.members.first.uname}') {
+ reg = RegExp(r"@.*( |:|$)");
+ }
matchMember = str.splitMapJoin(
- RegExp(r"@.*( |:)"),
+ reg,
onMatch: (Match match) {
if (match[0] != null) {
hasMatchMember = false;
@@ -657,7 +662,9 @@ InlineSpan buildContent(
return '';
},
onNonMatch: (String str) {
- spanChilds.add(TextSpan(text: str));
+ if (!str.contains('@')) {
+ spanChilds.add(TextSpan(text: str));
+ }
return str;
},
);
diff --git a/lib/pages/video/detail/view.dart b/lib/pages/video/detail/view.dart
index de35ddaf..29566e7b 100644
--- a/lib/pages/video/detail/view.dart
+++ b/lib/pages/video/detail/view.dart
@@ -1,5 +1,6 @@
import 'dart:async';
import 'dart:io';
+import 'dart:ui';
import 'package:extended_nested_scroll_view/extended_nested_scroll_view.dart';
import 'package:floating/floating.dart';
@@ -34,7 +35,7 @@ class VideoDetailPage extends StatefulWidget {
}
class _VideoDetailPageState extends State
- with TickerProviderStateMixin, RouteAware, WidgetsBindingObserver {
+ with TickerProviderStateMixin, RouteAware {
late VideoDetailController videoDetailController;
PlPlayerController? plPlayerController;
final ScrollController _extendNestCtr = ScrollController();
@@ -56,6 +57,8 @@ class _VideoDetailPageState extends State
late bool autoPlayEnable;
late bool autoPiP;
final floating = Floating();
+ // 生命周期监听
+ late final AppLifecycleListener _lifecycleListener;
@override
void initState() {
@@ -85,7 +88,7 @@ class _VideoDetailPageState extends State
videoSourceInit();
appbarStreamListen();
- WidgetsBinding.instance.addObserver(this);
+ lifecycleListener();
}
// 获取视频资源,初始化播放器
@@ -159,6 +162,27 @@ class _VideoDetailPageState extends State
videoDetailController.isShowCover.value = false;
}
+ // 生命周期监听
+ void lifecycleListener() {
+ _lifecycleListener = AppLifecycleListener(
+ onResume: () => _handleTransition('resume'),
+ // 后台
+ onInactive: () => _handleTransition('inactive'),
+ // 在Android和iOS端不生效
+ onHide: () => _handleTransition('hide'),
+ onShow: () => _handleTransition('show'),
+ onPause: () => _handleTransition('pause'),
+ onRestart: () => _handleTransition('restart'),
+ onDetach: () => _handleTransition('detach'),
+ // 只作用于桌面端
+ onExitRequested: () {
+ ScaffoldMessenger.maybeOf(context)
+ ?.showSnackBar(const SnackBar(content: Text("拦截应用退出")));
+ return Future.value(AppExitResponse.cancel);
+ },
+ );
+ }
+
@override
void dispose() {
if (plPlayerController != null) {
@@ -169,8 +193,8 @@ class _VideoDetailPageState extends State
videoDetailController.floating!.dispose();
}
videoPlayerServiceHandler.onVideoDetailDispose();
- WidgetsBinding.instance.removeObserver(this);
floating.dispose();
+ _lifecycleListener.dispose();
super.dispose();
}
@@ -217,12 +241,21 @@ class _VideoDetailPageState extends State
.subscribe(this, ModalRoute.of(context) as PageRoute);
}
- @override
- void didChangeAppLifecycleState(AppLifecycleState lifecycleState) {
+ void _handleTransition(String name) {
+ switch (name) {
+ case 'inactive':
+ autoEnterPip();
+ break;
+ }
+ }
+
+ void autoEnterPip() {
var routePath = Get.currentRoute;
- if (lifecycleState == AppLifecycleState.inactive &&
- autoPiP &&
- routePath.startsWith('/video')) {
+ bool isPortrait =
+ MediaQuery.of(context).orientation == Orientation.portrait;
+
+ /// TODO 横屏全屏状态下误触pip
+ if (autoPiP && routePath.startsWith('/video') && isPortrait) {
floating.enable(
aspectRatio: Rational(
videoDetailController.data.dash!.video!.first.width!,
@@ -243,7 +276,8 @@ class _VideoDetailPageState extends State
exitFullScreen();
}
Widget childWhenDisabled = SafeArea(
- top: MediaQuery.of(context).orientation == Orientation.portrait,
+ top: MediaQuery.of(context).orientation == Orientation.portrait &&
+ plPlayerController?.isFullScreen.value == true,
bottom: MediaQuery.of(context).orientation == Orientation.portrait &&
plPlayerController?.isFullScreen.value == true,
left: plPlayerController?.isFullScreen.value != true,
@@ -254,10 +288,17 @@ class _VideoDetailPageState extends State
resizeToAvoidBottomInset: false,
key: videoDetailController.scaffoldKey,
backgroundColor: Colors.black,
+ appBar: PreferredSize(
+ preferredSize: const Size.fromHeight(0),
+ child: AppBar(
+ backgroundColor: Theme.of(context).colorScheme.background,
+ elevation: 0,
+ ),
+ ),
body: ExtendedNestedScrollView(
controller: _extendNestCtr,
headerSliverBuilder:
- (BuildContext context, bool innerBoxIsScrolled) {
+ (BuildContext _context, bool innerBoxIsScrolled) {
return [
Obx(() => SliverAppBar(
automaticallyImplyLeading: false,
@@ -272,7 +313,7 @@ class _VideoDetailPageState extends State
(MediaQuery.of(context).orientation ==
Orientation.landscape
? 0
- : statusBarHeight)
+ : MediaQuery.of(context).padding.top)
: videoHeight,
backgroundColor: Colors.black,
flexibleSpace: FlexibleSpaceBar(
diff --git a/lib/pages/webview/controller.dart b/lib/pages/webview/controller.dart
index 2dfa9582..447693e2 100644
--- a/lib/pages/webview/controller.dart
+++ b/lib/pages/webview/controller.dart
@@ -115,7 +115,6 @@ class WebviewController extends GetxController {
MediaController mediaCtr = Get.find();
mediaCtr.mid = result['data'].mid;
await LoginUtils.refreshLoginStatus(true);
- MemberHttp.cookieToKey();
} catch (err) {
SmartDialog.show(builder: (context) {
return AlertDialog(
diff --git a/lib/router/app_pages.dart b/lib/router/app_pages.dart
index 9fa926ee..50f6a262 100644
--- a/lib/router/app_pages.dart
+++ b/lib/router/app_pages.dart
@@ -47,8 +47,6 @@ import 'package:pilipala/pages/whisperDetail/index.dart';
import 'package:pilipala/utils/storage.dart';
Box setting = GStrorage.setting;
-bool iosTransition =
- setting.get(SettingBoxKey.iosTransition, defaultValue: false);
class Routes {
static final List getPages = [
@@ -164,7 +162,7 @@ class CustomGetPage extends GetPage {
name: name,
page: page,
curve: Curves.linear,
- transition: iosTransition ? Transition.cupertino : Transition.native,
+ transition: Transition.native,
showCupertinoParallax: false,
popGesture: false,
transitionDuration: transitionDuration,
diff --git a/lib/utils/cookie.dart b/lib/utils/cookie.dart
index 5d4d9cbd..31284c03 100644
--- a/lib/utils/cookie.dart
+++ b/lib/utils/cookie.dart
@@ -11,9 +11,9 @@ class SetCookie {
cookies.map((cookie) => '${cookie.name}=${cookie.value}').join('; ');
Request.dio.options.headers['cookie'] = cookieString;
- cookies = await WebviewCookieManager().getCookies(HttpString.baseApiUrl);
+ cookies = await WebviewCookieManager().getCookies(HttpString.apiBaseUrl);
await Request.cookieManager.cookieJar
- .saveFromResponse(Uri.parse(HttpString.baseApiUrl), cookies);
+ .saveFromResponse(Uri.parse(HttpString.apiBaseUrl), cookies);
cookies = await WebviewCookieManager().getCookies(HttpString.tUrl);
await Request.cookieManager.cookieJar
diff --git a/lib/utils/storage.dart b/lib/utils/storage.dart
index e4210636..e3a50881 100644
--- a/lib/utils/storage.dart
+++ b/lib/utils/storage.dart
@@ -88,100 +88,100 @@ class GStrorage {
class SettingBoxKey {
/// 播放器
- static const String btmProgressBehavior = 'btmProgressBehavior';
- static const String defaultVideoSpeed = 'defaultVideoSpeed';
- static const String autoUpgradeEnable = 'autoUpgradeEnable';
- static const String feedBackEnable = 'feedBackEnable';
- static const String defaultVideoQa = 'defaultVideoQa';
- static const String defaultAudioQa = 'defaultAudioQa';
- static const String autoPlayEnable = 'autoPlayEnable';
- static const String fullScreenMode = 'fullScreenMode';
- static const String defaultDecode = 'defaultDecode';
- static const String danmakuEnable = 'danmakuEnable';
- static const String defaultToastOp = 'defaultToastOp';
- static const String defaultPicQa = 'defaultPicQa';
- static const String enableHA = 'enableHA';
- static const String enableOnlineTotal = 'enableOnlineTotal';
- static const String enableAutoBrightness = 'enableAutoBrightness';
- static const String enableAutoEnter = 'enableAutoEnter';
- static const String enableAutoExit = 'enableAutoExit';
- static const String p1080 = 'p1080';
- static const String enableCDN = 'enableCDN';
- static const String autoPiP = 'autoPiP';
- static const String enableAutoLongPressSpeed = 'enableAutoLongPressSpeed';
+ static const btmProgressBehavior = 'btmProgressBehavior',
+ defaultVideoSpeed = 'defaultVideoSpeed',
+ autoUpgradeEnable = 'autoUpgradeEnable',
+ feedBackEnable = 'feedBackEnable',
+ defaultVideoQa = 'defaultVideoQa',
+ defaultAudioQa = 'defaultAudioQa',
+ autoPlayEnable = 'autoPlayEnable',
+ fullScreenMode = 'fullScreenMode',
+ defaultDecode = 'defaultDecode',
+ danmakuEnable = 'danmakuEnable',
+ defaultToastOp = 'defaultToastOp',
+ defaultPicQa = 'defaultPicQa',
+ enableHA = 'enableHA',
+ enableOnlineTotal = 'enableOnlineTotal',
+ enableAutoBrightness = 'enableAutoBrightness',
+ enableAutoEnter = 'enableAutoEnter',
+ enableAutoExit = 'enableAutoExit',
+ p1080 = 'p1080',
+ enableCDN = 'enableCDN',
+ autoPiP = 'autoPiP',
+ enableAutoLongPressSpeed = 'enableAutoLongPressSpeed',
- // youtube 双击快进快退
- static const String enableQuickDouble = 'enableQuickDouble';
- static const String enableShowDanmaku = 'enableShowDanmaku';
- static const String enableBackgroundPlay = 'enableBackgroundPlay';
+ // youtube 双击快进快退
+ enableQuickDouble = 'enableQuickDouble',
+ enableShowDanmaku = 'enableShowDanmaku',
+ enableBackgroundPlay = 'enableBackgroundPlay',
- /// 隐私
- static const String blackMidsList = 'blackMidsList';
+ /// 隐私
+ blackMidsList = 'blackMidsList',
- /// 其他
- static const String autoUpdate = 'autoUpdate';
- static const String replySortType = 'replySortType';
- static const String defaultDynamicType = 'defaultDynamicType';
- static const String enableHotKey = 'enableHotKey';
- static const String enableQuickFav = 'enableQuickFav';
- static const String enableWordRe = 'enableWordRe';
- static const String enableSearchWord = 'enableSearchWord';
- static const String enableRcmdDynamic = 'enableRcmdDynamic';
- static const String enableSaveLastData = 'enableSaveLastData';
- static const String enableSystemProxy = 'enableSystemProxy';
- static const String enableAi = 'enableAi';
+ /// 其他
+ autoUpdate = 'autoUpdate',
+ defaultRcmdType = 'defaultRcmdType',
+ replySortType = 'replySortType',
+ defaultDynamicType = 'defaultDynamicType',
+ enableHotKey = 'enableHotKey',
+ enableQuickFav = 'enableQuickFav',
+ enableWordRe = 'enableWordRe',
+ enableSearchWord = 'enableSearchWord',
+ enableRcmdDynamic = 'enableRcmdDynamic',
+ enableSaveLastData = 'enableSaveLastData',
+ enableSystemProxy = 'enableSystemProxy',
+ enableAi = 'enableAi';
/// 外观
- static const String themeMode = 'themeMode';
- static const String defaultTextScale = 'textScale';
- static const String dynamicColor = 'dynamicColor'; // bool
- static const String customColor = 'customColor'; // 自定义主题色
- static const String iosTransition = 'iosTransition'; // ios路由
- static const String enableSingleRow = 'enableSingleRow'; // 首页单列
- static const String displayMode = 'displayMode';
- static const String customRows = 'customRows'; // 自定义列
- static const String enableMYBar = 'enableMYBar';
- static const String hideSearchBar = 'hideSearchBar'; // 收起顶栏
- static const String hideTabBar = 'hideTabBar'; // 收起底栏
+ static const String themeMode = 'themeMode',
+ defaultTextScale = 'textScale',
+ dynamicColor = 'dynamicColor', // bool
+ customColor = 'customColor', // 自定义主题色
+ enableSingleRow = 'enableSingleRow', // 首页单列
+ displayMode = 'displayMode',
+ customRows = 'customRows', // 自定义列
+ enableMYBar = 'enableMYBar',
+ hideSearchBar = 'hideSearchBar', // 收起顶栏
+ hideTabBar = 'hideTabBar'; // 收起底栏
}
class LocalCacheKey {
// 历史记录暂停状态 默认false 记录
- static const String historyPause = 'historyPause';
- // access_key
- static const String accessKey = 'accessKey';
+ static const String historyPause = 'historyPause',
+ // access_key
+ accessKey = 'accessKey',
- //
- static const String wbiKeys = 'wbiKeys';
- static const String timeStamp = 'timeStamp';
+ //
+ wbiKeys = 'wbiKeys',
+ timeStamp = 'timeStamp',
- // 弹幕相关设置 屏蔽类型 显示区域 透明度 字体大小 弹幕时间
- static const String danmakuBlockType = 'danmakuBlockType';
- static const String danmakuShowArea = 'danmakuShowArea';
- static const String danmakuOpacity = 'danmakuOpacity';
- static const String danmakuFontScale = 'danmakuFontScale';
- static const String danmakuDuration = 'danmakuDuration';
+ // 弹幕相关设置 屏蔽类型 显示区域 透明度 字体大小 弹幕时间
+ danmakuBlockType = 'danmakuBlockType',
+ danmakuShowArea = 'danmakuShowArea',
+ danmakuOpacity = 'danmakuOpacity',
+ danmakuFontScale = 'danmakuFontScale',
+ danmakuDuration = 'danmakuDuration',
- // 代理host port
- static const String systemProxyHost = 'systemProxyHost';
- static const String systemProxyPort = 'systemProxyPort';
+ // 代理host port
+ systemProxyHost = 'systemProxyHost',
+ systemProxyPort = 'systemProxyPort';
}
class VideoBoxKey {
// 视频比例
- static const String videoFit = 'videoFit';
- // 亮度
- static const String videoBrightness = 'videoBrightness';
- // 倍速
- static const String videoSpeed = 'videoSpeed';
- // 播放顺序
- static const String playRepeat = 'playRepeat';
- // 默认倍速
- static const String playSpeedDefault = 'playSpeedDefault';
- // 默认长按倍速
- static const String longPressSpeedDefault = 'longPressSpeedDefault';
- // 自定义倍速集合
- static const String customSpeedsList = 'customSpeedsList';
- // 画面填充比例
- static const String cacheVideoFit = 'cacheVideoFit';
+ static const String videoFit = 'videoFit',
+ // 亮度
+ videoBrightness = 'videoBrightness',
+ // 倍速
+ videoSpeed = 'videoSpeed',
+ // 播放顺序
+ playRepeat = 'playRepeat',
+ // 默认倍速
+ playSpeedDefault = 'playSpeedDefault',
+ // 默认长按倍速
+ longPressSpeedDefault = 'longPressSpeedDefault',
+ // 自定义倍速集合
+ customSpeedsList = 'customSpeedsList',
+ // 画面填充比例
+ cacheVideoFit = 'cacheVideoFit';
}
diff --git a/pubspec.yaml b/pubspec.yaml
index e8572cc4..dcd17995 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# In Windows, build-name is used as the major, minor, and patch parts
# of the product and file versions while build-number is used as the build suffix.
-version: 1.0.14
+version: 1.0.15
environment:
sdk: ">=2.19.6 <3.0.0"