mod: sync flip/onlyPlayAudio from orz12/main

Closes #100

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-01-06 16:15:55 +08:00
parent 3d803cce9f
commit 5001f3b6d2
5 changed files with 128 additions and 33 deletions

View File

@@ -165,6 +165,9 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
Icons.shield_outlined, Icons.shield_outlined,
size: size:
MediaQuery.textScalerOf(context).scale(16), MediaQuery.textScalerOf(context).scale(16),
color: Theme.of(context)
.colorScheme
.onSecondaryContainer,
), ),
Icon( Icon(
Icons.play_arrow_rounded, Icons.play_arrow_rounded,

View File

@@ -99,20 +99,24 @@ class MenuRow extends StatelessWidget {
class ActionRowLineItem extends StatelessWidget { class ActionRowLineItem extends StatelessWidget {
const ActionRowLineItem({ const ActionRowLineItem({
super.key, super.key,
this.selectStatus, required this.selectStatus,
this.onTap, this.onTap,
this.text, this.text,
this.loadingStatus = false, this.loadingStatus = false,
this.iconData,
this.icon,
}); });
final bool? selectStatus; final bool selectStatus;
final Function? onTap; final Function? onTap;
final bool? loadingStatus; final bool? loadingStatus;
final String? text; final String? text;
final IconData? iconData;
final Widget? icon;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Material( return Material(
color: selectStatus! color: selectStatus
? Theme.of(context).colorScheme.secondaryContainer ? Theme.of(context).colorScheme.secondaryContainer
: Colors.transparent, : Colors.transparent,
borderRadius: const BorderRadius.all(Radius.circular(30)), borderRadius: const BorderRadius.all(Radius.circular(30)),
@@ -127,7 +131,7 @@ class ActionRowLineItem extends StatelessWidget {
decoration: BoxDecoration( decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(30)), borderRadius: const BorderRadius.all(Radius.circular(30)),
border: Border.all( border: Border.all(
color: selectStatus! color: selectStatus
? Colors.transparent ? Colors.transparent
: Theme.of(context).colorScheme.secondaryContainer, : Theme.of(context).colorScheme.secondaryContainer,
), ),
@@ -135,6 +139,16 @@ class ActionRowLineItem extends StatelessWidget {
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
if (iconData != null)
Icon(
iconData,
size: 13,
color: selectStatus
? Theme.of(context).colorScheme.onSecondaryContainer
: Theme.of(context).colorScheme.outline,
)
else if (icon != null)
icon!,
AnimatedOpacity( AnimatedOpacity(
opacity: loadingStatus! ? 0 : 1, opacity: loadingStatus! ? 0 : 1,
duration: const Duration(milliseconds: 200), duration: const Duration(milliseconds: 200),
@@ -142,7 +156,7 @@ class ActionRowLineItem extends StatelessWidget {
text!, text!,
style: TextStyle( style: TextStyle(
fontSize: 13, fontSize: 13,
color: selectStatus! color: selectStatus
? Theme.of(context).colorScheme.onSecondaryContainer ? Theme.of(context).colorScheme.onSecondaryContainer
: Theme.of(context).colorScheme.outline), : Theme.of(context).colorScheme.outline),
), ),

View File

@@ -2,6 +2,7 @@ import 'dart:async';
import 'dart:io'; import 'dart:io';
import 'dart:math'; import 'dart:math';
import 'package:PiliPalaX/common/widgets/self_sized_horizontal_list.dart';
import 'package:PiliPalaX/pages/setting/widgets/switch_item.dart'; import 'package:PiliPalaX/pages/setting/widgets/switch_item.dart';
import 'package:PiliPalaX/utils/extension.dart'; import 'package:PiliPalaX/utils/extension.dart';
import 'package:PiliPalaX/utils/id_utils.dart'; import 'package:PiliPalaX/utils/id_utils.dart';
@@ -230,24 +231,71 @@ class _HeaderControlState extends State<HeaderControl> {
} }
}, },
), ),
ListTile( SelfSizedHorizontalList(
dense: true, itemCount: 4,
onTap: () { gapSize: 10,
Get.back(); padding: const EdgeInsets.symmetric(horizontal: 16),
Player? player = childBuilder: (index) {
widget.controller.videoPlayerController; return switch (index) {
if (player == null) { 0 => Obx(
SmartDialog.showToast('播放器未初始化'); () => ActionRowLineItem(
return; iconData: Icons.flip,
} onTap: () {
var pp = player.platform as NativePlayer; widget.controller.flipX.value =
pp.setProperty("video", "no"); !widget.controller.flipX.value;
},
text: " 左右翻转 ",
selectStatus: widget.controller.flipX.value,
),
),
1 => Obx(
() => ActionRowLineItem(
icon: Transform.rotate(
angle: pi / 2,
child: Icon(
Icons.flip,
size: 13,
color: widget.controller.flipY.value
? Theme.of(context)
.colorScheme
.onSecondaryContainer
: Theme.of(context)
.colorScheme
.outline,
),
),
onTap: () {
widget.controller.flipY.value =
!widget.controller.flipY.value;
},
text: " 上下翻转 ",
selectStatus: widget.controller.flipY.value,
),
),
2 => Obx(
() => ActionRowLineItem(
iconData: Icons.headphones,
onTap: widget.controller.setOnlyPlayAudio,
text: " 听视频 ",
selectStatus:
widget.controller.onlyPlayAudio.value,
),
),
3 => Obx(
() => ActionRowLineItem(
iconData: Icons.play_circle_outline,
onTap: widget
.controller.setContinuePlayInBackground,
text: " 后台播放 ",
selectStatus: widget.controller
.continuePlayInBackground.value,
),
),
int() => throw UnimplementedError(),
};
}, },
leading:
const Icon(Icons.headphones_outlined, size: 20),
title: const Text('听视频(需返回首页才能终止该状态)',
style: titleStyle),
), ),
ListTile( ListTile(
dense: true, dense: true,
onTap: () => {Get.back(), showSetVideoQa()}, onTap: () => {Get.back(), showSetVideoQa()},

View File

@@ -81,7 +81,13 @@ class PlPlayerController {
late StreamSubscription<DataStatus> _dataListenerForEnterFullscreen; late StreamSubscription<DataStatus> _dataListenerForEnterFullscreen;
/// 后台播放 /// 后台播放
final Rx<bool> _continuePlayInBackground = false.obs; late final Rx<bool> _continuePlayInBackground = false.obs;
late final Rx<bool> _onlyPlayAudio = false.obs;
late final Rx<bool> _flipX = false.obs;
late final Rx<bool> _flipY = false.obs;
/// ///
final Rx<bool> _isSliderMoving = false.obs; final Rx<bool> _isSliderMoving = false.obs;
@@ -212,6 +218,14 @@ class PlPlayerController {
/// 后台播放 /// 后台播放
Rx<bool> get continuePlayInBackground => _continuePlayInBackground; Rx<bool> get continuePlayInBackground => _continuePlayInBackground;
/// 听视频
Rx<bool> get onlyPlayAudio => _onlyPlayAudio;
/// 镜像
Rx<bool> get flipX => _flipX;
Rx<bool> get flipY => _flipY;
/// 是否长按倍速 /// 是否长按倍速
Rx<bool> get doubleSpeedStatus => _doubleSpeedStatus; Rx<bool> get doubleSpeedStatus => _doubleSpeedStatus;
@@ -1429,4 +1443,16 @@ class PlPlayerController {
_instance?._playerCount.value -= 1; _instance?._playerCount.value -= 1;
} }
} }
void setContinuePlayInBackground() {
_continuePlayInBackground.value = !_continuePlayInBackground.value;
setting.put(SettingBoxKey.continuePlayInBackground,
_continuePlayInBackground.value);
}
void setOnlyPlayAudio() {
_onlyPlayAudio.value = !_onlyPlayAudio.value;
videoPlayerController?.setVideoTrack(
_onlyPlayAudio.value ? VideoTrack.no() : VideoTrack.auto());
}
} }

View File

@@ -712,17 +712,21 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
_initialFocalPoint = Offset.zero; _initialFocalPoint = Offset.zero;
_gestureType = null; _gestureType = null;
}, },
child: Video( child: Transform.flip(
key: plPlayerController.key, flipX: plPlayerController.flipX.value,
controller: videoController, flipY: plPlayerController.flipY.value,
controls: NoVideoControls, child: Video(
pauseUponEnteringBackgroundMode: key: plPlayerController.key,
!plPlayerController.continuePlayInBackground.value, controller: videoController,
resumeUponEnteringForegroundMode: true, controls: NoVideoControls,
// 字幕尺寸调节 pauseUponEnteringBackgroundMode:
subtitleViewConfiguration: !plPlayerController.continuePlayInBackground.value,
plPlayerController.subtitleViewConfiguration, resumeUponEnteringForegroundMode: true,
fit: plPlayerController.videoFit.value, // 字幕尺寸调节
subtitleViewConfiguration:
plPlayerController.subtitleViewConfiguration,
fit: plPlayerController.videoFit.value,
),
), ),
), ),
), ),