Compare commits
17 Commits
feature-se
...
feature-hi
| Author | SHA1 | Date | |
|---|---|---|---|
| 99e6abdad9 | |||
| 3ece2bb173 | |||
| 06fb3e8d2f | |||
| 504be6fbda | |||
| df4539a035 | |||
| a3e1fd4e91 | |||
| 3bf6136bc6 | |||
| ab24da5f55 | |||
| ed0b43eff1 | |||
| ab9ae3a481 | |||
| d728b1fb6d | |||
| 12e947ef84 | |||
| 3fad86e7e3 | |||
| fea70011cb | |||
| 32cdb27f7c | |||
| eb4435045b | |||
| f1b829cec1 |
9
change_log/1.0.21.0306.md
Normal file
9
change_log/1.0.21.0306.md
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
## 1.0.21
|
||||||
|
|
||||||
|
### 修复
|
||||||
|
+ 推荐视频全屏问题
|
||||||
|
+ 番剧全屏播放时灰屏问题
|
||||||
|
+ 评论回调导致页面卡死问题
|
||||||
|
|
||||||
|
更多更新日志可在Github上查看
|
||||||
|
问题反馈、功能建议请查看「关于」页面。
|
||||||
@ -38,6 +38,10 @@ class VideoCardH extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final int aid = videoItem.aid;
|
final int aid = videoItem.aid;
|
||||||
final String bvid = videoItem.bvid;
|
final String bvid = videoItem.bvid;
|
||||||
|
String type = 'video';
|
||||||
|
try {
|
||||||
|
type = videoItem.type;
|
||||||
|
} catch (_) {}
|
||||||
final String heroTag = Utils.makeHeroTag(aid);
|
final String heroTag = Utils.makeHeroTag(aid);
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
onLongPress: () {
|
onLongPress: () {
|
||||||
@ -53,6 +57,10 @@ class VideoCardH extends StatelessWidget {
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
try {
|
try {
|
||||||
|
if (type == 'ketang') {
|
||||||
|
SmartDialog.showToast('课堂视频暂不支持播放');
|
||||||
|
return;
|
||||||
|
}
|
||||||
final int cid =
|
final int cid =
|
||||||
videoItem.cid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid);
|
videoItem.cid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid);
|
||||||
Get.toNamed('/video?bvid=$bvid&cid=$cid',
|
Get.toNamed('/video?bvid=$bvid&cid=$cid',
|
||||||
@ -95,12 +103,20 @@ class VideoCardH extends StatelessWidget {
|
|||||||
height: maxHeight,
|
height: maxHeight,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (videoItem.duration != 0)
|
||||||
PBadge(
|
PBadge(
|
||||||
text: Utils.timeFormat(videoItem.duration!),
|
text: Utils.timeFormat(videoItem.duration!),
|
||||||
right: 6.0,
|
right: 6.0,
|
||||||
bottom: 6.0,
|
bottom: 6.0,
|
||||||
type: 'gray',
|
type: 'gray',
|
||||||
),
|
),
|
||||||
|
if (type != 'video')
|
||||||
|
PBadge(
|
||||||
|
text: type,
|
||||||
|
left: 6.0,
|
||||||
|
bottom: 6.0,
|
||||||
|
type: 'primary',
|
||||||
|
),
|
||||||
// if (videoItem.rcmdReason != null &&
|
// if (videoItem.rcmdReason != null &&
|
||||||
// videoItem.rcmdReason.content != '')
|
// videoItem.rcmdReason.content != '')
|
||||||
// pBadge(videoItem.rcmdReason.content, context,
|
// pBadge(videoItem.rcmdReason.content, context,
|
||||||
|
|||||||
@ -490,9 +490,6 @@ class Api {
|
|||||||
/// 我的订阅详情
|
/// 我的订阅详情
|
||||||
static const userSubFolderDetail = '/x/space/fav/season/list';
|
static const userSubFolderDetail = '/x/space/fav/season/list';
|
||||||
|
|
||||||
/// 取消订阅
|
|
||||||
static const userSubCancel = '/x/v3/fav/season/unfav';
|
|
||||||
|
|
||||||
/// 表情
|
/// 表情
|
||||||
static const emojiList = '/x/emote/user/panel/web';
|
static const emojiList = '/x/emote/user/panel/web';
|
||||||
|
|
||||||
|
|||||||
@ -349,21 +349,4 @@ class UserHttp {
|
|||||||
return {'status': false, 'msg': res.data['message']};
|
return {'status': false, 'msg': res.data['message']};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 取消订阅
|
|
||||||
static Future userSubCancel({required int seasonId}) async {
|
|
||||||
var res = await Request().post(
|
|
||||||
Api.userSubCancel,
|
|
||||||
queryParameters: {
|
|
||||||
'season_id': seasonId,
|
|
||||||
'platform': 'web',
|
|
||||||
'csrf': await Request.getCsrf(),
|
|
||||||
},
|
|
||||||
);
|
|
||||||
if (res.data['code'] == 0) {
|
|
||||||
return {'status': true, 'msg': '取消订阅成功'};
|
|
||||||
} else {
|
|
||||||
return {'status': false, 'msg': res.data['message']};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
const defaultNavigationBars = [
|
List defaultNavigationBars = [
|
||||||
{
|
{
|
||||||
'id': 0,
|
'id': 0,
|
||||||
'icon': Icon(
|
'icon': const Icon(
|
||||||
Icons.home_outlined,
|
Icons.home_outlined,
|
||||||
size: 21,
|
size: 21,
|
||||||
),
|
),
|
||||||
'selectIcon': Icon(
|
'selectIcon': const Icon(
|
||||||
Icons.home,
|
Icons.home,
|
||||||
size: 21,
|
size: 21,
|
||||||
),
|
),
|
||||||
@ -16,11 +16,11 @@ const defaultNavigationBars = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id': 1,
|
'id': 1,
|
||||||
'icon': Icon(
|
'icon': const Icon(
|
||||||
Icons.motion_photos_on_outlined,
|
Icons.motion_photos_on_outlined,
|
||||||
size: 21,
|
size: 21,
|
||||||
),
|
),
|
||||||
'selectIcon': Icon(
|
'selectIcon': const Icon(
|
||||||
Icons.motion_photos_on,
|
Icons.motion_photos_on,
|
||||||
size: 21,
|
size: 21,
|
||||||
),
|
),
|
||||||
@ -29,11 +29,11 @@ const defaultNavigationBars = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
'id': 2,
|
'id': 2,
|
||||||
'icon': Icon(
|
'icon': const Icon(
|
||||||
Icons.video_collection_outlined,
|
Icons.video_collection_outlined,
|
||||||
size: 20,
|
size: 20,
|
||||||
),
|
),
|
||||||
'selectIcon': Icon(
|
'selectIcon': const Icon(
|
||||||
Icons.video_collection,
|
Icons.video_collection,
|
||||||
size: 21,
|
size: 21,
|
||||||
),
|
),
|
||||||
|
|||||||
@ -85,7 +85,9 @@ class SearchVideoItemModel {
|
|||||||
// title = json['title'].replaceAll(RegExp(r'<.*?>'), '');
|
// title = json['title'].replaceAll(RegExp(r'<.*?>'), '');
|
||||||
title = Em.regTitle(json['title']);
|
title = Em.regTitle(json['title']);
|
||||||
description = json['description'];
|
description = json['description'];
|
||||||
pic = 'https:${json['pic']}';
|
pic = json['pic'] != null && json['pic'].startsWith('//')
|
||||||
|
? 'https:${json['pic']}'
|
||||||
|
: json['pic'] ?? '';
|
||||||
videoReview = json['video_review'];
|
videoReview = json['video_review'];
|
||||||
pubdate = json['pubdate'];
|
pubdate = json['pubdate'];
|
||||||
senddate = json['senddate'];
|
senddate = json['senddate'];
|
||||||
|
|||||||
@ -201,7 +201,6 @@ class _AboutPageState extends State<AboutPage> {
|
|||||||
var cleanStatus = await CacheManage().clearCacheAll();
|
var cleanStatus = await CacheManage().clearCacheAll();
|
||||||
if (cleanStatus) {
|
if (cleanStatus) {
|
||||||
getCacheSize();
|
getCacheSize();
|
||||||
SmartDialog.showToast('清除成功');
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
title: const Text('清除缓存'),
|
title: const Text('清除缓存'),
|
||||||
@ -254,12 +253,16 @@ class AboutController extends GetxController {
|
|||||||
// 获取远程版本
|
// 获取远程版本
|
||||||
Future getRemoteApp() async {
|
Future getRemoteApp() async {
|
||||||
var result = await Request().get(Api.latestApp, extra: {'ua': 'pc'});
|
var result = await Request().get(Api.latestApp, extra: {'ua': 'pc'});
|
||||||
|
isLoading.value = false;
|
||||||
|
if (result.data == null || result.data.isEmpty) {
|
||||||
|
SmartDialog.showToast('获取远程版本失败,请检查网络');
|
||||||
|
return;
|
||||||
|
}
|
||||||
data = LatestDataModel.fromJson(result.data);
|
data = LatestDataModel.fromJson(result.data);
|
||||||
remoteAppInfo = data;
|
remoteAppInfo = data;
|
||||||
remoteVersion.value = data.tagName!;
|
remoteVersion.value = data.tagName!;
|
||||||
isUpdate.value =
|
isUpdate.value =
|
||||||
Utils.needUpdate(currentVersion.value, remoteVersion.value);
|
Utils.needUpdate(currentVersion.value, remoteVersion.value);
|
||||||
isLoading.value = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 跳转下载/本地更新
|
// 跳转下载/本地更新
|
||||||
@ -277,7 +280,7 @@ class AboutController extends GetxController {
|
|||||||
|
|
||||||
githubRelease() {
|
githubRelease() {
|
||||||
launchUrl(
|
launchUrl(
|
||||||
Uri.parse('https://github.com/guozhigq/pilipala/release'),
|
Uri.parse('https://github.com/guozhigq/pilipala/releases'),
|
||||||
mode: LaunchMode.externalApplication,
|
mode: LaunchMode.externalApplication,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,8 +34,6 @@ class HomeController extends GetxController with GetTickerProviderStateMixin {
|
|||||||
userInfo = userInfoCache.get('userInfoCache');
|
userInfo = userInfoCache.get('userInfoCache');
|
||||||
userLogin.value = userInfo != null;
|
userLogin.value = userInfo != null;
|
||||||
userFace.value = userInfo != null ? userInfo.face : '';
|
userFace.value = userInfo != null ? userInfo.face : '';
|
||||||
// 进行tabs配置
|
|
||||||
setTabConfig();
|
|
||||||
hideSearchBar =
|
hideSearchBar =
|
||||||
setting.get(SettingBoxKey.hideSearchBar, defaultValue: true);
|
setting.get(SettingBoxKey.hideSearchBar, defaultValue: true);
|
||||||
if (setting.get(SettingBoxKey.enableSearchWord, defaultValue: true)) {
|
if (setting.get(SettingBoxKey.enableSearchWord, defaultValue: true)) {
|
||||||
@ -43,6 +41,8 @@ class HomeController extends GetxController with GetTickerProviderStateMixin {
|
|||||||
}
|
}
|
||||||
enableGradientBg =
|
enableGradientBg =
|
||||||
setting.get(SettingBoxKey.enableGradientBg, defaultValue: true);
|
setting.get(SettingBoxKey.enableGradientBg, defaultValue: true);
|
||||||
|
// 进行tabs配置
|
||||||
|
setTabConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onRefresh() {
|
void onRefresh() {
|
||||||
@ -91,6 +91,7 @@ class HomeController extends GetxController with GetTickerProviderStateMixin {
|
|||||||
vsync: this,
|
vsync: this,
|
||||||
);
|
);
|
||||||
// 监听 tabController 切换
|
// 监听 tabController 切换
|
||||||
|
if (enableGradientBg) {
|
||||||
tabController.animation!.addListener(() {
|
tabController.animation!.addListener(() {
|
||||||
if (tabController.indexIsChanging) {
|
if (tabController.indexIsChanging) {
|
||||||
if (initialIndex.value != tabController.index) {
|
if (initialIndex.value != tabController.index) {
|
||||||
@ -105,6 +106,7 @@ class HomeController extends GetxController with GetTickerProviderStateMixin {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void searchDefault() async {
|
void searchDefault() async {
|
||||||
var res = await Request().get(Api.searchDefault);
|
var res = await Request().get(Api.searchDefault);
|
||||||
|
|||||||
@ -29,7 +29,6 @@ class BottomControl extends StatefulWidget implements PreferredSizeWidget {
|
|||||||
|
|
||||||
class _BottomControlState extends State<BottomControl> {
|
class _BottomControlState extends State<BottomControl> {
|
||||||
late PlayUrlModel videoInfo;
|
late PlayUrlModel videoInfo;
|
||||||
List<PlaySpeed> playSpeed = PlaySpeed.values;
|
|
||||||
TextStyle subTitleStyle = const TextStyle(fontSize: 12);
|
TextStyle subTitleStyle = const TextStyle(fontSize: 12);
|
||||||
TextStyle titleStyle = const TextStyle(fontSize: 14);
|
TextStyle titleStyle = const TextStyle(fontSize: 14);
|
||||||
Size get preferredSize => const Size(double.infinity, kToolbarHeight);
|
Size get preferredSize => const Size(double.infinity, kToolbarHeight);
|
||||||
|
|||||||
@ -173,6 +173,12 @@ class _ExtraSettingState extends State<ExtraSetting> {
|
|||||||
setKey: SettingBoxKey.enableAi,
|
setKey: SettingBoxKey.enableAi,
|
||||||
defaultVal: true,
|
defaultVal: true,
|
||||||
),
|
),
|
||||||
|
const SetSwitchItem(
|
||||||
|
title: '相关视频推荐',
|
||||||
|
subTitle: '视频详情页推荐相关视频',
|
||||||
|
setKey: SettingBoxKey.enableRelatedVideo,
|
||||||
|
defaultVal: true,
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
dense: false,
|
dense: false,
|
||||||
title: Text('评论展示', style: titleStyle),
|
title: Text('评论展示', style: titleStyle),
|
||||||
|
|||||||
@ -17,6 +17,7 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
|||||||
Box videoStorage = GStrorage.video;
|
Box videoStorage = GStrorage.video;
|
||||||
Box settingStorage = GStrorage.setting;
|
Box settingStorage = GStrorage.setting;
|
||||||
late double playSpeedDefault;
|
late double playSpeedDefault;
|
||||||
|
late List<double> playSpeedSystem;
|
||||||
late double longPressSpeedDefault;
|
late double longPressSpeedDefault;
|
||||||
late List customSpeedsList;
|
late List customSpeedsList;
|
||||||
late bool enableAutoLongPressSpeed;
|
late bool enableAutoLongPressSpeed;
|
||||||
@ -53,6 +54,9 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
// 系统预设倍速
|
||||||
|
playSpeedSystem =
|
||||||
|
videoStorage.get(VideoBoxKey.playSpeedSystem, defaultValue: playSpeed);
|
||||||
// 默认倍速
|
// 默认倍速
|
||||||
playSpeedDefault =
|
playSpeedDefault =
|
||||||
videoStorage.get(VideoBoxKey.playSpeedDefault, defaultValue: 1.0);
|
videoStorage.get(VideoBoxKey.playSpeedDefault, defaultValue: 1.0);
|
||||||
@ -64,6 +68,7 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
|||||||
videoStorage.get(VideoBoxKey.customSpeedsList, defaultValue: []);
|
videoStorage.get(VideoBoxKey.customSpeedsList, defaultValue: []);
|
||||||
enableAutoLongPressSpeed = settingStorage
|
enableAutoLongPressSpeed = settingStorage
|
||||||
.get(SettingBoxKey.enableAutoLongPressSpeed, defaultValue: false);
|
.get(SettingBoxKey.enableAutoLongPressSpeed, defaultValue: false);
|
||||||
|
// 开启动态长按倍速时不展示
|
||||||
if (enableAutoLongPressSpeed) {
|
if (enableAutoLongPressSpeed) {
|
||||||
Map newItem = sheetMenu[1];
|
Map newItem = sheetMenu[1];
|
||||||
newItem['show'] = false;
|
newItem['show'] = false;
|
||||||
@ -123,7 +128,7 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 设定倍速弹窗
|
// 设定倍速弹窗
|
||||||
void showBottomSheet(type, i) {
|
void showBottomSheet(String type, int i) {
|
||||||
showModalBottomSheet<void>(
|
showModalBottomSheet<void>(
|
||||||
context: context,
|
context: context,
|
||||||
isScrollControlled: true,
|
isScrollControlled: true,
|
||||||
@ -159,18 +164,11 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
void menuAction(type, index, id) async {
|
void menuAction(type, int index, id) async {
|
||||||
double chooseSpeed = 1.0;
|
double chooseSpeed = 1.0;
|
||||||
if (type == 'system' && id == -1) {
|
|
||||||
SmartDialog.showToast('系统预设倍速不支持删除');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
// 获取当前选中的倍速值
|
// 获取当前选中的倍速值
|
||||||
if (type == 'system') {
|
chooseSpeed =
|
||||||
chooseSpeed = PlaySpeed.values[index].value;
|
type == 'system' ? playSpeedSystem[index] : customSpeedsList[index];
|
||||||
} else {
|
|
||||||
chooseSpeed = customSpeedsList[index];
|
|
||||||
}
|
|
||||||
// 设置
|
// 设置
|
||||||
if (id == 1) {
|
if (id == 1) {
|
||||||
// 设置默认倍速
|
// 设置默认倍速
|
||||||
@ -182,17 +180,22 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
|||||||
videoStorage.put(
|
videoStorage.put(
|
||||||
VideoBoxKey.longPressSpeedDefault, longPressSpeedDefault);
|
VideoBoxKey.longPressSpeedDefault, longPressSpeedDefault);
|
||||||
} else if (id == -1) {
|
} else if (id == -1) {
|
||||||
if (customSpeedsList[index] == playSpeedDefault) {
|
late List speedsList =
|
||||||
playSpeedDefault = 1.0;
|
type == 'system' ? playSpeedSystem : customSpeedsList;
|
||||||
videoStorage.put(VideoBoxKey.playSpeedDefault, playSpeedDefault);
|
if (speedsList[index] == playSpeedDefault) {
|
||||||
|
SmartDialog.showToast('默认倍速不可删除');
|
||||||
}
|
}
|
||||||
if (customSpeedsList[index] == longPressSpeedDefault) {
|
if (speedsList[index] == longPressSpeedDefault) {
|
||||||
longPressSpeedDefault = 2.0;
|
longPressSpeedDefault = 2.0;
|
||||||
videoStorage.put(
|
videoStorage.put(
|
||||||
VideoBoxKey.longPressSpeedDefault, longPressSpeedDefault);
|
VideoBoxKey.longPressSpeedDefault, longPressSpeedDefault);
|
||||||
}
|
}
|
||||||
customSpeedsList.removeAt(index);
|
speedsList.removeAt(index);
|
||||||
await videoStorage.put(VideoBoxKey.customSpeedsList, customSpeedsList);
|
await videoStorage.put(
|
||||||
|
type == 'system'
|
||||||
|
? VideoBoxKey.playSpeedSystem
|
||||||
|
: VideoBoxKey.customSpeedsList,
|
||||||
|
speedsList);
|
||||||
}
|
}
|
||||||
setState(() {});
|
setState(() {});
|
||||||
SmartDialog.showToast('操作成功');
|
SmartDialog.showToast('操作成功');
|
||||||
@ -249,6 +252,7 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
|||||||
subtitle: Text(longPressSpeedDefault.toString()),
|
subtitle: Text(longPressSpeedDefault.toString()),
|
||||||
)
|
)
|
||||||
: const SizedBox(),
|
: const SizedBox(),
|
||||||
|
if (playSpeedSystem.isNotEmpty) ...[
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
left: 14,
|
left: 14,
|
||||||
@ -272,15 +276,16 @@ class _PlaySpeedPageState extends State<PlaySpeedPage> {
|
|||||||
spacing: 8,
|
spacing: 8,
|
||||||
runSpacing: 2,
|
runSpacing: 2,
|
||||||
children: [
|
children: [
|
||||||
for (var i in PlaySpeed.values) ...[
|
for (int i = 0; i < playSpeedSystem.length; i++) ...[
|
||||||
FilledButton.tonal(
|
FilledButton.tonal(
|
||||||
onPressed: () => showBottomSheet('system', i.index),
|
onPressed: () => showBottomSheet('system', i),
|
||||||
child: Text(i.description),
|
child: Text(playSpeedSystem[i].toString()),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
)
|
||||||
|
],
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(
|
padding: const EdgeInsets.only(
|
||||||
left: 14,
|
left: 14,
|
||||||
|
|||||||
@ -46,41 +46,4 @@ class SubController extends GetxController {
|
|||||||
Future onLoad() async {
|
Future onLoad() async {
|
||||||
querySubFolder(type: 'onload');
|
querySubFolder(type: 'onload');
|
||||||
}
|
}
|
||||||
|
|
||||||
// 取消订阅
|
|
||||||
Future<dynamic> cancelSub({required int id}) async {
|
|
||||||
showDialog(
|
|
||||||
context: Get.context!,
|
|
||||||
builder: (context) {
|
|
||||||
return AlertDialog(
|
|
||||||
title: const Text('提示'),
|
|
||||||
content: const Text('确认要取消订阅吗?'),
|
|
||||||
actions: [
|
|
||||||
TextButton(
|
|
||||||
onPressed: () => Get.back(),
|
|
||||||
child: Text(
|
|
||||||
'取消',
|
|
||||||
style:
|
|
||||||
TextStyle(color: Theme.of(context).colorScheme.outline),
|
|
||||||
)),
|
|
||||||
TextButton(
|
|
||||||
onPressed: () async {
|
|
||||||
Get.back();
|
|
||||||
var res = await UserHttp.userSubCancel(seasonId: id);
|
|
||||||
if (res['status']) {
|
|
||||||
SmartDialog.showToast('取消订阅成功');
|
|
||||||
subFolderData.value.list!
|
|
||||||
.removeWhere((element) => element.id == id);
|
|
||||||
subFolderData.update((val) {});
|
|
||||||
} else {
|
|
||||||
SmartDialog.showToast(res['msg']);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
child: const Text('确认'),
|
|
||||||
)
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -58,14 +58,7 @@ class _SubPageState extends State<SubPage> {
|
|||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
return SubItem(
|
return SubItem(
|
||||||
subFolderItem:
|
subFolderItem:
|
||||||
_subController.subFolderData.value.list![index],
|
_subController.subFolderData.value.list![index]);
|
||||||
fuc: () {
|
|
||||||
_subController.cancelSub(
|
|
||||||
id: _subController
|
|
||||||
.subFolderData.value.list![index].id!,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -8,8 +8,7 @@ import '../../../models/user/sub_folder.dart';
|
|||||||
|
|
||||||
class SubItem extends StatelessWidget {
|
class SubItem extends StatelessWidget {
|
||||||
final SubFolderItemData subFolderItem;
|
final SubFolderItemData subFolderItem;
|
||||||
final Function fuc;
|
const SubItem({super.key, required this.subFolderItem});
|
||||||
const SubItem({super.key, required this.subFolderItem, required this.fuc});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -52,7 +51,7 @@ class SubItem extends StatelessWidget {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
VideoContent(subFolderItem: subFolderItem, fuc: fuc)
|
VideoContent(subFolderItem: subFolderItem)
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -65,9 +64,7 @@ class SubItem extends StatelessWidget {
|
|||||||
|
|
||||||
class VideoContent extends StatelessWidget {
|
class VideoContent extends StatelessWidget {
|
||||||
final SubFolderItemData subFolderItem;
|
final SubFolderItemData subFolderItem;
|
||||||
final Function fuc;
|
const VideoContent({super.key, required this.subFolderItem});
|
||||||
const VideoContent(
|
|
||||||
{super.key, required this.subFolderItem, required this.fuc});
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -103,20 +100,6 @@ class VideoContent extends StatelessWidget {
|
|||||||
color: Theme.of(context).colorScheme.outline,
|
color: Theme.of(context).colorScheme.outline,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const Spacer(),
|
|
||||||
SizedBox(
|
|
||||||
height: 34,
|
|
||||||
child: TextButton(
|
|
||||||
onPressed: () => fuc(),
|
|
||||||
style: TextButton.styleFrom(
|
|
||||||
padding: const EdgeInsets.fromLTRB(15, 0, 15, 0),
|
|
||||||
foregroundColor: Theme.of(context).colorScheme.outline,
|
|
||||||
backgroundColor:
|
|
||||||
Theme.of(context).colorScheme.onInverseSurface, // 设置按钮背景色
|
|
||||||
),
|
|
||||||
child: const Text('取消订阅'),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@ -91,6 +91,7 @@ class VideoDetailController extends GetxController
|
|||||||
late int cacheAudioQa;
|
late int cacheAudioQa;
|
||||||
|
|
||||||
PersistentBottomSheetController? replyReplyBottomSheetCtr;
|
PersistentBottomSheetController? replyReplyBottomSheetCtr;
|
||||||
|
late bool enableRelatedVideo;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
@ -113,7 +114,8 @@ class VideoDetailController extends GetxController
|
|||||||
autoPlay.value =
|
autoPlay.value =
|
||||||
setting.get(SettingBoxKey.autoPlayEnable, defaultValue: true);
|
setting.get(SettingBoxKey.autoPlayEnable, defaultValue: true);
|
||||||
enableHA.value = setting.get(SettingBoxKey.enableHA, defaultValue: true);
|
enableHA.value = setting.get(SettingBoxKey.enableHA, defaultValue: true);
|
||||||
|
enableRelatedVideo =
|
||||||
|
setting.get(SettingBoxKey.enableRelatedVideo, defaultValue: true);
|
||||||
if (userInfo == null ||
|
if (userInfo == null ||
|
||||||
localCache.get(LocalCacheKey.historyPause) == true) {
|
localCache.get(LocalCacheKey.historyPause) == true) {
|
||||||
enableHeart = false;
|
enableHeart = false;
|
||||||
@ -129,6 +131,7 @@ class VideoDetailController extends GetxController
|
|||||||
videoDetailCtr: this,
|
videoDetailCtr: this,
|
||||||
floating: floating,
|
floating: floating,
|
||||||
bvid: bvid,
|
bvid: bvid,
|
||||||
|
videoType: videoType,
|
||||||
);
|
);
|
||||||
// CDN优化
|
// CDN优化
|
||||||
enableCDN = setting.get(SettingBoxKey.enableCDN, defaultValue: true);
|
enableCDN = setting.get(SettingBoxKey.enableCDN, defaultValue: true);
|
||||||
|
|||||||
@ -23,7 +23,10 @@ class IntroDetail extends StatelessWidget {
|
|||||||
sheetHeight = localCache.get('sheetHeight');
|
sheetHeight = localCache.get('sheetHeight');
|
||||||
return Container(
|
return Container(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.background,
|
||||||
padding: const EdgeInsets.only(left: 14, right: 14),
|
padding: EdgeInsets.only(
|
||||||
|
left: 14,
|
||||||
|
right: 14,
|
||||||
|
bottom: MediaQuery.of(context).padding.bottom + 20),
|
||||||
height: sheetHeight,
|
height: sheetHeight,
|
||||||
child: Column(
|
child: Column(
|
||||||
children: [
|
children: [
|
||||||
|
|||||||
@ -280,7 +280,7 @@ class ReplyItem extends StatelessWidget {
|
|||||||
// 完成评论,数据添加
|
// 完成评论,数据添加
|
||||||
if (value != null && value['data'] != null)
|
if (value != null && value['data'] != null)
|
||||||
{
|
{
|
||||||
addReply!(value['data'])
|
addReply?.call(value['data'])
|
||||||
// replyControl.replies.add(value['data']),
|
// replyControl.replies.add(value['data']),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -531,8 +531,8 @@ InlineSpan buildContent(
|
|||||||
spanChilds.add(TextSpan(
|
spanChilds.add(TextSpan(
|
||||||
text: str,
|
text: str,
|
||||||
recognizer: TapGestureRecognizer()
|
recognizer: TapGestureRecognizer()
|
||||||
..onTap =
|
..onTap = () =>
|
||||||
() => replyReply(replyItem.root == 0 ? replyItem : fReplyItem)));
|
replyReply?.call(replyItem.root == 0 ? replyItem : fReplyItem)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// 分割文本并处理每个部分
|
// 分割文本并处理每个部分
|
||||||
@ -642,6 +642,11 @@ InlineSpan buildContent(
|
|||||||
} else {
|
} else {
|
||||||
final String redirectUrl =
|
final String redirectUrl =
|
||||||
await UrlUtils.parseRedirectUrl(matchStr);
|
await UrlUtils.parseRedirectUrl(matchStr);
|
||||||
|
if (redirectUrl == matchStr) {
|
||||||
|
Clipboard.setData(ClipboardData(text: matchStr));
|
||||||
|
SmartDialog.showToast('地址可能有误');
|
||||||
|
return;
|
||||||
|
}
|
||||||
final String pathSegment = Uri.parse(redirectUrl).path;
|
final String pathSegment = Uri.parse(redirectUrl).path;
|
||||||
final String lastPathSegment =
|
final String lastPathSegment =
|
||||||
pathSegment.split('/').last;
|
pathSegment.split('/').last;
|
||||||
|
|||||||
@ -30,6 +30,9 @@ class VideoReplyReplyController extends GetxController {
|
|||||||
if (type == 'init') {
|
if (type == 'init') {
|
||||||
currentPage = 0;
|
currentPage = 0;
|
||||||
}
|
}
|
||||||
|
if (isLoadingMore) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
isLoadingMore = true;
|
isLoadingMore = true;
|
||||||
final res = await ReplyHttp.replyReplyList(
|
final res = await ReplyHttp.replyReplyList(
|
||||||
oid: aid!,
|
oid: aid!,
|
||||||
@ -41,7 +44,7 @@ class VideoReplyReplyController extends GetxController {
|
|||||||
final List<ReplyItemModel> replies = res['data'].replies;
|
final List<ReplyItemModel> replies = res['data'].replies;
|
||||||
if (replies.isNotEmpty) {
|
if (replies.isNotEmpty) {
|
||||||
noMore.value = '加载中...';
|
noMore.value = '加载中...';
|
||||||
if (replyList.length == res['data'].page.count) {
|
if (replies.length == res['data'].page.count) {
|
||||||
noMore.value = '没有更多了';
|
noMore.value = '没有更多了';
|
||||||
}
|
}
|
||||||
currentPage++;
|
currentPage++;
|
||||||
@ -50,21 +53,6 @@ class VideoReplyReplyController extends GetxController {
|
|||||||
noMore.value = currentPage == 0 ? '还没有评论' : '没有更多了';
|
noMore.value = currentPage == 0 ? '还没有评论' : '没有更多了';
|
||||||
}
|
}
|
||||||
if (type == 'init') {
|
if (type == 'init') {
|
||||||
// List<ReplyItemModel> replies = res['data'].replies;
|
|
||||||
// 添加置顶回复
|
|
||||||
// if (res['data'].upper.top != null) {
|
|
||||||
// bool flag = false;
|
|
||||||
// for (var i = 0; i < res['data'].topReplies.length; i++) {
|
|
||||||
// if (res['data'].topReplies[i].rpid == res['data'].upper.top.rpid) {
|
|
||||||
// flag = true;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// if (!flag) {
|
|
||||||
// replies.insert(0, res['data'].upper.top);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// replies.insertAll(0, res['data'].topReplies);
|
|
||||||
// res['data'].replies = replies;
|
|
||||||
replyList.value = replies;
|
replyList.value = replies;
|
||||||
} else {
|
} else {
|
||||||
// 每次回复之后,翻页请求有且只有相同的一条回复数据
|
// 每次回复之后,翻页请求有且只有相同的一条回复数据
|
||||||
|
|||||||
@ -54,7 +54,8 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
|
|||||||
() {
|
() {
|
||||||
if (scrollController.position.pixels >=
|
if (scrollController.position.pixels >=
|
||||||
scrollController.position.maxScrollExtent - 300) {
|
scrollController.position.maxScrollExtent - 300) {
|
||||||
EasyThrottle.throttle('replylist', const Duration(seconds: 2), () {
|
EasyThrottle.throttle('replylist', const Duration(milliseconds: 200),
|
||||||
|
() {
|
||||||
_videoReplyReplyController.queryReplyList(type: 'onLoad');
|
_videoReplyReplyController.queryReplyList(type: 'onLoad');
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -92,7 +93,7 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
|
|||||||
icon: const Icon(Icons.close, size: 20),
|
icon: const Icon(Icons.close, size: 20),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
_videoReplyReplyController.currentPage = 0;
|
_videoReplyReplyController.currentPage = 0;
|
||||||
widget.closePanel!();
|
widget.closePanel?.call;
|
||||||
Navigator.pop(context);
|
Navigator.pop(context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@ -184,6 +185,8 @@ class _VideoReplyReplyPanelState extends State<VideoReplyReplyPanel> {
|
|||||||
.add(replyItem);
|
.add(replyItem);
|
||||||
},
|
},
|
||||||
replyType: widget.replyType,
|
replyType: widget.replyType,
|
||||||
|
replyReply: (replyItem) =>
|
||||||
|
replyReply(replyItem),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -521,6 +521,9 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
.withOpacity(0.06),
|
.withOpacity(0.06),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (videoDetailController.videoType ==
|
||||||
|
SearchType.video &&
|
||||||
|
videoDetailController.enableRelatedVideo)
|
||||||
const RelatedVideoPanel(),
|
const RelatedVideoPanel(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
@ -572,6 +575,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
controller: plPlayerController,
|
controller: plPlayerController,
|
||||||
videoDetailCtr: videoDetailController,
|
videoDetailCtr: videoDetailController,
|
||||||
bvid: videoDetailController.bvid,
|
bvid: videoDetailController.bvid,
|
||||||
|
videoType: videoDetailController.videoType,
|
||||||
),
|
),
|
||||||
danmuWidget: Obx(
|
danmuWidget: Obx(
|
||||||
() => PlDanmaku(
|
() => PlDanmaku(
|
||||||
|
|||||||
@ -19,6 +19,7 @@ import 'package:pilipala/plugin/pl_player/models/play_repeat.dart';
|
|||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
import 'package:pilipala/http/danmaku.dart';
|
import 'package:pilipala/http/danmaku.dart';
|
||||||
import 'package:pilipala/services/shutdown_timer_service.dart';
|
import 'package:pilipala/services/shutdown_timer_service.dart';
|
||||||
|
import '../../../../models/common/search_type.dart';
|
||||||
import '../../../../models/video_detail_res.dart';
|
import '../../../../models/video_detail_res.dart';
|
||||||
import '../introduction/index.dart';
|
import '../introduction/index.dart';
|
||||||
|
|
||||||
@ -28,12 +29,14 @@ class HeaderControl extends StatefulWidget implements PreferredSizeWidget {
|
|||||||
this.videoDetailCtr,
|
this.videoDetailCtr,
|
||||||
this.floating,
|
this.floating,
|
||||||
this.bvid,
|
this.bvid,
|
||||||
|
this.videoType,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
final PlPlayerController? controller;
|
final PlPlayerController? controller;
|
||||||
final VideoDetailController? videoDetailCtr;
|
final VideoDetailController? videoDetailCtr;
|
||||||
final Floating? floating;
|
final Floating? floating;
|
||||||
final String? bvid;
|
final String? bvid;
|
||||||
|
final SearchType? videoType;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<HeaderControl> createState() => _HeaderControlState();
|
State<HeaderControl> createState() => _HeaderControlState();
|
||||||
@ -44,7 +47,6 @@ class HeaderControl extends StatefulWidget implements PreferredSizeWidget {
|
|||||||
|
|
||||||
class _HeaderControlState extends State<HeaderControl> {
|
class _HeaderControlState extends State<HeaderControl> {
|
||||||
late PlayUrlModel videoInfo;
|
late PlayUrlModel videoInfo;
|
||||||
List<PlaySpeed> playSpeed = PlaySpeed.values;
|
|
||||||
static const TextStyle subTitleStyle = TextStyle(fontSize: 12);
|
static const TextStyle subTitleStyle = TextStyle(fontSize: 12);
|
||||||
static const TextStyle titleStyle = TextStyle(fontSize: 14);
|
static const TextStyle titleStyle = TextStyle(fontSize: 14);
|
||||||
Size get preferredSize => const Size(double.infinity, kToolbarHeight);
|
Size get preferredSize => const Size(double.infinity, kToolbarHeight);
|
||||||
@ -76,7 +78,11 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
} else {
|
} else {
|
||||||
showTitle = false;
|
showTitle = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// TODO setState() called after dispose()
|
||||||
|
if (mounted) {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1107,14 +1113,16 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
SizedBox(width: buttonSpace),
|
SizedBox(width: buttonSpace),
|
||||||
if (showTitle && isLandscape) ...[
|
if (showTitle &&
|
||||||
|
isLandscape &&
|
||||||
|
widget.videoType == SearchType.video) ...[
|
||||||
Column(
|
Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
children: [
|
children: [
|
||||||
ConstrainedBox(
|
ConstrainedBox(
|
||||||
constraints: BoxConstraints(maxWidth: 200),
|
constraints: const BoxConstraints(maxWidth: 200),
|
||||||
child: Text(
|
child: Text(
|
||||||
videoIntroController.videoDetail.value.title!,
|
videoIntroController.videoDetail.value.title ?? '',
|
||||||
style: const TextStyle(
|
style: const TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
fontSize: 16,
|
fontSize: 16,
|
||||||
|
|||||||
@ -277,8 +277,7 @@ class PlPlayerController {
|
|||||||
danmakuDurationVal =
|
danmakuDurationVal =
|
||||||
localCache.get(LocalCacheKey.danmakuDuration, defaultValue: 4.0);
|
localCache.get(LocalCacheKey.danmakuDuration, defaultValue: 4.0);
|
||||||
// 描边粗细
|
// 描边粗细
|
||||||
strokeWidth =
|
strokeWidth = localCache.get(LocalCacheKey.strokeWidth, defaultValue: 1.5);
|
||||||
localCache.get(LocalCacheKey.strokeWidth, defaultValue: 1.5);
|
|
||||||
playRepeat = PlayRepeat.values.toList().firstWhere(
|
playRepeat = PlayRepeat.values.toList().firstWhere(
|
||||||
(e) =>
|
(e) =>
|
||||||
e.value ==
|
e.value ==
|
||||||
@ -293,11 +292,19 @@ class PlPlayerController {
|
|||||||
_longPressSpeed.value = videoStorage
|
_longPressSpeed.value = videoStorage
|
||||||
.get(VideoBoxKey.longPressSpeedDefault, defaultValue: 2.0);
|
.get(VideoBoxKey.longPressSpeedDefault, defaultValue: 2.0);
|
||||||
}
|
}
|
||||||
|
// 自定义倍速集合
|
||||||
speedsList = List<double>.from(videoStorage
|
speedsList = List<double>.from(videoStorage
|
||||||
.get(VideoBoxKey.customSpeedsList, defaultValue: <double>[]));
|
.get(VideoBoxKey.customSpeedsList, defaultValue: <double>[]));
|
||||||
for (final PlaySpeed i in PlaySpeed.values) {
|
// 默认倍速
|
||||||
speedsList.add(i.value);
|
speedsList = List<double>.from(videoStorage
|
||||||
}
|
.get(VideoBoxKey.customSpeedsList, defaultValue: <double>[]));
|
||||||
|
//playSpeedSystem
|
||||||
|
final List<double> playSpeedSystem =
|
||||||
|
videoStorage.get(VideoBoxKey.playSpeedSystem, defaultValue: playSpeed);
|
||||||
|
|
||||||
|
// for (final PlaySpeed i in PlaySpeed.values) {
|
||||||
|
speedsList.addAll(playSpeedSystem);
|
||||||
|
// }
|
||||||
|
|
||||||
// _playerEventSubs = onPlayerStatusChanged.listen((PlayerStatus status) {
|
// _playerEventSubs = onPlayerStatusChanged.listen((PlayerStatus status) {
|
||||||
// if (status == PlayerStatus.playing) {
|
// if (status == PlayerStatus.playing) {
|
||||||
@ -535,8 +542,10 @@ class PlPlayerController {
|
|||||||
if (event) {
|
if (event) {
|
||||||
playerStatus.status.value = PlayerStatus.playing;
|
playerStatus.status.value = PlayerStatus.playing;
|
||||||
} else {
|
} else {
|
||||||
// playerStatus.status.value = PlayerStatus.paused;
|
playerStatus.status.value = PlayerStatus.paused;
|
||||||
}
|
}
|
||||||
|
videoPlayerServiceHandler.onStatusChange(
|
||||||
|
playerStatus.status.value, isBuffering.value);
|
||||||
|
|
||||||
/// 触发回调事件
|
/// 触发回调事件
|
||||||
for (var element in _statusListeners) {
|
for (var element in _statusListeners) {
|
||||||
@ -675,18 +684,6 @@ class PlPlayerController {
|
|||||||
_playbackSpeed.value = speed;
|
_playbackSpeed.value = speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 设置倍速
|
|
||||||
// Future<void> togglePlaybackSpeed() async {
|
|
||||||
// List<double> allowedSpeeds =
|
|
||||||
// PlaySpeed.values.map<double>((e) => e.value).toList();
|
|
||||||
// int index = allowedSpeeds.indexOf(_playbackSpeed.value);
|
|
||||||
// if (index < allowedSpeeds.length - 1) {
|
|
||||||
// setPlaybackSpeed(allowedSpeeds[index + 1]);
|
|
||||||
// } else {
|
|
||||||
// setPlaybackSpeed(allowedSpeeds[0]);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
/// 播放视频
|
/// 播放视频
|
||||||
/// TODO _duration.value丢失
|
/// TODO _duration.value丢失
|
||||||
Future<void> play(
|
Future<void> play(
|
||||||
|
|||||||
@ -1,39 +1,15 @@
|
|||||||
enum PlaySpeed {
|
List<double> generatePlaySpeedList() {
|
||||||
pointTwoFive,
|
List<double> playSpeed = [];
|
||||||
pointFive,
|
double startSpeed = 0.25;
|
||||||
pointSevenFive,
|
double endSpeed = 2.0;
|
||||||
|
double increment = 0.25;
|
||||||
|
|
||||||
one,
|
for (double speed = startSpeed; speed <= endSpeed; speed += increment) {
|
||||||
onePointTwoFive,
|
playSpeed.add(speed);
|
||||||
onePointFive,
|
}
|
||||||
onePointSevenFive,
|
|
||||||
|
|
||||||
two,
|
return playSpeed;
|
||||||
}
|
}
|
||||||
|
|
||||||
extension PlaySpeedExtension on PlaySpeed {
|
// 导出 playSpeed 列表
|
||||||
static final List<String> _descList = [
|
List<double> playSpeed = generatePlaySpeedList();
|
||||||
'0.25',
|
|
||||||
'0.5',
|
|
||||||
'0.75',
|
|
||||||
'正常',
|
|
||||||
'1.25',
|
|
||||||
'1.5',
|
|
||||||
'1.75',
|
|
||||||
'2.0',
|
|
||||||
];
|
|
||||||
String get description => _descList[index];
|
|
||||||
|
|
||||||
static final List<double> _valueList = [
|
|
||||||
0.25,
|
|
||||||
0.5,
|
|
||||||
0.75,
|
|
||||||
1.0,
|
|
||||||
1.25,
|
|
||||||
1.5,
|
|
||||||
1.75,
|
|
||||||
2.0,
|
|
||||||
];
|
|
||||||
double get value => _valueList[index];
|
|
||||||
double get defaultValue => _valueList[3];
|
|
||||||
}
|
|
||||||
|
|||||||
@ -26,6 +26,7 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler {
|
|||||||
static final List<MediaItem> _item = [];
|
static final List<MediaItem> _item = [];
|
||||||
Box setting = GStrorage.setting;
|
Box setting = GStrorage.setting;
|
||||||
bool enableBackgroundPlay = false;
|
bool enableBackgroundPlay = false;
|
||||||
|
PlPlayerController player = PlPlayerController.getInstance();
|
||||||
|
|
||||||
VideoPlayerServiceHandler() {
|
VideoPlayerServiceHandler() {
|
||||||
revalidateSetting();
|
revalidateSetting();
|
||||||
@ -38,12 +39,12 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> play() async {
|
Future<void> play() async {
|
||||||
PlPlayerController.getInstance().play();
|
player.play();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> pause() async {
|
Future<void> pause() async {
|
||||||
PlPlayerController.getInstance().pause();
|
player.pause();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -51,7 +52,7 @@ class VideoPlayerServiceHandler extends BaseAudioHandler with SeekHandler {
|
|||||||
playbackState.add(playbackState.value.copyWith(
|
playbackState.add(playbackState.value.copyWith(
|
||||||
updatePosition: position,
|
updatePosition: position,
|
||||||
));
|
));
|
||||||
await PlPlayerController.getInstance().seekTo(position);
|
await player.seekTo(position);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> setMediaItem(MediaItem newMediaItem) async {
|
Future<void> setMediaItem(MediaItem newMediaItem) async {
|
||||||
|
|||||||
@ -20,7 +20,7 @@ class AudioSessionHandler {
|
|||||||
session.interruptionEventStream.listen((event) {
|
session.interruptionEventStream.listen((event) {
|
||||||
final player = PlPlayerController.getInstance();
|
final player = PlPlayerController.getInstance();
|
||||||
if (event.begin) {
|
if (event.begin) {
|
||||||
if (player.playerStatus != PlayerStatus.playing) return;
|
if (!player.playerStatus.playing) return;
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
case AudioInterruptionType.duck:
|
case AudioInterruptionType.duck:
|
||||||
player.setVolume(player.volume.value * 0.5);
|
player.setVolume(player.volume.value * 0.5);
|
||||||
@ -52,7 +52,7 @@ class AudioSessionHandler {
|
|||||||
// 耳机拔出暂停
|
// 耳机拔出暂停
|
||||||
session.becomingNoisyEventStream.listen((_) {
|
session.becomingNoisyEventStream.listen((_) {
|
||||||
final player = PlPlayerController.getInstance();
|
final player = PlPlayerController.getInstance();
|
||||||
if (player.playerStatus == PlayerStatus.playing) {
|
if (player.playerStatus.playing) {
|
||||||
player.pause();
|
player.pause();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@ -99,11 +99,9 @@ class CacheManage {
|
|||||||
try {
|
try {
|
||||||
// 清除缓存 图片缓存
|
// 清除缓存 图片缓存
|
||||||
await clearLibraryCache();
|
await clearLibraryCache();
|
||||||
Timer(const Duration(milliseconds: 500), () {
|
|
||||||
SmartDialog.dismiss().then((res) {
|
SmartDialog.dismiss().then((res) {
|
||||||
SmartDialog.showToast('清除完成');
|
SmartDialog.showToast('清除完成');
|
||||||
});
|
});
|
||||||
});
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
SmartDialog.dismiss();
|
SmartDialog.dismiss();
|
||||||
SmartDialog.showToast(err.toString());
|
SmartDialog.showToast(err.toString());
|
||||||
|
|||||||
@ -131,7 +131,8 @@ class SettingBoxKey {
|
|||||||
enableSearchWord = 'enableSearchWord',
|
enableSearchWord = 'enableSearchWord',
|
||||||
enableSystemProxy = 'enableSystemProxy',
|
enableSystemProxy = 'enableSystemProxy',
|
||||||
enableAi = 'enableAi',
|
enableAi = 'enableAi',
|
||||||
defaultHomePage = 'defaultHomePage';
|
defaultHomePage = 'defaultHomePage',
|
||||||
|
enableRelatedVideo = 'enableRelatedVideo';
|
||||||
|
|
||||||
/// 外观
|
/// 外观
|
||||||
static const String themeMode = 'themeMode',
|
static const String themeMode = 'themeMode',
|
||||||
@ -181,6 +182,8 @@ class VideoBoxKey {
|
|||||||
videoSpeed = 'videoSpeed',
|
videoSpeed = 'videoSpeed',
|
||||||
// 播放顺序
|
// 播放顺序
|
||||||
playRepeat = 'playRepeat',
|
playRepeat = 'playRepeat',
|
||||||
|
// 系统预设倍速
|
||||||
|
playSpeedSystem = 'playSpeedSystem',
|
||||||
// 默认倍速
|
// 默认倍速
|
||||||
playSpeedDefault = 'playSpeedDefault',
|
playSpeedDefault = 'playSpeedDefault',
|
||||||
// 默认长按倍速
|
// 默认长按倍速
|
||||||
|
|||||||
@ -14,6 +14,7 @@ class UrlUtils {
|
|||||||
dio.options.validateStatus = (status) {
|
dio.options.validateStatus = (status) {
|
||||||
return status == 200 || status == 301 || status == 302;
|
return status == 200 || status == 301 || status == 302;
|
||||||
};
|
};
|
||||||
|
try {
|
||||||
final response = await dio.get(url);
|
final response = await dio.get(url);
|
||||||
if (response.statusCode == 302) {
|
if (response.statusCode == 302) {
|
||||||
redirectUrl = response.headers['location']?.first as String;
|
redirectUrl = response.headers['location']?.first as String;
|
||||||
@ -27,6 +28,9 @@ class UrlUtils {
|
|||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
return redirectUrl;
|
return redirectUrl;
|
||||||
|
} catch (err) {
|
||||||
|
return url;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 匹配url路由跳转
|
// 匹配url路由跳转
|
||||||
|
|||||||
@ -50,6 +50,9 @@ class Utils {
|
|||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
if (time < 3600) {
|
if (time < 3600) {
|
||||||
|
if (time == 0) {
|
||||||
|
return time;
|
||||||
|
}
|
||||||
final int minute = time ~/ 60;
|
final int minute = time ~/ 60;
|
||||||
final double res = time / 60;
|
final double res = time / 60;
|
||||||
if (minute != res) {
|
if (minute != res) {
|
||||||
@ -87,6 +90,9 @@ class Utils {
|
|||||||
|
|
||||||
// 时间显示,刚刚,x分钟前
|
// 时间显示,刚刚,x分钟前
|
||||||
static String dateFormat(timeStamp, {formatType = 'list'}) {
|
static String dateFormat(timeStamp, {formatType = 'list'}) {
|
||||||
|
if (timeStamp == 0 || timeStamp == null || timeStamp == '') {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
// 当前时间
|
// 当前时间
|
||||||
int time = (DateTime.now().millisecondsSinceEpoch / 1000).round();
|
int time = (DateTime.now().millisecondsSinceEpoch / 1000).round();
|
||||||
// 对比
|
// 对比
|
||||||
@ -103,6 +109,7 @@ class Utils {
|
|||||||
toInt: false,
|
toInt: false,
|
||||||
formatType: formatType);
|
formatType: formatType);
|
||||||
}
|
}
|
||||||
|
print('distance: $distance');
|
||||||
if (distance <= 60) {
|
if (distance <= 60) {
|
||||||
return '刚刚';
|
return '刚刚';
|
||||||
} else if (distance <= 3600) {
|
} else if (distance <= 3600) {
|
||||||
@ -236,6 +243,10 @@ class Utils {
|
|||||||
SmartDialog.dismiss();
|
SmartDialog.dismiss();
|
||||||
var currentInfo = await PackageInfo.fromPlatform();
|
var currentInfo = await PackageInfo.fromPlatform();
|
||||||
var result = await Request().get(Api.latestApp, extra: {'ua': 'mob'});
|
var result = await Request().get(Api.latestApp, extra: {'ua': 'mob'});
|
||||||
|
if (result.data == null || result.data.isEmpty) {
|
||||||
|
SmartDialog.showToast('获取远程版本失败,请检查网络');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
LatestDataModel data = LatestDataModel.fromJson(result.data);
|
LatestDataModel data = LatestDataModel.fromJson(result.data);
|
||||||
bool isUpdate = Utils.needUpdate(currentInfo.version, data.tagName!);
|
bool isUpdate = Utils.needUpdate(currentInfo.version, data.tagName!);
|
||||||
if (isUpdate) {
|
if (isUpdate) {
|
||||||
@ -344,9 +355,8 @@ class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static List<int> generateRandomBytes(int minLength, int maxLength) {
|
static List<int> generateRandomBytes(int minLength, int maxLength) {
|
||||||
return List<int>.generate(
|
return List<int>.generate(random.nextInt(maxLength - minLength + 1),
|
||||||
random.nextInt(maxLength-minLength+1), (_) => random.nextInt(0x60) + 0x20
|
(_) => random.nextInt(0x60) + 0x20);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static String base64EncodeRandomString(int minLength, int maxLength) {
|
static String base64EncodeRandomString(int minLength, int maxLength) {
|
||||||
|
|||||||
@ -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
|
# 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
|
# 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.
|
# of the product and file versions while build-number is used as the build suffix.
|
||||||
version: 1.0.20+1020
|
version: 1.0.21+1021
|
||||||
|
|
||||||
environment:
|
environment:
|
||||||
sdk: ">=2.19.6 <3.0.0"
|
sdk: ">=2.19.6 <3.0.0"
|
||||||
|
|||||||
Reference in New Issue
Block a user