feat: 播放顺序、视频详情操作栏样式
This commit is contained in:
@ -9,6 +9,7 @@ import 'package:pilipala/models/bangumi/info.dart';
|
|||||||
import 'package:pilipala/models/user/fav_folder.dart';
|
import 'package:pilipala/models/user/fav_folder.dart';
|
||||||
import 'package:pilipala/pages/video/detail/index.dart';
|
import 'package:pilipala/pages/video/detail/index.dart';
|
||||||
import 'package:pilipala/pages/video/detail/reply/index.dart';
|
import 'package:pilipala/pages/video/detail/reply/index.dart';
|
||||||
|
import 'package:pilipala/plugin/pl_player/models/play_repeat.dart';
|
||||||
import 'package:pilipala/utils/feed_back.dart';
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
import 'package:pilipala/utils/id_utils.dart';
|
import 'package:pilipala/utils/id_utils.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
@ -21,7 +22,7 @@ class BangumiIntroController extends GetxController {
|
|||||||
? int.parse(Get.parameters['seasonId']!)
|
? int.parse(Get.parameters['seasonId']!)
|
||||||
: null;
|
: null;
|
||||||
var epId = Get.parameters['epId'] != null
|
var epId = Get.parameters['epId'] != null
|
||||||
? int.parse(Get.parameters['epId']!)
|
? int.tryParse(Get.parameters['epId']!)
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
// 是否预渲染 骨架屏
|
// 是否预渲染 骨架屏
|
||||||
@ -257,7 +258,7 @@ class BangumiIntroController extends GetxController {
|
|||||||
VideoDetailController videoDetailCtr =
|
VideoDetailController videoDetailCtr =
|
||||||
Get.find<VideoDetailController>(tag: Get.arguments['heroTag']);
|
Get.find<VideoDetailController>(tag: Get.arguments['heroTag']);
|
||||||
videoDetailCtr.bvid = bvid;
|
videoDetailCtr.bvid = bvid;
|
||||||
videoDetailCtr.cid = cid;
|
videoDetailCtr.cid.value = cid;
|
||||||
videoDetailCtr.danmakuCid.value = cid;
|
videoDetailCtr.danmakuCid.value = cid;
|
||||||
videoDetailCtr.queryVideoUrl();
|
videoDetailCtr.queryVideoUrl();
|
||||||
// 重新请求评论
|
// 重新请求评论
|
||||||
@ -292,4 +293,31 @@ class BangumiIntroController extends GetxController {
|
|||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 列表循环或者顺序播放时,自动播放下一个
|
||||||
|
void nextPlay() {
|
||||||
|
late List episodes;
|
||||||
|
if (bangumiDetail.value.episodes != null) {
|
||||||
|
episodes = bangumiDetail.value.episodes!;
|
||||||
|
}
|
||||||
|
VideoDetailController videoDetailCtr =
|
||||||
|
Get.find<VideoDetailController>(tag: Get.arguments['heroTag']);
|
||||||
|
int currentIndex =
|
||||||
|
episodes.indexWhere((e) => e.cid == videoDetailCtr.cid.value);
|
||||||
|
int nextIndex = currentIndex + 1;
|
||||||
|
PlayRepeat platRepeat = videoDetailCtr.plPlayerController.playRepeat;
|
||||||
|
// 列表循环
|
||||||
|
if (platRepeat == PlayRepeat.listCycle) {
|
||||||
|
if (nextIndex == episodes.length - 1) {
|
||||||
|
nextIndex = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (nextIndex <= episodes.length - 1 &&
|
||||||
|
platRepeat == PlayRepeat.listOrder) {}
|
||||||
|
|
||||||
|
int cid = episodes[nextIndex].cid!;
|
||||||
|
String bvid = episodes[nextIndex].bvid!;
|
||||||
|
int aid = episodes[nextIndex].aid!;
|
||||||
|
changeSeasonOrbangu(bvid, cid, aid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,10 +34,12 @@ class BangumiIntroPanel extends StatefulWidget {
|
|||||||
|
|
||||||
class _BangumiIntroPanelState extends State<BangumiIntroPanel>
|
class _BangumiIntroPanelState extends State<BangumiIntroPanel>
|
||||||
with AutomaticKeepAliveClientMixin {
|
with AutomaticKeepAliveClientMixin {
|
||||||
final BangumiIntroController bangumiIntroController =
|
late BangumiIntroController bangumiIntroController;
|
||||||
Get.put(BangumiIntroController(), tag: Get.arguments['heroTag']);
|
late VideoDetailController videoDetailCtr;
|
||||||
BangumiInfoModel? bangumiDetail;
|
BangumiInfoModel? bangumiDetail;
|
||||||
late Future _futureBuilderFuture;
|
late Future _futureBuilderFuture;
|
||||||
|
late int cid;
|
||||||
|
late String heroTag;
|
||||||
|
|
||||||
// 添加页面缓存
|
// 添加页面缓存
|
||||||
@override
|
@override
|
||||||
@ -46,10 +48,19 @@ class _BangumiIntroPanelState extends State<BangumiIntroPanel>
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
heroTag = Get.arguments['heroTag'];
|
||||||
|
cid = widget.cid!;
|
||||||
|
bangumiIntroController = Get.put(BangumiIntroController(), tag: heroTag);
|
||||||
|
videoDetailCtr = Get.find<VideoDetailController>(tag: heroTag);
|
||||||
bangumiIntroController.bangumiDetail.listen((value) {
|
bangumiIntroController.bangumiDetail.listen((value) {
|
||||||
bangumiDetail = value;
|
bangumiDetail = value;
|
||||||
});
|
});
|
||||||
_futureBuilderFuture = bangumiIntroController.queryBangumiIntro();
|
_futureBuilderFuture = bangumiIntroController.queryBangumiIntro();
|
||||||
|
videoDetailCtr.cid.listen((p0) {
|
||||||
|
print('🐶🐶$p0');
|
||||||
|
cid = p0;
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -61,9 +72,11 @@ class _BangumiIntroPanelState extends State<BangumiIntroPanel>
|
|||||||
if (snapshot.connectionState == ConnectionState.done) {
|
if (snapshot.connectionState == ConnectionState.done) {
|
||||||
if (snapshot.data['status']) {
|
if (snapshot.data['status']) {
|
||||||
// 请求成功
|
// 请求成功
|
||||||
|
|
||||||
return BangumiInfo(
|
return BangumiInfo(
|
||||||
loadingStatus: false,
|
loadingStatus: false,
|
||||||
bangumiDetail: bangumiDetail,
|
bangumiDetail: bangumiDetail,
|
||||||
|
cid: cid,
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
// 请求错误
|
// 请求错误
|
||||||
@ -77,7 +90,7 @@ class _BangumiIntroPanelState extends State<BangumiIntroPanel>
|
|||||||
return BangumiInfo(
|
return BangumiInfo(
|
||||||
loadingStatus: true,
|
loadingStatus: true,
|
||||||
bangumiDetail: bangumiDetail,
|
bangumiDetail: bangumiDetail,
|
||||||
cid: widget.cid,
|
cid: cid,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -118,6 +131,12 @@ class _BangumiInfoState extends State<BangumiInfo> {
|
|||||||
bangumiItem = bangumiIntroController.bangumiItem;
|
bangumiItem = bangumiIntroController.bangumiItem;
|
||||||
sheetHeight = localCache.get('sheetHeight');
|
sheetHeight = localCache.get('sheetHeight');
|
||||||
cid = widget.cid!;
|
cid = widget.cid!;
|
||||||
|
print('cid: $cid');
|
||||||
|
videoDetailCtr.cid.listen((p0) {
|
||||||
|
cid = p0;
|
||||||
|
print('cid: $cid');
|
||||||
|
setState(() {});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// 收藏
|
// 收藏
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
|
import 'package:get/get.dart';
|
||||||
import 'package:hive/hive.dart';
|
import 'package:hive/hive.dart';
|
||||||
import 'package:pilipala/models/bangumi/info.dart';
|
import 'package:pilipala/models/bangumi/info.dart';
|
||||||
|
import 'package:pilipala/pages/video/detail/index.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
|
|
||||||
class BangumiPanel extends StatefulWidget {
|
class BangumiPanel extends StatefulWidget {
|
||||||
@ -30,16 +32,28 @@ class _BangumiPanelState extends State<BangumiPanel> {
|
|||||||
dynamic userInfo;
|
dynamic userInfo;
|
||||||
// 默认未开通
|
// 默认未开通
|
||||||
int vipStatus = 0;
|
int vipStatus = 0;
|
||||||
|
late int cid;
|
||||||
|
String heroTag = Get.arguments['heroTag'];
|
||||||
|
late final VideoDetailController videoDetailCtr;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
currentIndex = widget.pages.indexWhere((e) => e.cid == widget.cid!);
|
cid = widget.cid!;
|
||||||
|
currentIndex = widget.pages.indexWhere((e) => e.cid == cid);
|
||||||
scrollToIndex();
|
scrollToIndex();
|
||||||
userInfo = userInfoCache.get('userInfoCache');
|
userInfo = userInfoCache.get('userInfoCache');
|
||||||
if (userInfo != null) {
|
if (userInfo != null) {
|
||||||
vipStatus = userInfo.vipStatus;
|
vipStatus = userInfo.vipStatus;
|
||||||
}
|
}
|
||||||
|
videoDetailCtr = Get.find<VideoDetailController>(tag: heroTag);
|
||||||
|
|
||||||
|
videoDetailCtr.cid.listen((p0) {
|
||||||
|
cid = p0;
|
||||||
|
setState(() {});
|
||||||
|
currentIndex = widget.pages.indexWhere((e) => e.cid == cid);
|
||||||
|
scrollToIndex();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
|||||||
@ -24,7 +24,7 @@ class VideoDetailController extends GetxController
|
|||||||
with GetSingleTickerProviderStateMixin {
|
with GetSingleTickerProviderStateMixin {
|
||||||
/// 路由传参
|
/// 路由传参
|
||||||
String bvid = Get.parameters['bvid']!;
|
String bvid = Get.parameters['bvid']!;
|
||||||
int cid = int.parse(Get.parameters['cid']!);
|
RxInt cid = int.parse(Get.parameters['cid']!).obs;
|
||||||
RxInt danmakuCid = 0.obs;
|
RxInt danmakuCid = 0.obs;
|
||||||
String heroTag = Get.arguments['heroTag'];
|
String heroTag = Get.arguments['heroTag'];
|
||||||
// 视频详情
|
// 视频详情
|
||||||
@ -109,7 +109,7 @@ class VideoDetailController extends GetxController
|
|||||||
localCache.get(LocalCacheKey.historyPause) == true) {
|
localCache.get(LocalCacheKey.historyPause) == true) {
|
||||||
enableHeart = false;
|
enableHeart = false;
|
||||||
}
|
}
|
||||||
danmakuCid.value = cid;
|
danmakuCid.value = cid.value;
|
||||||
|
|
||||||
///
|
///
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
@ -218,7 +218,7 @@ class VideoDetailController extends GetxController
|
|||||||
// 默认1倍速
|
// 默认1倍速
|
||||||
speed: 1.0,
|
speed: 1.0,
|
||||||
bvid: bvid,
|
bvid: bvid,
|
||||||
cid: cid,
|
cid: cid.value,
|
||||||
enableHeart: enableHeart,
|
enableHeart: enableHeart,
|
||||||
isFirstTime: isFirstTime,
|
isFirstTime: isFirstTime,
|
||||||
autoplay: autoplay,
|
autoplay: autoplay,
|
||||||
@ -230,7 +230,7 @@ class VideoDetailController extends GetxController
|
|||||||
|
|
||||||
// 视频链接
|
// 视频链接
|
||||||
Future queryVideoUrl() async {
|
Future queryVideoUrl() async {
|
||||||
var result = await VideoHttp.videoUrl(cid: cid, bvid: bvid);
|
var result = await VideoHttp.videoUrl(cid: cid.value, bvid: bvid);
|
||||||
if (result['status']) {
|
if (result['status']) {
|
||||||
data = result['data'];
|
data = result['data'];
|
||||||
|
|
||||||
|
|||||||
@ -11,6 +11,7 @@ import 'package:pilipala/models/user/fav_folder.dart';
|
|||||||
import 'package:pilipala/models/video_detail_res.dart';
|
import 'package:pilipala/models/video_detail_res.dart';
|
||||||
import 'package:pilipala/pages/video/detail/controller.dart';
|
import 'package:pilipala/pages/video/detail/controller.dart';
|
||||||
import 'package:pilipala/pages/video/detail/reply/index.dart';
|
import 'package:pilipala/pages/video/detail/reply/index.dart';
|
||||||
|
import 'package:pilipala/plugin/pl_player/models/play_repeat.dart';
|
||||||
import 'package:pilipala/utils/feed_back.dart';
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
import 'package:pilipala/utils/id_utils.dart';
|
import 'package:pilipala/utils/id_utils.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
@ -58,6 +59,7 @@ class VideoIntroController extends GetxController {
|
|||||||
RxString total = '1'.obs;
|
RxString total = '1'.obs;
|
||||||
Timer? timer;
|
Timer? timer;
|
||||||
bool isPaused = false;
|
bool isPaused = false;
|
||||||
|
String heroTag = Get.arguments['heroTag'];
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onInit() {
|
void onInit() {
|
||||||
@ -102,9 +104,10 @@ class VideoIntroController extends GetxController {
|
|||||||
if (videoDetail.value.pages!.isNotEmpty && lastPlayCid.value == 0) {
|
if (videoDetail.value.pages!.isNotEmpty && lastPlayCid.value == 0) {
|
||||||
lastPlayCid.value = videoDetail.value.pages!.first.cid!;
|
lastPlayCid.value = videoDetail.value.pages!.first.cid!;
|
||||||
}
|
}
|
||||||
Get.find<VideoDetailController>(tag: Get.arguments['heroTag'])
|
// Get.find<VideoDetailController>(tag: heroTag).tabs.value = [
|
||||||
.tabs
|
// '简介',
|
||||||
.value = ['简介', '评论 ${result['data']!.stat!.reply}'];
|
// '评论 ${result['data']!.stat!.reply}'
|
||||||
|
// ];
|
||||||
// 获取到粉丝数再返回
|
// 获取到粉丝数再返回
|
||||||
await queryUserStat();
|
await queryUserStat();
|
||||||
}
|
}
|
||||||
@ -440,16 +443,16 @@ class VideoIntroController extends GetxController {
|
|||||||
Future changeSeasonOrbangu(bvid, cid, aid) async {
|
Future changeSeasonOrbangu(bvid, cid, aid) async {
|
||||||
// 重新获取视频资源
|
// 重新获取视频资源
|
||||||
VideoDetailController videoDetailCtr =
|
VideoDetailController videoDetailCtr =
|
||||||
Get.find<VideoDetailController>(tag: Get.arguments['heroTag']);
|
Get.find<VideoDetailController>(tag: heroTag);
|
||||||
videoDetailCtr.bvid = bvid;
|
videoDetailCtr.bvid = bvid;
|
||||||
videoDetailCtr.cid = cid;
|
videoDetailCtr.cid.value = cid;
|
||||||
videoDetailCtr.danmakuCid.value = cid;
|
videoDetailCtr.danmakuCid.value = cid;
|
||||||
videoDetailCtr.queryVideoUrl();
|
videoDetailCtr.queryVideoUrl();
|
||||||
// 重新请求评论
|
// 重新请求评论
|
||||||
try {
|
try {
|
||||||
/// 未渲染回复组件时可能异常
|
/// 未渲染回复组件时可能异常
|
||||||
VideoReplyController videoReplyCtr =
|
VideoReplyController videoReplyCtr =
|
||||||
Get.find<VideoReplyController>(tag: Get.arguments['heroTag']);
|
Get.find<VideoReplyController>(tag: heroTag);
|
||||||
videoReplyCtr.aid = aid;
|
videoReplyCtr.aid = aid;
|
||||||
videoReplyCtr.queryReplyList(type: 'init');
|
videoReplyCtr.queryReplyList(type: 'init');
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
@ -486,4 +489,52 @@ class VideoIntroController extends GetxController {
|
|||||||
}
|
}
|
||||||
super.onClose();
|
super.onClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 列表循环或者顺序播放时,自动播放下一个
|
||||||
|
void nextPlay() {
|
||||||
|
late List episodes;
|
||||||
|
// if (videoDetail.value.ugcSeason != null) {
|
||||||
|
// UgcSeason ugcSeason = videoDetail.value.ugcSeason!;
|
||||||
|
// List<SectionItem> sections = ugcSeason.sections!;
|
||||||
|
// for (int i = 0; i < sections.length; i++) {
|
||||||
|
// List<EpisodeItem> episodesList = sections[i].episodes!;
|
||||||
|
// for (int j = 0; j < episodesList.length; j++) {
|
||||||
|
// if (episodesList[j].cid == lastPlayCid.value) {
|
||||||
|
// episodes = episodesList;
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
if (videoDetail.value.ugcSeason != null) {
|
||||||
|
UgcSeason ugcSeason = videoDetail.value.ugcSeason!;
|
||||||
|
List<SectionItem> sections = ugcSeason.sections!;
|
||||||
|
episodes = [];
|
||||||
|
|
||||||
|
for (int i = 0; i < sections.length; i++) {
|
||||||
|
List<EpisodeItem> episodesList = sections[i].episodes!;
|
||||||
|
episodes.addAll(episodesList);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int currentIndex = episodes.indexWhere((e) => e.cid == lastPlayCid.value);
|
||||||
|
int nextIndex = currentIndex + 1;
|
||||||
|
VideoDetailController videoDetailCtr =
|
||||||
|
Get.find<VideoDetailController>(tag: heroTag);
|
||||||
|
PlayRepeat platRepeat = videoDetailCtr.plPlayerController.playRepeat;
|
||||||
|
|
||||||
|
// 列表循环
|
||||||
|
if (nextIndex >= episodes.length) {
|
||||||
|
if (platRepeat == PlayRepeat.listCycle) {
|
||||||
|
nextIndex = 0;
|
||||||
|
}
|
||||||
|
if (platRepeat == PlayRepeat.listOrder) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int cid = episodes[nextIndex].cid!;
|
||||||
|
String bvid = episodes[nextIndex].bvid!;
|
||||||
|
int aid = episodes[nextIndex].aid!;
|
||||||
|
changeSeasonOrbangu(bvid, cid, aid);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -330,17 +330,17 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
|||||||
),
|
),
|
||||||
const SizedBox(height: 7),
|
const SizedBox(height: 7),
|
||||||
// 点赞收藏转发 布局样式1
|
// 点赞收藏转发 布局样式1
|
||||||
SingleChildScrollView(
|
// SingleChildScrollView(
|
||||||
padding: const EdgeInsets.only(top: 7, bottom: 7),
|
// padding: const EdgeInsets.only(top: 7, bottom: 7),
|
||||||
scrollDirection: Axis.horizontal,
|
// scrollDirection: Axis.horizontal,
|
||||||
child: actionRow(
|
// child: actionRow(
|
||||||
context,
|
// context,
|
||||||
videoIntroController,
|
// videoIntroController,
|
||||||
videoDetailCtr,
|
// videoDetailCtr,
|
||||||
),
|
// ),
|
||||||
),
|
// ),
|
||||||
// 点赞收藏转发 布局样式2
|
// 点赞收藏转发 布局样式2
|
||||||
// actionGrid(context, videoIntroController),
|
actionGrid(context, videoIntroController),
|
||||||
// 合集
|
// 合集
|
||||||
if (!loadingStatus &&
|
if (!loadingStatus &&
|
||||||
widget.videoDetail!.ugcSeason != null) ...[
|
widget.videoDetail!.ugcSeason != null) ...[
|
||||||
@ -458,7 +458,7 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
|||||||
Widget actionGrid(BuildContext context, videoIntroController) {
|
Widget actionGrid(BuildContext context, videoIntroController) {
|
||||||
return LayoutBuilder(builder: (context, constraints) {
|
return LayoutBuilder(builder: (context, constraints) {
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.only(top: 6, bottom: 10),
|
margin: const EdgeInsets.only(top: 6, bottom: 4),
|
||||||
height: constraints.maxWidth / 5 * 0.8,
|
height: constraints.maxWidth / 5 * 0.8,
|
||||||
child: GridView.count(
|
child: GridView.count(
|
||||||
primary: false,
|
primary: false,
|
||||||
@ -477,12 +477,12 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
|||||||
? widget.videoDetail!.stat!.like!.toString()
|
? widget.videoDetail!.stat!.like!.toString()
|
||||||
: '-'),
|
: '-'),
|
||||||
),
|
),
|
||||||
ActionItem(
|
// ActionItem(
|
||||||
icon: const Icon(FontAwesomeIcons.clock),
|
// icon: const Icon(FontAwesomeIcons.clock),
|
||||||
onTap: () => videoIntroController.actionShareVideo(),
|
// onTap: () => videoIntroController.actionShareVideo(),
|
||||||
selectStatus: false,
|
// selectStatus: false,
|
||||||
loadingStatus: loadingStatus,
|
// loadingStatus: loadingStatus,
|
||||||
text: '稍后再看'),
|
// text: '稍后再看'),
|
||||||
Obx(
|
Obx(
|
||||||
() => ActionItem(
|
() => ActionItem(
|
||||||
icon: const Icon(FontAwesomeIcons.b),
|
icon: const Icon(FontAwesomeIcons.b),
|
||||||
@ -498,22 +498,28 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
|
|||||||
() => ActionItem(
|
() => ActionItem(
|
||||||
icon: const Icon(FontAwesomeIcons.star),
|
icon: const Icon(FontAwesomeIcons.star),
|
||||||
selectIcon: const Icon(FontAwesomeIcons.solidStar),
|
selectIcon: const Icon(FontAwesomeIcons.solidStar),
|
||||||
// onTap: () => videoIntroController.actionFavVideo(),
|
|
||||||
onTap: () => showFavBottomSheet(),
|
onTap: () => showFavBottomSheet(),
|
||||||
|
onLongPress: () => showFavBottomSheet(type: 'longPress'),
|
||||||
selectStatus: videoIntroController.hasFav.value,
|
selectStatus: videoIntroController.hasFav.value,
|
||||||
loadingStatus: loadingStatus,
|
loadingStatus: loadingStatus,
|
||||||
text: !loadingStatus
|
text: !loadingStatus
|
||||||
? widget.videoDetail!.stat!.favorite!.toString()
|
? widget.videoDetail!.stat!.favorite!.toString()
|
||||||
: '-'),
|
: '-'),
|
||||||
),
|
),
|
||||||
|
ActionItem(
|
||||||
|
icon: const Icon(FontAwesomeIcons.comment),
|
||||||
|
onTap: () => videoDetailCtr.tabCtr.animateTo(1),
|
||||||
|
selectStatus: false,
|
||||||
|
loadingStatus: loadingStatus,
|
||||||
|
text: !loadingStatus
|
||||||
|
? widget.videoDetail!.stat!.reply!.toString()
|
||||||
|
: '评论'),
|
||||||
ActionItem(
|
ActionItem(
|
||||||
icon: const Icon(FontAwesomeIcons.shareFromSquare),
|
icon: const Icon(FontAwesomeIcons.shareFromSquare),
|
||||||
onTap: () => videoIntroController.actionShareVideo(),
|
onTap: () => videoIntroController.actionShareVideo(),
|
||||||
selectStatus: false,
|
selectStatus: false,
|
||||||
loadingStatus: loadingStatus,
|
loadingStatus: loadingStatus,
|
||||||
text: !loadingStatus
|
text: '分享'),
|
||||||
? widget.videoDetail!.stat!.share!.toString()
|
|
||||||
: '-'),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|||||||
@ -6,6 +6,7 @@ class ActionItem extends StatelessWidget {
|
|||||||
final Icon? icon;
|
final Icon? icon;
|
||||||
final Icon? selectIcon;
|
final Icon? selectIcon;
|
||||||
final Function? onTap;
|
final Function? onTap;
|
||||||
|
final Function? onLongPress;
|
||||||
final bool? loadingStatus;
|
final bool? loadingStatus;
|
||||||
final String? text;
|
final String? text;
|
||||||
final bool selectStatus;
|
final bool selectStatus;
|
||||||
@ -15,6 +16,7 @@ class ActionItem extends StatelessWidget {
|
|||||||
this.icon,
|
this.icon,
|
||||||
this.selectIcon,
|
this.selectIcon,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
|
this.onLongPress,
|
||||||
this.loadingStatus,
|
this.loadingStatus,
|
||||||
this.text,
|
this.text,
|
||||||
this.selectStatus = false,
|
this.selectStatus = false,
|
||||||
@ -27,6 +29,9 @@ class ActionItem extends StatelessWidget {
|
|||||||
feedBack(),
|
feedBack(),
|
||||||
onTap!(),
|
onTap!(),
|
||||||
},
|
},
|
||||||
|
onLongPress: () => {
|
||||||
|
if (onLongPress != null) {onLongPress!()}
|
||||||
|
},
|
||||||
borderRadius: StyleString.mdRadius,
|
borderRadius: StyleString.mdRadius,
|
||||||
child: Column(
|
child: Column(
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/models/video_detail_res.dart';
|
import 'package:pilipala/models/video_detail_res.dart';
|
||||||
|
import 'package:pilipala/pages/video/detail/index.dart';
|
||||||
|
|
||||||
class PagesPanel extends StatefulWidget {
|
class PagesPanel extends StatefulWidget {
|
||||||
final List<Part> pages;
|
final List<Part> pages;
|
||||||
@ -22,13 +23,23 @@ class PagesPanel extends StatefulWidget {
|
|||||||
|
|
||||||
class _PagesPanelState extends State<PagesPanel> {
|
class _PagesPanelState extends State<PagesPanel> {
|
||||||
late List<Part> episodes;
|
late List<Part> episodes;
|
||||||
|
late int cid;
|
||||||
late int currentIndex;
|
late int currentIndex;
|
||||||
|
String heroTag = Get.arguments['heroTag'];
|
||||||
|
late VideoDetailController _videoDetailController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
cid = widget.cid!;
|
||||||
episodes = widget.pages;
|
episodes = widget.pages;
|
||||||
currentIndex = episodes.indexWhere((e) => e.cid == widget.cid);
|
_videoDetailController = Get.find<VideoDetailController>(tag: heroTag);
|
||||||
|
currentIndex = episodes.indexWhere((e) => e.cid == cid);
|
||||||
|
_videoDetailController.cid.listen((p0) {
|
||||||
|
cid = p0;
|
||||||
|
setState(() {});
|
||||||
|
currentIndex = episodes.indexWhere((e) => e.cid == cid);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void changeFucCall(item, i) async {
|
void changeFucCall(item, i) async {
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart';
|
import 'package:get/get.dart';
|
||||||
import 'package:pilipala/models/video_detail_res.dart';
|
import 'package:pilipala/models/video_detail_res.dart';
|
||||||
|
import 'package:pilipala/pages/video/detail/index.dart';
|
||||||
import 'package:pilipala/utils/id_utils.dart';
|
import 'package:pilipala/utils/id_utils.dart';
|
||||||
|
|
||||||
class SeasonPanel extends StatefulWidget {
|
class SeasonPanel extends StatefulWidget {
|
||||||
@ -23,11 +24,16 @@ class SeasonPanel extends StatefulWidget {
|
|||||||
|
|
||||||
class _SeasonPanelState extends State<SeasonPanel> {
|
class _SeasonPanelState extends State<SeasonPanel> {
|
||||||
late List<EpisodeItem> episodes;
|
late List<EpisodeItem> episodes;
|
||||||
|
late int cid;
|
||||||
late int currentIndex;
|
late int currentIndex;
|
||||||
|
String heroTag = Get.arguments['heroTag'];
|
||||||
|
late VideoDetailController _videoDetailController;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
cid = widget.cid!;
|
||||||
|
_videoDetailController = Get.find<VideoDetailController>(tag: heroTag);
|
||||||
|
|
||||||
/// 根据 cid 找到对应集,找到对应 episodes
|
/// 根据 cid 找到对应集,找到对应 episodes
|
||||||
/// 有多个episodes时,只显示其中一个
|
/// 有多个episodes时,只显示其中一个
|
||||||
@ -36,7 +42,7 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
|||||||
for (int i = 0; i < sections.length; i++) {
|
for (int i = 0; i < sections.length; i++) {
|
||||||
List<EpisodeItem> episodesList = sections[i].episodes!;
|
List<EpisodeItem> episodesList = sections[i].episodes!;
|
||||||
for (int j = 0; j < episodesList.length; j++) {
|
for (int j = 0; j < episodesList.length; j++) {
|
||||||
if (episodesList[j].cid == widget.cid) {
|
if (episodesList[j].cid == cid) {
|
||||||
episodes = episodesList;
|
episodes = episodesList;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -47,7 +53,12 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
|||||||
// episodes = widget.ugcSeason.sections!
|
// episodes = widget.ugcSeason.sections!
|
||||||
// .firstWhere((e) => e.seasonId == widget.ugcSeason.id)
|
// .firstWhere((e) => e.seasonId == widget.ugcSeason.id)
|
||||||
// .episodes!;
|
// .episodes!;
|
||||||
currentIndex = episodes.indexWhere((e) => e.cid == widget.cid);
|
currentIndex = episodes.indexWhere((e) => e.cid == cid);
|
||||||
|
_videoDetailController.cid.listen((p0) {
|
||||||
|
cid = p0;
|
||||||
|
setState(() {});
|
||||||
|
currentIndex = episodes.indexWhere((e) => e.cid == cid);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void changeFucCall(item, i) async {
|
void changeFucCall(item, i) async {
|
||||||
@ -57,6 +68,7 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
|||||||
item.aid,
|
item.aid,
|
||||||
);
|
);
|
||||||
currentIndex = i;
|
currentIndex = i;
|
||||||
|
setState(() {});
|
||||||
Get.back();
|
Get.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,7 @@ import 'package:pilipala/pages/video/detail/controller.dart';
|
|||||||
import 'package:pilipala/pages/video/detail/introduction/index.dart';
|
import 'package:pilipala/pages/video/detail/introduction/index.dart';
|
||||||
import 'package:pilipala/pages/video/detail/related/index.dart';
|
import 'package:pilipala/pages/video/detail/related/index.dart';
|
||||||
import 'package:pilipala/plugin/pl_player/index.dart';
|
import 'package:pilipala/plugin/pl_player/index.dart';
|
||||||
|
import 'package:pilipala/plugin/pl_player/models/play_repeat.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
|
|
||||||
import 'widgets/app_bar.dart';
|
import 'widgets/app_bar.dart';
|
||||||
@ -41,6 +42,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
final ScrollController _extendNestCtr = ScrollController();
|
final ScrollController _extendNestCtr = ScrollController();
|
||||||
late StreamController<double> appbarStream;
|
late StreamController<double> appbarStream;
|
||||||
late VideoIntroController videoIntroController;
|
late VideoIntroController videoIntroController;
|
||||||
|
late BangumiIntroController bangumiIntroController;
|
||||||
late String heroTag;
|
late String heroTag;
|
||||||
|
|
||||||
PlayerStatus playerStatus = PlayerStatus.playing;
|
PlayerStatus playerStatus = PlayerStatus.playing;
|
||||||
@ -61,6 +63,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
heroTag = Get.arguments['heroTag'];
|
heroTag = Get.arguments['heroTag'];
|
||||||
videoDetailController = Get.put(VideoDetailController(), tag: heroTag);
|
videoDetailController = Get.put(VideoDetailController(), tag: heroTag);
|
||||||
videoIntroController = Get.put(VideoIntroController(), tag: heroTag);
|
videoIntroController = Get.put(VideoIntroController(), tag: heroTag);
|
||||||
|
bangumiIntroController = Get.put(BangumiIntroController(), tag: heroTag);
|
||||||
statusBarHeight = localCache.get('statusBarHeight');
|
statusBarHeight = localCache.get('statusBarHeight');
|
||||||
autoExitFullcreen =
|
autoExitFullcreen =
|
||||||
setting.get(SettingBoxKey.enableAutoExit, defaultValue: false);
|
setting.get(SettingBoxKey.enableAutoExit, defaultValue: false);
|
||||||
@ -98,6 +101,23 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
if (autoExitFullcreen) {
|
if (autoExitFullcreen) {
|
||||||
plPlayerController!.triggerFullScreen(status: false);
|
plPlayerController!.triggerFullScreen(status: false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 顺序播放 列表循环
|
||||||
|
if (plPlayerController!.playRepeat != PlayRepeat.pause &&
|
||||||
|
plPlayerController!.playRepeat != PlayRepeat.singleCycle) {
|
||||||
|
if (videoDetailController.videoType == SearchType.video) {
|
||||||
|
videoIntroController.nextPlay();
|
||||||
|
}
|
||||||
|
if (videoDetailController.videoType == SearchType.media_bangumi) {
|
||||||
|
bangumiIntroController.nextPlay();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 单个循环
|
||||||
|
if (plPlayerController!.playRepeat == PlayRepeat.singleCycle) {
|
||||||
|
plPlayerController!.seekTo(Duration.zero);
|
||||||
|
plPlayerController!.play();
|
||||||
|
}
|
||||||
// 播放完展示控制栏
|
// 播放完展示控制栏
|
||||||
try {
|
try {
|
||||||
PiPStatus currentStatus =
|
PiPStatus currentStatus =
|
||||||
@ -385,8 +405,8 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
const VideoIntroPanel(),
|
const VideoIntroPanel(),
|
||||||
] else if (videoDetailController.videoType ==
|
] else if (videoDetailController.videoType ==
|
||||||
SearchType.media_bangumi) ...[
|
SearchType.media_bangumi) ...[
|
||||||
BangumiIntroPanel(
|
Obx(() => BangumiIntroPanel(
|
||||||
cid: videoDetailController.cid)
|
cid: videoDetailController.cid.value)),
|
||||||
],
|
],
|
||||||
// if (videoDetailController.videoType ==
|
// if (videoDetailController.videoType ==
|
||||||
// SearchType.video) ...[
|
// SearchType.video) ...[
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import 'package:pilipala/models/video/play/url.dart';
|
|||||||
import 'package:pilipala/pages/video/detail/index.dart';
|
import 'package:pilipala/pages/video/detail/index.dart';
|
||||||
import 'package:pilipala/pages/video/detail/introduction/widgets/menu_row.dart';
|
import 'package:pilipala/pages/video/detail/introduction/widgets/menu_row.dart';
|
||||||
import 'package:pilipala/plugin/pl_player/index.dart';
|
import 'package:pilipala/plugin/pl_player/index.dart';
|
||||||
|
import 'package:pilipala/plugin/pl_player/models/play_repeat.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
|
|
||||||
class HeaderControl extends StatefulWidget implements PreferredSizeWidget {
|
class HeaderControl extends StatefulWidget implements PreferredSizeWidget {
|
||||||
@ -56,7 +57,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
builder: (_) {
|
builder: (_) {
|
||||||
return Container(
|
return Container(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
height: 400,
|
height: 440,
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: Theme.of(context).colorScheme.background,
|
color: Theme.of(context).colorScheme.background,
|
||||||
@ -149,13 +150,14 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
'当前解码格式 ${widget.videoDetailCtr!.currentDecodeFormats.description}',
|
'当前解码格式 ${widget.videoDetailCtr!.currentDecodeFormats.description}',
|
||||||
style: subTitleStyle),
|
style: subTitleStyle),
|
||||||
),
|
),
|
||||||
// ListTile(
|
ListTile(
|
||||||
// onTap: () {},
|
onTap: () => {Get.back(), showSetRepeat()},
|
||||||
// dense: true,
|
dense: true,
|
||||||
// enabled: false,
|
leading: const Icon(Icons.repeat, size: 20),
|
||||||
// leading: const Icon(Icons.play_circle_outline, size: 20),
|
title: Text('播放顺序', style: titleStyle),
|
||||||
// title: Text('播放设置', style: titleStyle),
|
subtitle: Text(widget.controller!.playRepeat.description,
|
||||||
// ),
|
style: subTitleStyle),
|
||||||
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
onTap: () => {Get.back(), showSetDanmaku()},
|
onTap: () => {Get.back(), showSetDanmaku()},
|
||||||
dense: true,
|
dense: true,
|
||||||
@ -704,6 +706,60 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 播放顺序
|
||||||
|
void showSetRepeat() async {
|
||||||
|
showModalBottomSheet(
|
||||||
|
context: context,
|
||||||
|
elevation: 0,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
builder: (BuildContext context) {
|
||||||
|
return Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: 250,
|
||||||
|
clipBehavior: Clip.hardEdge,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: Theme.of(context).colorScheme.background,
|
||||||
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||||
|
),
|
||||||
|
margin: const EdgeInsets.all(12),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
SizedBox(
|
||||||
|
height: 45,
|
||||||
|
child: Center(child: Text('选择播放顺序', style: titleStyle))),
|
||||||
|
Expanded(
|
||||||
|
child: Material(
|
||||||
|
child: ListView(
|
||||||
|
children: [
|
||||||
|
for (var i in PlayRepeat.values) ...[
|
||||||
|
ListTile(
|
||||||
|
onTap: () {
|
||||||
|
widget.controller!.setPlayRepeat(i);
|
||||||
|
Get.back();
|
||||||
|
},
|
||||||
|
dense: true,
|
||||||
|
contentPadding:
|
||||||
|
const EdgeInsets.only(left: 20, right: 20),
|
||||||
|
title: Text(i.description),
|
||||||
|
trailing: widget.controller!.playRepeat == i
|
||||||
|
? Icon(
|
||||||
|
Icons.done,
|
||||||
|
color: Theme.of(context).colorScheme.primary,
|
||||||
|
)
|
||||||
|
: const SizedBox(),
|
||||||
|
)
|
||||||
|
],
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final _ = widget.controller!;
|
final _ = widget.controller!;
|
||||||
|
|||||||
@ -13,6 +13,7 @@ import 'package:media_kit_video/media_kit_video.dart';
|
|||||||
import 'package:ns_danmaku/ns_danmaku.dart';
|
import 'package:ns_danmaku/ns_danmaku.dart';
|
||||||
import 'package:pilipala/http/video.dart';
|
import 'package:pilipala/http/video.dart';
|
||||||
import 'package:pilipala/plugin/pl_player/index.dart';
|
import 'package:pilipala/plugin/pl_player/index.dart';
|
||||||
|
import 'package:pilipala/plugin/pl_player/models/play_repeat.dart';
|
||||||
import 'package:pilipala/utils/feed_back.dart';
|
import 'package:pilipala/utils/feed_back.dart';
|
||||||
import 'package:pilipala/utils/storage.dart';
|
import 'package:pilipala/utils/storage.dart';
|
||||||
import 'package:screen_brightness/screen_brightness.dart';
|
import 'package:screen_brightness/screen_brightness.dart';
|
||||||
@ -209,6 +210,9 @@ class PlPlayerController {
|
|||||||
late double fontSizeVal;
|
late double fontSizeVal;
|
||||||
late double danmakuSpeedVal;
|
late double danmakuSpeedVal;
|
||||||
|
|
||||||
|
// 播放顺序相关
|
||||||
|
PlayRepeat playRepeat = PlayRepeat.pause;
|
||||||
|
|
||||||
// 添加一个私有构造函数
|
// 添加一个私有构造函数
|
||||||
PlPlayerController._() {
|
PlPlayerController._() {
|
||||||
_videoType = videoType;
|
_videoType = videoType;
|
||||||
@ -226,6 +230,12 @@ class PlPlayerController {
|
|||||||
// 弹幕速度
|
// 弹幕速度
|
||||||
danmakuSpeedVal =
|
danmakuSpeedVal =
|
||||||
localCache.get(LocalCacheKey.danmakuSpeed, defaultValue: 4.0);
|
localCache.get(LocalCacheKey.danmakuSpeed, defaultValue: 4.0);
|
||||||
|
playRepeat = PlayRepeat.values.toList().firstWhere(
|
||||||
|
(e) =>
|
||||||
|
e.value ==
|
||||||
|
videoStorage.get(VideoBoxKey.playRepeat,
|
||||||
|
defaultValue: PlayRepeat.pause.value),
|
||||||
|
);
|
||||||
// _playerEventSubs = onPlayerStatusChanged.listen((PlayerStatus status) {
|
// _playerEventSubs = onPlayerStatusChanged.listen((PlayerStatus status) {
|
||||||
// if (status == PlayerStatus.playing) {
|
// if (status == PlayerStatus.playing) {
|
||||||
// WakelockPlus.enable();
|
// WakelockPlus.enable();
|
||||||
@ -910,6 +920,11 @@ class PlPlayerController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setPlayRepeat(PlayRepeat type) {
|
||||||
|
playRepeat = type;
|
||||||
|
videoStorage.put(VideoBoxKey.playRepeat, type.value);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> dispose({String type = 'single'}) async {
|
Future<void> dispose({String type = 'single'}) async {
|
||||||
// 每次减1,最后销毁
|
// 每次减1,最后销毁
|
||||||
if (type == 'single' && playerCount.value > 1) {
|
if (type == 'single' && playerCount.value > 1) {
|
||||||
|
|||||||
25
lib/plugin/pl_player/models/play_repeat.dart
Normal file
25
lib/plugin/pl_player/models/play_repeat.dart
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
enum PlayRepeat {
|
||||||
|
pause,
|
||||||
|
listOrder,
|
||||||
|
singleCycle,
|
||||||
|
listCycle,
|
||||||
|
}
|
||||||
|
|
||||||
|
extension PlayRepeatExtension on PlayRepeat {
|
||||||
|
static final List<String> _descList = [
|
||||||
|
'播完暂停',
|
||||||
|
'顺序播放',
|
||||||
|
'单个循环',
|
||||||
|
'列表循环',
|
||||||
|
];
|
||||||
|
get description => _descList[index];
|
||||||
|
|
||||||
|
static final List<double> _valueList = [
|
||||||
|
1,
|
||||||
|
2,
|
||||||
|
3,
|
||||||
|
4,
|
||||||
|
];
|
||||||
|
get value => _valueList[index];
|
||||||
|
get defaultValue => _valueList[1];
|
||||||
|
}
|
||||||
@ -157,4 +157,6 @@ class VideoBoxKey {
|
|||||||
static const String videoBrightness = 'videoBrightness';
|
static const String videoBrightness = 'videoBrightness';
|
||||||
// 倍速
|
// 倍速
|
||||||
static const String videoSpeed = 'videoSpeed';
|
static const String videoSpeed = 'videoSpeed';
|
||||||
|
// 播放顺序
|
||||||
|
static const String playRepeat = 'playRepeat';
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user