mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
feat: custom subtitle padding
Closes #77 Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -954,7 +954,7 @@ class _VideoDetailPageState extends State<VideoDetailPage>
|
|||||||
? bangumiIntroController
|
? bangumiIntroController
|
||||||
: null,
|
: null,
|
||||||
headerControl: HeaderControl(
|
headerControl: HeaderControl(
|
||||||
controller: plPlayerController,
|
controller: plPlayerController!,
|
||||||
videoDetailCtr: videoDetailController,
|
videoDetailCtr: videoDetailController,
|
||||||
heroTag: heroTag,
|
heroTag: heroTag,
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -33,14 +33,14 @@ import 'package:marquee/marquee.dart';
|
|||||||
|
|
||||||
class HeaderControl extends StatefulWidget implements PreferredSizeWidget {
|
class HeaderControl extends StatefulWidget implements PreferredSizeWidget {
|
||||||
const HeaderControl({
|
const HeaderControl({
|
||||||
this.controller,
|
required this.controller,
|
||||||
this.videoDetailCtr,
|
required this.videoDetailCtr,
|
||||||
this.floating,
|
this.floating,
|
||||||
required this.heroTag,
|
required this.heroTag,
|
||||||
super.key,
|
super.key,
|
||||||
});
|
});
|
||||||
final PlPlayerController? controller;
|
final PlPlayerController controller;
|
||||||
final VideoDetailController? videoDetailCtr;
|
final VideoDetailController videoDetailCtr;
|
||||||
final Floating? floating;
|
final Floating? floating;
|
||||||
final String heroTag;
|
final String heroTag;
|
||||||
|
|
||||||
@@ -52,32 +52,24 @@ class HeaderControl extends StatefulWidget implements PreferredSizeWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _HeaderControlState extends State<HeaderControl> {
|
class _HeaderControlState extends State<HeaderControl> {
|
||||||
late PlayUrlModel videoInfo;
|
PlayUrlModel get videoInfo => widget.videoDetailCtr.data;
|
||||||
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);
|
||||||
double buttonSpace = 8;
|
double buttonSpace = 8;
|
||||||
// bool isFullScreen = false;
|
String get heroTag => widget.heroTag;
|
||||||
late String heroTag;
|
|
||||||
late VideoIntroController videoIntroController;
|
late VideoIntroController videoIntroController;
|
||||||
late VideoDetailData videoDetail;
|
late VideoDetailData videoDetail;
|
||||||
// late StreamSubscription<bool> fullScreenStatusListener;
|
|
||||||
late bool horizontalScreen;
|
late bool horizontalScreen;
|
||||||
RxString now = ''.obs;
|
RxString now = ''.obs;
|
||||||
Timer? clock;
|
Timer? clock;
|
||||||
late String defaultCDNService;
|
late String defaultCDNService;
|
||||||
bool get isFullScreen => widget.controller!.isFullScreen.value;
|
bool get isFullScreen => widget.controller.isFullScreen.value;
|
||||||
Box get setting => GStorage.setting;
|
Box get setting => GStorage.setting;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
videoInfo = widget.videoDetailCtr!.data;
|
|
||||||
// listenFullScreenStatus();
|
|
||||||
heroTag = widget.heroTag;
|
|
||||||
// if (Get.arguments != null && Get.arguments['heroTag'] != null) {
|
|
||||||
// heroTag = Get.arguments['heroTag'];
|
|
||||||
// }
|
|
||||||
videoIntroController = Get.put(VideoIntroController(), tag: heroTag);
|
videoIntroController = Get.put(VideoIntroController(), tag: heroTag);
|
||||||
horizontalScreen =
|
horizontalScreen =
|
||||||
setting.get(SettingBoxKey.horizontalScreen, defaultValue: false);
|
setting.get(SettingBoxKey.horizontalScreen, defaultValue: false);
|
||||||
@@ -85,23 +77,8 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
defaultValue: CDNService.backupUrl.code);
|
defaultValue: CDNService.backupUrl.code);
|
||||||
}
|
}
|
||||||
|
|
||||||
// void listenFullScreenStatus() {
|
|
||||||
// fullScreenStatusListener = widget
|
|
||||||
// .videoDetailCtr!.plPlayerController.isFullScreen
|
|
||||||
// .listen((bool status) {
|
|
||||||
// isFullScreen = status;
|
|
||||||
|
|
||||||
// /// TODO setState() called after dispose()
|
|
||||||
// if (mounted) {
|
|
||||||
// setState(() {});
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
// widget.floating?.dispose();
|
|
||||||
// fullScreenStatusListener.cancel();
|
|
||||||
clock?.cancel();
|
clock?.cancel();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
@@ -190,13 +167,13 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
// ),
|
// ),
|
||||||
// ),
|
// ),
|
||||||
// ),
|
// ),
|
||||||
// if (widget.videoDetailCtr?.userInfo != null)
|
// if (widget.videoDetailCtr.userInfo != null)
|
||||||
ListTile(
|
ListTile(
|
||||||
dense: true,
|
dense: true,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
Get.back();
|
Get.back();
|
||||||
final res = await UserHttp.toViewLater(
|
final res = await UserHttp.toViewLater(
|
||||||
bvid: widget.videoDetailCtr!.bvid);
|
bvid: widget.videoDetailCtr.bvid);
|
||||||
SmartDialog.showToast(res['msg']);
|
SmartDialog.showToast(res['msg']);
|
||||||
},
|
},
|
||||||
leading:
|
leading:
|
||||||
@@ -214,7 +191,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
dense: true,
|
dense: true,
|
||||||
onTap: () => {
|
onTap: () => {
|
||||||
Get.back(),
|
Get.back(),
|
||||||
widget.videoDetailCtr!.queryVideoUrl()
|
widget.videoDetailCtr.queryVideoUrl()
|
||||||
},
|
},
|
||||||
leading: const Icon(Icons.refresh_outlined, size: 20),
|
leading: const Icon(Icons.refresh_outlined, size: 20),
|
||||||
title: const Text('重载视频', style: titleStyle),
|
title: const Text('重载视频', style: titleStyle),
|
||||||
@@ -249,7 +226,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
SmartDialog.showToast(
|
SmartDialog.showToast(
|
||||||
'已设置为 ${CDNServiceCode.fromCode(result)!.description},正在重载视频');
|
'已设置为 ${CDNServiceCode.fromCode(result)!.description},正在重载视频');
|
||||||
setState(() {});
|
setState(() {});
|
||||||
widget.videoDetailCtr!.queryVideoUrl();
|
widget.videoDetailCtr.queryVideoUrl();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -258,7 +235,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
onTap: () {
|
onTap: () {
|
||||||
Get.back();
|
Get.back();
|
||||||
Player? player =
|
Player? player =
|
||||||
widget.controller?.videoPlayerController;
|
widget.controller.videoPlayerController;
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
SmartDialog.showToast('播放器未初始化');
|
SmartDialog.showToast('播放器未初始化');
|
||||||
return;
|
return;
|
||||||
@@ -278,17 +255,17 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
const Icon(Icons.play_circle_outline, size: 20),
|
const Icon(Icons.play_circle_outline, size: 20),
|
||||||
title: const Text('选择画质', style: titleStyle),
|
title: const Text('选择画质', style: titleStyle),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'当前画质 ${widget.videoDetailCtr!.currentVideoQa.description}',
|
'当前画质 ${widget.videoDetailCtr.currentVideoQa.description}',
|
||||||
style: subTitleStyle),
|
style: subTitleStyle),
|
||||||
),
|
),
|
||||||
if (widget.videoDetailCtr!.currentAudioQa != null)
|
if (widget.videoDetailCtr.currentAudioQa != null)
|
||||||
ListTile(
|
ListTile(
|
||||||
dense: true,
|
dense: true,
|
||||||
onTap: () => {Get.back(), showSetAudioQa()},
|
onTap: () => {Get.back(), showSetAudioQa()},
|
||||||
leading: const Icon(Icons.album_outlined, size: 20),
|
leading: const Icon(Icons.album_outlined, size: 20),
|
||||||
title: const Text('选择音质', style: titleStyle),
|
title: const Text('选择音质', style: titleStyle),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'当前音质 ${widget.videoDetailCtr!.currentAudioQa!.description}',
|
'当前音质 ${widget.videoDetailCtr.currentAudioQa!.description}',
|
||||||
style: subTitleStyle),
|
style: subTitleStyle),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
@@ -298,7 +275,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
const Icon(Icons.av_timer_outlined, size: 20),
|
const Icon(Icons.av_timer_outlined, size: 20),
|
||||||
title: const Text('解码格式', style: titleStyle),
|
title: const Text('解码格式', style: titleStyle),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
'当前解码格式 ${widget.videoDetailCtr!.currentDecodeFormats.description}',
|
'当前解码格式 ${widget.videoDetailCtr.currentDecodeFormats.description}',
|
||||||
style: subTitleStyle),
|
style: subTitleStyle),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
@@ -307,7 +284,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
leading: const Icon(Icons.repeat, size: 20),
|
leading: const Icon(Icons.repeat, size: 20),
|
||||||
title: const Text('播放顺序', style: titleStyle),
|
title: const Text('播放顺序', style: titleStyle),
|
||||||
subtitle: Text(
|
subtitle: Text(
|
||||||
widget.controller!.playRepeat.description,
|
widget.controller.playRepeat.description,
|
||||||
style: subTitleStyle),
|
style: subTitleStyle),
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
@@ -323,7 +300,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
leading: const Icon(Icons.info_outline, size: 20),
|
leading: const Icon(Icons.info_outline, size: 20),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Player? player =
|
Player? player =
|
||||||
widget.controller?.videoPlayerController;
|
widget.controller.videoPlayerController;
|
||||||
if (player == null) {
|
if (player == null) {
|
||||||
SmartDialog.showToast('播放器未初始化');
|
SmartDialog.showToast('播放器未初始化');
|
||||||
return;
|
return;
|
||||||
@@ -483,14 +460,14 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
ListTile(
|
ListTile(
|
||||||
dense: true,
|
dense: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (widget.videoDetailCtr?.userInfo == null) {
|
if (widget.videoDetailCtr.userInfo == null) {
|
||||||
SmartDialog.showToast('账号未登录');
|
SmartDialog.showToast('账号未登录');
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Get.back();
|
Get.back();
|
||||||
Get.toNamed('/webviewnew', parameters: {
|
Get.toNamed('/webviewnew', parameters: {
|
||||||
'url':
|
'url':
|
||||||
'https://www.bilibili.com/appeal/?avid=${IdUtils.bv2av(widget.videoDetailCtr!.bvid)}&bvid=${widget.videoDetailCtr!.bvid}'
|
'https://www.bilibili.com/appeal/?avid=${IdUtils.bv2av(widget.videoDetailCtr.bvid)}&bvid=${widget.videoDetailCtr.bvid}'
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
leading: const Icon(Icons.error_outline, size: 20),
|
leading: const Icon(Icons.error_outline, size: 20),
|
||||||
@@ -713,7 +690,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final List<FormatItem> videoFormat = videoInfo.supportFormats!;
|
final List<FormatItem> videoFormat = videoInfo.supportFormats!;
|
||||||
final VideoQuality currentVideoQa = widget.videoDetailCtr!.currentVideoQa;
|
final VideoQuality currentVideoQa = widget.videoDetailCtr.currentVideoQa;
|
||||||
|
|
||||||
/// 总质量分类
|
/// 总质量分类
|
||||||
final int totalQaSam = videoFormat.length;
|
final int totalQaSam = videoFormat.length;
|
||||||
@@ -790,9 +767,9 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
}
|
}
|
||||||
Get.back();
|
Get.back();
|
||||||
final int quality = videoFormat[i].quality!;
|
final int quality = videoFormat[i].quality!;
|
||||||
widget.videoDetailCtr!.currentVideoQa =
|
widget.videoDetailCtr.currentVideoQa =
|
||||||
VideoQualityCode.fromCode(quality)!;
|
VideoQualityCode.fromCode(quality)!;
|
||||||
widget.videoDetailCtr!.updatePlayer();
|
widget.videoDetailCtr.updatePlayer();
|
||||||
// String oldQualityDesc =
|
// String oldQualityDesc =
|
||||||
// VideoQualityCode.fromCode(setting.get(
|
// VideoQualityCode.fromCode(setting.get(
|
||||||
// SettingBoxKey.defaultVideoQa,
|
// SettingBoxKey.defaultVideoQa,
|
||||||
@@ -837,7 +814,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
|
|
||||||
/// 选择音质
|
/// 选择音质
|
||||||
void showSetAudioQa() {
|
void showSetAudioQa() {
|
||||||
final AudioQuality currentAudioQa = widget.videoDetailCtr!.currentAudioQa!;
|
final AudioQuality currentAudioQa = widget.videoDetailCtr.currentAudioQa!;
|
||||||
final List<AudioItem> audio = videoInfo.dash!.audio!;
|
final List<AudioItem> audio = videoInfo.dash!.audio!;
|
||||||
showModalBottomSheet(
|
showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
@@ -879,9 +856,9 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
}
|
}
|
||||||
Get.back();
|
Get.back();
|
||||||
final int quality = i.id!;
|
final int quality = i.id!;
|
||||||
widget.videoDetailCtr!.currentAudioQa =
|
widget.videoDetailCtr.currentAudioQa =
|
||||||
AudioQualityCode.fromCode(quality)!;
|
AudioQualityCode.fromCode(quality)!;
|
||||||
widget.videoDetailCtr!.updatePlayer();
|
widget.videoDetailCtr.updatePlayer();
|
||||||
// String oldQualityDesc = AudioQualityCode.fromCode(
|
// String oldQualityDesc = AudioQualityCode.fromCode(
|
||||||
// setting.get(SettingBoxKey.defaultAudioQa,
|
// setting.get(SettingBoxKey.defaultAudioQa,
|
||||||
// defaultValue:
|
// defaultValue:
|
||||||
@@ -924,8 +901,8 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
void showSetDecodeFormats() {
|
void showSetDecodeFormats() {
|
||||||
// 当前选中的解码格式
|
// 当前选中的解码格式
|
||||||
final VideoDecodeFormats currentDecodeFormats =
|
final VideoDecodeFormats currentDecodeFormats =
|
||||||
widget.videoDetailCtr!.currentDecodeFormats;
|
widget.videoDetailCtr.currentDecodeFormats;
|
||||||
final VideoItem firstVideo = widget.videoDetailCtr!.firstVideo;
|
final VideoItem firstVideo = widget.videoDetailCtr.firstVideo;
|
||||||
// 当前视频可用的解码格式
|
// 当前视频可用的解码格式
|
||||||
final List<FormatItem> videoFormat = videoInfo.supportFormats!;
|
final List<FormatItem> videoFormat = videoInfo.supportFormats!;
|
||||||
final List? list = videoFormat
|
final List? list = videoFormat
|
||||||
@@ -974,9 +951,9 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
if (i.startsWith(currentDecodeFormats.code)) {
|
if (i.startsWith(currentDecodeFormats.code)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
widget.videoDetailCtr!.currentDecodeFormats =
|
widget.videoDetailCtr.currentDecodeFormats =
|
||||||
VideoDecodeFormatsCode.fromString(i)!;
|
VideoDecodeFormatsCode.fromString(i)!;
|
||||||
widget.videoDetailCtr!.updatePlayer();
|
widget.videoDetailCtr.updatePlayer();
|
||||||
Get.back();
|
Get.back();
|
||||||
},
|
},
|
||||||
contentPadding:
|
contentPadding:
|
||||||
@@ -1017,7 +994,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
{'value': 4, 'label': '底部'},
|
{'value': 4, 'label': '底部'},
|
||||||
{'value': 6, 'label': '彩色'},
|
{'value': 6, 'label': '彩色'},
|
||||||
];
|
];
|
||||||
final List blockTypes = widget.controller!.blockTypes;
|
final List blockTypes = widget.controller.blockTypes;
|
||||||
// 显示区域
|
// 显示区域
|
||||||
final List<Map<String, dynamic>> showAreas = [
|
final List<Map<String, dynamic>> showAreas = [
|
||||||
{'value': 0.25, 'label': '1/4屏'},
|
{'value': 0.25, 'label': '1/4屏'},
|
||||||
@@ -1026,28 +1003,30 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
{'value': 1.0, 'label': '满屏'},
|
{'value': 1.0, 'label': '满屏'},
|
||||||
];
|
];
|
||||||
// 智能云屏蔽
|
// 智能云屏蔽
|
||||||
int danmakuWeight = widget.controller!.danmakuWeight;
|
int danmakuWeight = widget.controller.danmakuWeight;
|
||||||
// 显示区域
|
// 显示区域
|
||||||
double showArea = widget.controller!.showArea;
|
double showArea = widget.controller.showArea;
|
||||||
// 不透明度
|
// 不透明度
|
||||||
double opacityVal = widget.controller!.opacityVal;
|
double opacityVal = widget.controller.opacityVal;
|
||||||
// 字体大小
|
// 字体大小
|
||||||
double fontSizeVal = widget.controller!.fontSizeVal;
|
double fontSizeVal = widget.controller.fontSizeVal;
|
||||||
// 全屏字体大小
|
// 全屏字体大小
|
||||||
double fontSizeFSVal = widget.controller!.fontSizeFSVal;
|
double fontSizeFSVal = widget.controller.fontSizeFSVal;
|
||||||
double subtitleFontScale = widget.controller!.subtitleFontScale.value;
|
double subtitleFontScale = widget.controller.subtitleFontScale;
|
||||||
double subtitleFontScaleFS = widget.controller!.subtitleFontScaleFS.value;
|
double subtitleFontScaleFS = widget.controller.subtitleFontScaleFS;
|
||||||
double danmakuLineHeight = widget.controller!.danmakuLineHeight;
|
double danmakuLineHeight = widget.controller.danmakuLineHeight;
|
||||||
// 弹幕速度
|
// 弹幕速度
|
||||||
double danmakuDurationVal = widget.controller!.danmakuDurationVal;
|
double danmakuDurationVal = widget.controller.danmakuDurationVal;
|
||||||
// 弹幕描边
|
// 弹幕描边
|
||||||
double strokeWidth = widget.controller!.strokeWidth;
|
double strokeWidth = widget.controller.strokeWidth;
|
||||||
// 字体粗细
|
// 字体粗细
|
||||||
int fontWeight = widget.controller!.fontWeight;
|
int fontWeight = widget.controller.fontWeight;
|
||||||
bool massiveMode = widget.controller!.massiveMode;
|
bool massiveMode = widget.controller.massiveMode;
|
||||||
|
int subtitlePaddingH = widget.controller.subtitlePaddingH;
|
||||||
|
int subtitlePaddingB = widget.controller.subtitlePaddingB;
|
||||||
|
|
||||||
final DanmakuController danmakuController =
|
final DanmakuController? danmakuController =
|
||||||
widget.controller!.danmakuController!;
|
widget.controller.danmakuController;
|
||||||
await showModalBottomSheet(
|
await showModalBottomSheet(
|
||||||
context: context,
|
context: context,
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
@@ -1068,9 +1047,8 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
left: 12,
|
left: 12,
|
||||||
top: 12,
|
top: 12,
|
||||||
right: 12,
|
right: 12,
|
||||||
bottom:
|
bottom: (widget.controller.isFullScreen.value == true ? 70 : 12) +
|
||||||
(widget.controller?.isFullScreen.value == true ? 70 : 12) +
|
MediaQuery.paddingOf(context).bottom,
|
||||||
MediaQuery.paddingOf(context).bottom,
|
|
||||||
),
|
),
|
||||||
padding: const EdgeInsets.only(left: 14, right: 14),
|
padding: const EdgeInsets.only(left: 14, right: 14),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
@@ -1098,7 +1076,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
arguments: widget.controller)
|
arguments: widget.controller)
|
||||||
},
|
},
|
||||||
child: Text(
|
child: Text(
|
||||||
"屏蔽管理(${widget.controller!.danmakuFilterRule.length})")),
|
"屏蔽管理(${widget.controller.danmakuFilterRule.length})")),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Padding(
|
Padding(
|
||||||
@@ -1125,8 +1103,9 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
label: '$danmakuWeight',
|
label: '$danmakuWeight',
|
||||||
onChanged: (double val) {
|
onChanged: (double val) {
|
||||||
danmakuWeight = val.toInt();
|
danmakuWeight = val.toInt();
|
||||||
widget.controller!.danmakuWeight = danmakuWeight;
|
widget.controller
|
||||||
widget.controller!.putDanmakuSettings();
|
..danmakuWeight = danmakuWeight
|
||||||
|
..putDanmakuSettings();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -1148,11 +1127,12 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
} else {
|
} else {
|
||||||
blockTypes.add(i['value']);
|
blockTypes.add(i['value']);
|
||||||
}
|
}
|
||||||
widget.controller!.blockTypes = blockTypes;
|
widget.controller
|
||||||
widget.controller?.putDanmakuSettings();
|
..blockTypes = blockTypes
|
||||||
|
..putDanmakuSettings();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
try {
|
try {
|
||||||
danmakuController.updateOption(
|
danmakuController?.updateOption(
|
||||||
danmakuController.option.copyWith(
|
danmakuController.option.copyWith(
|
||||||
hideTop: blockTypes.contains(5),
|
hideTop: blockTypes.contains(5),
|
||||||
hideBottom: blockTypes.contains(4),
|
hideBottom: blockTypes.contains(4),
|
||||||
@@ -1179,11 +1159,12 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
ActionRowLineItem(
|
ActionRowLineItem(
|
||||||
onTap: () {
|
onTap: () {
|
||||||
showArea = i['value'];
|
showArea = i['value'];
|
||||||
widget.controller!.showArea = showArea;
|
widget.controller
|
||||||
widget.controller?.putDanmakuSettings();
|
..showArea = showArea
|
||||||
|
..putDanmakuSettings();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
try {
|
try {
|
||||||
danmakuController.updateOption(
|
danmakuController?.updateOption(
|
||||||
danmakuController.option
|
danmakuController.option
|
||||||
.copyWith(area: i['value']),
|
.copyWith(area: i['value']),
|
||||||
);
|
);
|
||||||
@@ -1205,10 +1186,10 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
setKey: SettingBoxKey.danmakuMassiveMode,
|
setKey: SettingBoxKey.danmakuMassiveMode,
|
||||||
onChanged: (value) {
|
onChanged: (value) {
|
||||||
massiveMode = value;
|
massiveMode = value;
|
||||||
widget.controller!.massiveMode = value;
|
widget.controller.massiveMode = value;
|
||||||
setState(() {});
|
setState(() {});
|
||||||
try {
|
try {
|
||||||
danmakuController.updateOption(
|
danmakuController?.updateOption(
|
||||||
danmakuController.option.copyWith(massiveMode: value),
|
danmakuController.option.copyWith(massiveMode: value),
|
||||||
);
|
);
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
@@ -1239,11 +1220,12 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
label: '${opacityVal * 100}%',
|
label: '${opacityVal * 100}%',
|
||||||
onChanged: (double val) {
|
onChanged: (double val) {
|
||||||
opacityVal = val;
|
opacityVal = val;
|
||||||
widget.controller!.opacityVal = opacityVal;
|
widget.controller
|
||||||
widget.controller?.putDanmakuSettings();
|
..opacityVal = opacityVal
|
||||||
|
..putDanmakuSettings();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
try {
|
try {
|
||||||
danmakuController.updateOption(
|
danmakuController?.updateOption(
|
||||||
danmakuController.option.copyWith(opacity: val),
|
danmakuController.option.copyWith(opacity: val),
|
||||||
);
|
);
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
@@ -1276,11 +1258,12 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
label: '${fontWeight + 1}',
|
label: '${fontWeight + 1}',
|
||||||
onChanged: (double val) {
|
onChanged: (double val) {
|
||||||
fontWeight = val.toInt();
|
fontWeight = val.toInt();
|
||||||
widget.controller!.fontWeight = fontWeight;
|
widget.controller
|
||||||
widget.controller?.putDanmakuSettings();
|
..fontWeight = fontWeight
|
||||||
|
..putDanmakuSettings();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
try {
|
try {
|
||||||
danmakuController.updateOption(
|
danmakuController?.updateOption(
|
||||||
danmakuController.option
|
danmakuController.option
|
||||||
.copyWith(fontWeight: fontWeight),
|
.copyWith(fontWeight: fontWeight),
|
||||||
);
|
);
|
||||||
@@ -1314,11 +1297,12 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
label: '$strokeWidth',
|
label: '$strokeWidth',
|
||||||
onChanged: (double val) {
|
onChanged: (double val) {
|
||||||
strokeWidth = val;
|
strokeWidth = val;
|
||||||
widget.controller!.strokeWidth = val;
|
widget.controller
|
||||||
widget.controller?.putDanmakuSettings();
|
..strokeWidth = val
|
||||||
|
..putDanmakuSettings();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
try {
|
try {
|
||||||
danmakuController.updateOption(
|
danmakuController?.updateOption(
|
||||||
danmakuController.option
|
danmakuController.option
|
||||||
.copyWith(strokeWidth: val),
|
.copyWith(strokeWidth: val),
|
||||||
);
|
);
|
||||||
@@ -1352,12 +1336,13 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
label: '${(fontSizeVal * 100).toStringAsFixed(1)}%',
|
label: '${(fontSizeVal * 100).toStringAsFixed(1)}%',
|
||||||
onChanged: (double val) {
|
onChanged: (double val) {
|
||||||
fontSizeVal = val;
|
fontSizeVal = val;
|
||||||
widget.controller!.fontSizeVal = fontSizeVal;
|
widget.controller
|
||||||
widget.controller?.putDanmakuSettings();
|
..fontSizeVal = fontSizeVal
|
||||||
|
..putDanmakuSettings();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
if (widget.controller?.isFullScreen.value == false) {
|
if (widget.controller.isFullScreen.value == false) {
|
||||||
try {
|
try {
|
||||||
danmakuController.updateOption(
|
danmakuController?.updateOption(
|
||||||
danmakuController.option.copyWith(
|
danmakuController.option.copyWith(
|
||||||
fontSize: (15 * fontSizeVal).toDouble(),
|
fontSize: (15 * fontSizeVal).toDouble(),
|
||||||
),
|
),
|
||||||
@@ -1393,12 +1378,13 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
label: '${(fontSizeFSVal * 100).toStringAsFixed(1)}%',
|
label: '${(fontSizeFSVal * 100).toStringAsFixed(1)}%',
|
||||||
onChanged: (double val) {
|
onChanged: (double val) {
|
||||||
fontSizeFSVal = val;
|
fontSizeFSVal = val;
|
||||||
widget.controller!.fontSizeFSVal = fontSizeFSVal;
|
widget.controller
|
||||||
widget.controller?.putDanmakuSettings();
|
..fontSizeFSVal = fontSizeFSVal
|
||||||
|
..putDanmakuSettings();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
if (widget.controller?.isFullScreen.value == true) {
|
if (widget.controller.isFullScreen.value == true) {
|
||||||
try {
|
try {
|
||||||
danmakuController.updateOption(
|
danmakuController?.updateOption(
|
||||||
danmakuController.option.copyWith(
|
danmakuController.option.copyWith(
|
||||||
fontSize: (15 * fontSizeFSVal).toDouble(),
|
fontSize: (15 * fontSizeFSVal).toDouble(),
|
||||||
),
|
),
|
||||||
@@ -1435,15 +1421,15 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
onChanged: (double val) {
|
onChanged: (double val) {
|
||||||
danmakuDurationVal =
|
danmakuDurationVal =
|
||||||
(pow(val, 4) as double).toPrecision(2);
|
(pow(val, 4) as double).toPrecision(2);
|
||||||
widget.controller!.danmakuDurationVal =
|
widget.controller
|
||||||
danmakuDurationVal;
|
..danmakuDurationVal = danmakuDurationVal
|
||||||
widget.controller?.putDanmakuSettings();
|
..putDanmakuSettings();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
try {
|
try {
|
||||||
danmakuController.updateOption(
|
danmakuController?.updateOption(
|
||||||
danmakuController.option.copyWith(
|
danmakuController.option.copyWith(
|
||||||
duration: danmakuDurationVal ~/
|
duration: danmakuDurationVal ~/
|
||||||
widget.controller!.playbackSpeed),
|
widget.controller.playbackSpeed),
|
||||||
);
|
);
|
||||||
} catch (_) {}
|
} catch (_) {}
|
||||||
},
|
},
|
||||||
@@ -1474,12 +1460,12 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
label: '$danmakuLineHeight',
|
label: '$danmakuLineHeight',
|
||||||
onChanged: (double val) {
|
onChanged: (double val) {
|
||||||
danmakuLineHeight = val.toPrecision(1);
|
danmakuLineHeight = val.toPrecision(1);
|
||||||
widget.controller!.danmakuLineHeight =
|
widget.controller
|
||||||
danmakuLineHeight;
|
..danmakuLineHeight = danmakuLineHeight
|
||||||
widget.controller?.putDanmakuSettings();
|
..putDanmakuSettings();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
try {
|
try {
|
||||||
danmakuController.updateOption(
|
danmakuController?.updateOption(
|
||||||
danmakuController.option.copyWith(
|
danmakuController.option.copyWith(
|
||||||
lineHeight: danmakuLineHeight,
|
lineHeight: danmakuLineHeight,
|
||||||
),
|
),
|
||||||
@@ -1516,9 +1502,10 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
'${(subtitleFontScale * 100).toStringAsFixed(1)}%',
|
'${(subtitleFontScale * 100).toStringAsFixed(1)}%',
|
||||||
onChanged: (double val) {
|
onChanged: (double val) {
|
||||||
subtitleFontScale = val;
|
subtitleFontScale = val;
|
||||||
widget.controller!.subtitleFontScale.value =
|
widget.controller
|
||||||
subtitleFontScale;
|
..subtitleFontScale = subtitleFontScale
|
||||||
widget.controller?.putDanmakuSettings();
|
..updateSubtitleStyle()
|
||||||
|
..putDanmakuSettings();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -1551,9 +1538,78 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
'${(subtitleFontScaleFS * 100).toStringAsFixed(1)}%',
|
'${(subtitleFontScaleFS * 100).toStringAsFixed(1)}%',
|
||||||
onChanged: (double val) {
|
onChanged: (double val) {
|
||||||
subtitleFontScaleFS = val;
|
subtitleFontScaleFS = val;
|
||||||
widget.controller!.subtitleFontScaleFS.value =
|
widget.controller
|
||||||
subtitleFontScaleFS;
|
..subtitleFontScaleFS = subtitleFontScaleFS
|
||||||
widget.controller?.putDanmakuSettings();
|
..updateSubtitleStyle()
|
||||||
|
..putDanmakuSettings();
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text('字幕左右边距 $subtitlePaddingH'),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 0,
|
||||||
|
bottom: 6,
|
||||||
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
),
|
||||||
|
child: SliderTheme(
|
||||||
|
data: SliderThemeData(
|
||||||
|
trackShape: MSliderTrackShape(),
|
||||||
|
thumbColor: Theme.of(context).colorScheme.primary,
|
||||||
|
activeTrackColor: Theme.of(context).colorScheme.primary,
|
||||||
|
trackHeight: 10,
|
||||||
|
thumbShape: const RoundSliderThumbShape(
|
||||||
|
enabledThumbRadius: 6.0),
|
||||||
|
),
|
||||||
|
child: Slider(
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
value: subtitlePaddingH.toDouble(),
|
||||||
|
divisions: 100,
|
||||||
|
label: '$subtitlePaddingH',
|
||||||
|
onChanged: (double val) {
|
||||||
|
subtitlePaddingH = val.round();
|
||||||
|
widget.controller
|
||||||
|
..subtitlePaddingH = subtitlePaddingH
|
||||||
|
..updateSubtitleStyle()
|
||||||
|
..putDanmakuSettings();
|
||||||
|
setState(() {});
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Text('字幕底部边距 $subtitlePaddingB'),
|
||||||
|
Padding(
|
||||||
|
padding: const EdgeInsets.only(
|
||||||
|
top: 0,
|
||||||
|
bottom: 6,
|
||||||
|
left: 10,
|
||||||
|
right: 10,
|
||||||
|
),
|
||||||
|
child: SliderTheme(
|
||||||
|
data: SliderThemeData(
|
||||||
|
trackShape: MSliderTrackShape(),
|
||||||
|
thumbColor: Theme.of(context).colorScheme.primary,
|
||||||
|
activeTrackColor: Theme.of(context).colorScheme.primary,
|
||||||
|
trackHeight: 10,
|
||||||
|
thumbShape: const RoundSliderThumbShape(
|
||||||
|
enabledThumbRadius: 6.0),
|
||||||
|
),
|
||||||
|
child: Slider(
|
||||||
|
min: 0,
|
||||||
|
max: 100,
|
||||||
|
value: subtitlePaddingB.toDouble(),
|
||||||
|
divisions: 100,
|
||||||
|
label: '$subtitlePaddingB',
|
||||||
|
onChanged: (double val) {
|
||||||
|
subtitlePaddingB = val.round();
|
||||||
|
widget.controller
|
||||||
|
..subtitlePaddingB = subtitlePaddingB
|
||||||
|
..updateSubtitleStyle()
|
||||||
|
..putDanmakuSettings();
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
@@ -1605,13 +1661,13 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
ListTile(
|
ListTile(
|
||||||
dense: true,
|
dense: true,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
widget.controller!.setPlayRepeat(i);
|
widget.controller.setPlayRepeat(i);
|
||||||
Get.back();
|
Get.back();
|
||||||
},
|
},
|
||||||
contentPadding:
|
contentPadding:
|
||||||
const EdgeInsets.only(left: 20, right: 20),
|
const EdgeInsets.only(left: 20, right: 20),
|
||||||
title: Text(i.description),
|
title: Text(i.description),
|
||||||
trailing: widget.controller!.playRepeat == i
|
trailing: widget.controller.playRepeat == i
|
||||||
? Icon(
|
? Icon(
|
||||||
Icons.done,
|
Icons.done,
|
||||||
color:
|
color:
|
||||||
@@ -1643,7 +1699,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final plPlayerController = widget.controller!;
|
final plPlayerController = widget.controller;
|
||||||
// final bool isLandscape =
|
// final bool isLandscape =
|
||||||
// MediaQuery.of(context).orientation == Orientation.landscape;
|
// MediaQuery.of(context).orientation == Orientation.landscape;
|
||||||
|
|
||||||
@@ -1669,11 +1725,11 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
if (widget.videoDetailCtr?.bsController != null) {
|
if (widget.videoDetailCtr.bsController != null) {
|
||||||
widget.videoDetailCtr?.bsController!.close();
|
widget.videoDetailCtr.bsController!.close();
|
||||||
widget.videoDetailCtr?.bsController = null;
|
widget.videoDetailCtr.bsController = null;
|
||||||
} else if (isFullScreen) {
|
} else if (isFullScreen) {
|
||||||
widget.controller!.triggerFullScreen(status: false);
|
widget.controller.triggerFullScreen(status: false);
|
||||||
} else if (MediaQuery.of(context).orientation ==
|
} else if (MediaQuery.of(context).orientation ==
|
||||||
Orientation.landscape &&
|
Orientation.landscape &&
|
||||||
!horizontalScreen) {
|
!horizontalScreen) {
|
||||||
@@ -1770,7 +1826,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
// ),
|
// ),
|
||||||
// fuc: () => _.screenshot(),
|
// fuc: () => _.screenshot(),
|
||||||
// ),
|
// ),
|
||||||
if (widget.videoDetailCtr?.enableSponsorBlock == true)
|
if (widget.videoDetailCtr.enableSponsorBlock == true)
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 42,
|
width: 42,
|
||||||
height: 34,
|
height: 34,
|
||||||
@@ -1779,7 +1835,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
||||||
),
|
),
|
||||||
onPressed: () => widget.videoDetailCtr?.onBlock(context),
|
onPressed: () => widget.videoDetailCtr.onBlock(context),
|
||||||
icon: Stack(
|
icon: Stack(
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
children: [
|
children: [
|
||||||
@@ -1798,7 +1854,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Obx(
|
Obx(
|
||||||
() => widget.videoDetailCtr?.segmentList.isNotEmpty == true
|
() => widget.videoDetailCtr.segmentList.isNotEmpty == true
|
||||||
? SizedBox(
|
? SizedBox(
|
||||||
width: 42,
|
width: 42,
|
||||||
height: 34,
|
height: 34,
|
||||||
@@ -1808,7 +1864,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
||||||
),
|
),
|
||||||
onPressed: () =>
|
onPressed: () =>
|
||||||
widget.videoDetailCtr?.showSBDetail(context),
|
widget.videoDetailCtr.showSBDetail(context),
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
MdiIcons.advertisements,
|
MdiIcons.advertisements,
|
||||||
size: 19,
|
size: 19,
|
||||||
@@ -1826,7 +1882,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
style: ButtonStyle(
|
style: ButtonStyle(
|
||||||
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
||||||
),
|
),
|
||||||
onPressed: widget.videoDetailCtr?.showShootDanmakuSheet,
|
onPressed: widget.videoDetailCtr.showShootDanmakuSheet,
|
||||||
icon: const Icon(
|
icon: const Icon(
|
||||||
Icons.comment_outlined,
|
Icons.comment_outlined,
|
||||||
size: 19,
|
size: 19,
|
||||||
@@ -1875,7 +1931,7 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
bool canUsePiP = widget.floating != null &&
|
bool canUsePiP = widget.floating != null &&
|
||||||
await widget.floating!.isPipAvailable;
|
await widget.floating!.isPipAvailable;
|
||||||
widget.controller!.hiddenControls(false);
|
widget.controller.hiddenControls(false);
|
||||||
if (canUsePiP) {
|
if (canUsePiP) {
|
||||||
bool enableBackgroundPlay = setting.get(
|
bool enableBackgroundPlay = setting.get(
|
||||||
SettingBoxKey.enableBackgroundPlay,
|
SettingBoxKey.enableBackgroundPlay,
|
||||||
@@ -1945,8 +2001,8 @@ class _HeaderControlState extends State<HeaderControl> {
|
|||||||
await Future.delayed(const Duration(seconds: 3), () {});
|
await Future.delayed(const Duration(seconds: 3), () {});
|
||||||
}
|
}
|
||||||
final Rational aspectRatio = Rational(
|
final Rational aspectRatio = Rational(
|
||||||
widget.videoDetailCtr!.data.dash!.video!.first.width!,
|
widget.videoDetailCtr.data.dash!.video!.first.width!,
|
||||||
widget.videoDetailCtr!.data.dash!.video!.first.height!,
|
widget.videoDetailCtr.data.dash!.video!.first.height!,
|
||||||
);
|
);
|
||||||
if (!context.mounted) return;
|
if (!context.mounted) return;
|
||||||
await widget.floating!.enable(EnableManual(
|
await widget.floating!.enable(EnableManual(
|
||||||
|
|||||||
@@ -251,13 +251,47 @@ class PlPlayerController {
|
|||||||
double? defaultDuration;
|
double? defaultDuration;
|
||||||
late bool enableAutoLongPressSpeed = false;
|
late bool enableAutoLongPressSpeed = false;
|
||||||
late bool enableLongShowControl;
|
late bool enableLongShowControl;
|
||||||
RxDouble subtitleFontScale = (1.0).obs;
|
double subtitleFontScale = 1.0;
|
||||||
RxDouble subtitleFontScaleFS = (1.5).obs;
|
double subtitleFontScaleFS = 1.5;
|
||||||
late double danmakuLineHeight = GStorage.danmakuLineHeight;
|
late double danmakuLineHeight = GStorage.danmakuLineHeight;
|
||||||
|
late int subtitlePaddingH = GStorage.subtitlePaddingH;
|
||||||
|
late int subtitlePaddingB = GStorage.subtitlePaddingB;
|
||||||
|
|
||||||
// 播放顺序相关
|
// 播放顺序相关
|
||||||
PlayRepeat playRepeat = PlayRepeat.pause;
|
PlayRepeat playRepeat = PlayRepeat.pause;
|
||||||
|
|
||||||
|
final GlobalKey<VideoState> key = GlobalKey<VideoState>();
|
||||||
|
|
||||||
|
TextStyle get subTitleStyle => TextStyle(
|
||||||
|
height: 1.5,
|
||||||
|
fontSize:
|
||||||
|
16 * (isFullScreen.value ? subtitleFontScaleFS : subtitleFontScale),
|
||||||
|
letterSpacing: 0.1,
|
||||||
|
wordSpacing: 0.1,
|
||||||
|
color: Colors.white,
|
||||||
|
fontWeight: FontWeight.normal,
|
||||||
|
backgroundColor: Color(0xaa000000),
|
||||||
|
);
|
||||||
|
|
||||||
|
void updateSubtitleStyle([double? value]) {
|
||||||
|
key.currentState?.update(
|
||||||
|
subtitleViewConfiguration: SubtitleViewConfiguration(
|
||||||
|
style: subTitleStyle.copyWith(
|
||||||
|
fontSize: 16 *
|
||||||
|
(value ??
|
||||||
|
(isFullScreen.value
|
||||||
|
? subtitleFontScaleFS
|
||||||
|
: subtitleFontScale))),
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
left: subtitlePaddingH.toDouble(),
|
||||||
|
right: subtitlePaddingH.toDouble(),
|
||||||
|
bottom: subtitlePaddingB.toDouble(),
|
||||||
|
),
|
||||||
|
textScaleFactor: MediaQuery.textScalerOf(Get.context!).scale(1),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
void updateSliderPositionSecond() {
|
void updateSliderPositionSecond() {
|
||||||
int newSecond = _sliderPosition.value.inSeconds;
|
int newSecond = _sliderPosition.value.inSeconds;
|
||||||
if (sliderPositionSeconds.value != newSecond) {
|
if (sliderPositionSeconds.value != newSecond) {
|
||||||
@@ -346,8 +380,8 @@ class PlPlayerController {
|
|||||||
setting.get(SettingBoxKey.danmakuFontScale, defaultValue: 1.0);
|
setting.get(SettingBoxKey.danmakuFontScale, defaultValue: 1.0);
|
||||||
// 全屏字体大小
|
// 全屏字体大小
|
||||||
fontSizeFSVal = GStorage.danmakuFontScaleFS;
|
fontSizeFSVal = GStorage.danmakuFontScaleFS;
|
||||||
subtitleFontScale.value = GStorage.subtitleFontScale;
|
subtitleFontScale = GStorage.subtitleFontScale;
|
||||||
subtitleFontScaleFS.value = GStorage.subtitleFontScaleFS;
|
subtitleFontScaleFS = GStorage.subtitleFontScaleFS;
|
||||||
massiveMode = GStorage.danmakuMassiveMode;
|
massiveMode = GStorage.danmakuMassiveMode;
|
||||||
// 弹幕时间
|
// 弹幕时间
|
||||||
danmakuDurationVal =
|
danmakuDurationVal =
|
||||||
@@ -1154,6 +1188,7 @@ class PlPlayerController {
|
|||||||
|
|
||||||
void toggleFullScreen(bool val) {
|
void toggleFullScreen(bool val) {
|
||||||
_isFullScreen.value = val;
|
_isFullScreen.value = val;
|
||||||
|
updateSubtitleStyle();
|
||||||
}
|
}
|
||||||
|
|
||||||
// 全屏
|
// 全屏
|
||||||
@@ -1279,12 +1314,14 @@ class PlPlayerController {
|
|||||||
setting.put(SettingBoxKey.danmakuOpacity, opacityVal);
|
setting.put(SettingBoxKey.danmakuOpacity, opacityVal);
|
||||||
setting.put(SettingBoxKey.danmakuFontScale, fontSizeVal);
|
setting.put(SettingBoxKey.danmakuFontScale, fontSizeVal);
|
||||||
setting.put(SettingBoxKey.danmakuFontScaleFS, fontSizeFSVal);
|
setting.put(SettingBoxKey.danmakuFontScaleFS, fontSizeFSVal);
|
||||||
setting.put(SettingBoxKey.subtitleFontScale, subtitleFontScale.value);
|
setting.put(SettingBoxKey.subtitleFontScale, subtitleFontScale);
|
||||||
setting.put(SettingBoxKey.subtitleFontScaleFS, subtitleFontScaleFS.value);
|
setting.put(SettingBoxKey.subtitleFontScaleFS, subtitleFontScaleFS);
|
||||||
setting.put(SettingBoxKey.danmakuDuration, danmakuDurationVal);
|
setting.put(SettingBoxKey.danmakuDuration, danmakuDurationVal);
|
||||||
setting.put(SettingBoxKey.strokeWidth, strokeWidth);
|
setting.put(SettingBoxKey.strokeWidth, strokeWidth);
|
||||||
setting.put(SettingBoxKey.fontWeight, fontWeight);
|
setting.put(SettingBoxKey.fontWeight, fontWeight);
|
||||||
setting.put(SettingBoxKey.danmakuLineHeight, danmakuLineHeight);
|
setting.put(SettingBoxKey.danmakuLineHeight, danmakuLineHeight);
|
||||||
|
setting.put(SettingBoxKey.subtitlePaddingH, subtitlePaddingH);
|
||||||
|
setting.put(SettingBoxKey.subtitlePaddingB, subtitlePaddingB);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> dispose({String type = 'single'}) async {
|
Future<void> dispose({String type = 'single'}) async {
|
||||||
|
|||||||
@@ -78,7 +78,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
late BangumiIntroController? bangumiIntroController;
|
late BangumiIntroController? bangumiIntroController;
|
||||||
|
|
||||||
final GlobalKey _playerKey = GlobalKey();
|
final GlobalKey _playerKey = GlobalKey();
|
||||||
final GlobalKey<VideoState> _key = GlobalKey<VideoState>();
|
|
||||||
|
|
||||||
final RxBool _mountSeekBackwardButton = false.obs;
|
final RxBool _mountSeekBackwardButton = false.obs;
|
||||||
final RxBool _mountSeekForwardButton = false.obs;
|
final RxBool _mountSeekForwardButton = false.obs;
|
||||||
@@ -146,7 +145,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
}
|
}
|
||||||
|
|
||||||
StreamSubscription? _listener;
|
StreamSubscription? _listener;
|
||||||
StreamSubscription? _listenerFS;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -226,7 +224,6 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_listener?.cancel();
|
_listener?.cancel();
|
||||||
_listenerFS?.cancel();
|
|
||||||
animationController.dispose();
|
animationController.dispose();
|
||||||
FlutterVolumeController.removeListener();
|
FlutterVolumeController.removeListener();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
@@ -573,39 +570,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
|
|
||||||
bool get isFullScreen => plPlayerController.isFullScreen.value;
|
bool get isFullScreen => plPlayerController.isFullScreen.value;
|
||||||
|
|
||||||
TextStyle get subTitleStyle => TextStyle(
|
|
||||||
height: 1.5,
|
|
||||||
fontSize: 16 *
|
|
||||||
(isFullScreen
|
|
||||||
? plPlayerController.subtitleFontScaleFS.value
|
|
||||||
: plPlayerController.subtitleFontScale.value),
|
|
||||||
letterSpacing: 0.1,
|
|
||||||
wordSpacing: 0.1,
|
|
||||||
color: Colors.white,
|
|
||||||
fontWeight: FontWeight.normal,
|
|
||||||
backgroundColor: Color(0xaa000000),
|
|
||||||
);
|
|
||||||
|
|
||||||
void _updateSubtitle(double value) {
|
|
||||||
_key.currentState?.update(
|
|
||||||
subtitleViewConfiguration: SubtitleViewConfiguration(
|
|
||||||
style: subTitleStyle.copyWith(fontSize: 16 * value),
|
|
||||||
padding: const EdgeInsets.all(24.0),
|
|
||||||
textScaleFactor: MediaQuery.textScalerOf(context).scale(1),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
_listenerFS?.cancel();
|
|
||||||
_listenerFS = isFullScreen
|
|
||||||
? plPlayerController.subtitleFontScaleFS.listen((value) {
|
|
||||||
_updateSubtitle(value);
|
|
||||||
})
|
|
||||||
: _listenerFS = plPlayerController.subtitleFontScale.listen((value) {
|
|
||||||
_updateSubtitle(value);
|
|
||||||
});
|
|
||||||
final Color colorTheme = Theme.of(context).colorScheme.primary;
|
final Color colorTheme = Theme.of(context).colorScheme.primary;
|
||||||
const TextStyle textStyle = TextStyle(
|
const TextStyle textStyle = TextStyle(
|
||||||
color: Colors.white,
|
color: Colors.white,
|
||||||
@@ -747,7 +713,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
_gestureType = null;
|
_gestureType = null;
|
||||||
},
|
},
|
||||||
child: Video(
|
child: Video(
|
||||||
key: _key,
|
key: plPlayerController.key,
|
||||||
controller: videoController,
|
controller: videoController,
|
||||||
controls: NoVideoControls,
|
controls: NoVideoControls,
|
||||||
pauseUponEnteringBackgroundMode:
|
pauseUponEnteringBackgroundMode:
|
||||||
@@ -755,7 +721,7 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
resumeUponEnteringForegroundMode: true,
|
resumeUponEnteringForegroundMode: true,
|
||||||
// 字幕尺寸调节
|
// 字幕尺寸调节
|
||||||
subtitleViewConfiguration: SubtitleViewConfiguration(
|
subtitleViewConfiguration: SubtitleViewConfiguration(
|
||||||
style: subTitleStyle,
|
style: plPlayerController.subTitleStyle,
|
||||||
padding: const EdgeInsets.all(24.0),
|
padding: const EdgeInsets.all(24.0),
|
||||||
textScaleFactor: MediaQuery.textScalerOf(context).scale(1),
|
textScaleFactor: MediaQuery.textScalerOf(context).scale(1),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -151,6 +151,12 @@ class GStorage {
|
|||||||
static bool get reverseFromFirst =>
|
static bool get reverseFromFirst =>
|
||||||
setting.get(SettingBoxKey.reverseFromFirst, defaultValue: true);
|
setting.get(SettingBoxKey.reverseFromFirst, defaultValue: true);
|
||||||
|
|
||||||
|
static int get subtitlePaddingH =>
|
||||||
|
setting.get(SettingBoxKey.subtitlePaddingH, defaultValue: 24);
|
||||||
|
|
||||||
|
static int get subtitlePaddingB =>
|
||||||
|
setting.get(SettingBoxKey.subtitlePaddingB, defaultValue: 24);
|
||||||
|
|
||||||
static List<double> get dynamicDetailRatio => List<double>.from(setting
|
static List<double> get dynamicDetailRatio => List<double>.from(setting
|
||||||
.get(SettingBoxKey.dynamicDetailRatio, defaultValue: [60.0, 40.0]));
|
.get(SettingBoxKey.dynamicDetailRatio, defaultValue: [60.0, 40.0]));
|
||||||
|
|
||||||
@@ -354,6 +360,8 @@ class SettingBoxKey {
|
|||||||
replyLengthLimit = 'replyLengthLimit',
|
replyLengthLimit = 'replyLengthLimit',
|
||||||
showArgueMsg = 'showArgueMsg',
|
showArgueMsg = 'showArgueMsg',
|
||||||
reverseFromFirst = 'reverseFromFirst',
|
reverseFromFirst = 'reverseFromFirst',
|
||||||
|
subtitlePaddingH = 'subtitlePaddingH',
|
||||||
|
subtitlePaddingB = 'subtitlePaddingB',
|
||||||
|
|
||||||
// Sponsor Block
|
// Sponsor Block
|
||||||
enableSponsorBlock = 'enableSponsorBlock',
|
enableSponsorBlock = 'enableSponsorBlock',
|
||||||
|
|||||||
Reference in New Issue
Block a user